SpecialFunction.ml

(* Copyright INRIA and Microsoft Corporation, 2008-2013. *)
(* DDMF is distributed under CeCILL-B license. *)

INCLUDE "preamble.ml"


let display_sf_main sf values parsed_values =
  let params = SF.params_of_t sf and rep_with_params = sf.SF.rep in
  let notation = CommonTools.subs_expr rep_with_params params values
  and var = SF.var_of_t sf
  and y = << y >> in  (* This is a convention, may change in the future. *)
  let yofz = << $(y)($(var)) >> in

  let sf = SF.instantiate_parameters sf values
  and parametrized = <:bool< nops(indets($(parsed_values))) > 0 >> in
  let marshaled_sf = DB.marshal_sf sf in

  let proc = << unapply($(sf.SF.rep), $(var)) >>
  and eqn = sf.SF.lode in

  let sings = << DDMF:-singular_points($(eqn), $(y), $(var)) >> in

  let definition, def = Definition.doc_and_def sf notation y << 0 >> values in

  let gen_conds =
    CommonTools.symb_list_of_symb
      << DDMF:-genericity_conditions($(eqn), $(y), $(var)) >> in
  let genericity =
    if gen_conds = [] then DC.ent_null else
      <:par<All formulas on this page are valid under the condition that >> @:@
      (Wording.enumeration_of_maples gen_conds) @:@
      (if List.length gen_conds = 1
       then <:par< is not an integer>>
       else <:par< are not integers>>) @:@
      <:par< (special values for parameters can be entered at the bottom).>> in

  let plot =
    if not parametrized
    then DC.inline_service (Plot.descr proc None)
    else DC.ent_null in

  let numerics =
    let analytic = (SF.get_initial_conditions sf << 0 >>).SF.analytic in
    if analytic && <:bool< not(member(0, $(sings))) >> && not parametrized then
      (* TODO: Passing lists as arguments to a service causes an error. *)
      (* As a hack, we convert the lists params and values to any maple. *)
      let p_hack = CommonTools.symb_of_name_list params
      and v_hack =
        CommonTools.symb_of_symb_list
          (List.map (fun a -> << $(str: a) >>) values) in
      DC.inline_service
        (NumericalEvaluation.descr
           (def, var, rep_with_params, p_hack, v_hack) None)
    else DC.ent_null in

  let derivatives =
    DC.inline_service (Derivatives.descr (eqn, notation, var) None) in

  let symmetries =
    let func_of_neg =
      CommonTools.subs_expr
        rep_with_params (var :: params) (<:latex< -$(var) >> :: values) in
    try (* TODO: instead of this try, one should fix the bugs! *)
      match Symmetries.obj ((def, yofz, notation, func_of_neg), ()) with
      | Symmetries.NoSym -> DC.ent_null
      | _ ->
          DC.inline_service
            (Symmetries.descr (def, yofz, notation, func_of_neg) None)
    with _ -> DC.ent_null in

  let expansion0 =
    DC.inline_service
      (LocalExpansion.descr
         (marshaled_sf, << 0 >>, y, notation, parametrized) None) in

  let sings =
    CommonTools.symb_list_of_symb
      << [op({op($(sings))} minus {0, infinity})] >> in
  let nb_sing =  List.length sings in
  let sOrNo = Wording.ending_of_int nb_sing
  and key = "singular point" in
  let sing_text =
    <:par<
      The differential equation above has $(int: nb_sing) non-zero
      finite $(t_ent: Glossary.g ~display: (Some (key ^ sOrNo)) key).
    >> in
  let secs_sing =
    List.map
      (fun p ->
        DC.inline_service
          (LocalExpansion.descr
             (marshaled_sf, p, y, notation, parametrized) None))
      sings in
  let sec_inf =
    DC.inline_service
      (LocalExpansion.descr
         (marshaled_sf, << infinity >>, y, notation, parametrized) None) in
  let other_expansions =
    DC.section
      <:text<Local Expansions at Singularities and at Infinity>>
      ((List.fold_left (@@@) sing_text secs_sing) @@@ sec_inf) in

  let hypergeometric =
    if HypergeomRepresentation.obj ((marshaled_sf, y, notation), ()) then
      DC.inline_service
        (HypergeomRepresentation.descr (marshaled_sf, y, notation) None)
    else DC.ent_null in

  let chebyshev =
    if snd (Chebyshev.has_a_recurrence def yofz) then
      DC.inline_service
        (Chebyshev.descr (def, yofz, sf.SF.rep, notation, proc) None)
    else DC.ent_null in

  let laplace =
    match LaplaceTransform.obj ((marshaled_sf, y, def), ()) with
    | true ->
        DC.inline_service
          (LaplaceTransform.descr (marshaled_sf, y, def) None)
    | false -> DC.ent_null in

  let enter_params =
    if params = [] then DC.ent_null else
    let nb_params = List.length params in
    let s = Wording.ending_of_int nb_params in
    let param_text =
      <:par<
        The $(str: sf.SF.full_name) <:isymb< $(rep_with_params) >> \
        depends on the parameter$(str: s) \
      >> @:@
      (Wording.enumeration_of_ents
         (List.map (fun a -> <:par<<:isymb< $(a) >>>>) params)) @:@
      <:par<. The box>>  @:@
      (if nb_params = 1 then <:par<>> else <:par<es>>) @:@
      <:par< below can be used to rename or instantiate >> @:@
      (if nb_params = 1 then <:par<this>> else <:par<these>>) @:@
      <:par< parameter$(str: s).>> in
    DC.section <:text<Parameters>> (param_text @@@ <:par<>>) in

  <:text<The Special Function <:imath< $(str: notation) >>>>,
  definition @@@ genericity @@@ plot @@@ numerics @@@ derivatives @@@
  symmetries @@@ expansion0 @@@ other_expansions @@@ hypergeometric @@@
  chebyshev @@@ laplace @@@ enter_params


(* This function checks whether the choice of parameters conflicts with *)
(* the function name, typically y(x), w.r.t. which the ODE is given. *)
let display_sf sf_id values =
  let sf = DB.sf_of_id sf_id in
  let var = SF.var_of_t sf in
  let parsed_values = CommonTools.parse_string_list values in
  if <:bool< has($(parsed_values), {$(var), y}) >>
  then
    <:text<The Special Function <:isymb< $(sf.SF.rep) >>>>,
    DC.warning
      <:par<
        Conflict between the function name <:isymb< y($(var)) >>
        and the choice of the parameters. Please do not use
        <:isymb< $(var) >> or <:isymb< y >>.
      >>
  else display_sf_main sf values parsed_values


(* Define several services, corresponding to the number of parameters. *)
let_service P0
  (sf_id : string) :
  DC.sec_entities * unit =
  let title, body = display_sf sf_id [] in
  DC.section title body, ()

let_service P1
  (sf_id : string)
  (p1 : string = "a") :
  DC.sec_entities * unit =
  let title, body = display_sf sf_id [p1] in
  DC.section title body, ()

let_service P2
  (sf_id : string)
  (p1 : string = "a")
  (p2 : string = "b") :
  DC.sec_entities * unit =
  let title, body = display_sf sf_id [p1; p2] in
  DC.section title body, ()

let_service P3
  (sf_id : string)
  (p1 : string = "a")
  (p2 : string = "b")
  (p3 : string = "c") :
  DC.sec_entities * unit =
  let title, body = display_sf sf_id [p1; p2; p3] in
  DC.section title body, ()

let_service Pn
  (sf_id : string) :
  DC.sec_entities * unit =
  let rep = (DB.sf_of_id sf_id).SF.rep in
  let warn = DC.warning <:par<This function has too many parameters.>> in
  DC.section <:text<The Special Function <:isymb< $(rep) >>>> warn, ()

Generated by GNU Enscript 1.6.5.90.