OrdinaryDiffEqn.ml

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

INCLUDE "preamble.ml"


(* Create a page that displays information about a differential equation. *)
let ode_main_page ode parvals =

  let var = FEqn.var_of_t ode
  and params = FEqn.params_of_t ode in
  let eqn = CommonTools.eval_expr ode.FEqn.eqn params parvals in

  (* Determine names for coefficient sequences and summation variable. *)
  let in_use =
    CommonTools.symb_of_symb_list
      ((List.map (fun a -> << parse($(str: a)) >>) parvals) @
       [ << $(var) >> ]) in
  let seq_var, sum_var = CommonTools.unused_names_for_sequence in_use in

  (* (1) Particular Solutions *)
  (* Display the ODE and its solutions, provided they are in the sf database. *)
  let display_sf sf_id =
    try
      (* For displaying the mathematical representation of the function, *)
      (* we test whether the particular choice of the parameters allows  *)
      (* a simplification; in this case we write, e.g., J_{1/2}(x) = ... *)
      let sf = DB.sf_of_id sf_id in
      let func_rep1 = CommonTools.subs_expr sf.SF.rep params parvals
      and func_rep2 =
        <:latex< $(CommonTools.eval_expr sf.SF.rep params parvals) >> in
      let func_rep =
        if String.compare func_rep1 func_rep2 = 0
        then <:par<<:imath< $(str: func_rep1) >>>>
        else <:par<<:imath< $(str: func_rep1) = $(str: func_rep2) >>>>
      in
      [ <:par<the function >> @:@ func_rep ]
    with
      _ -> [] in
  (* TODO: The word "function" should appear as a link to the corresponding *)
  (* special function page. But since SpecialFunction.ml is compiled after  *)
  (* OrdinaryDiffEqn.ml, this causes a linking problem during compilation.  *)
  let sols = List.flatten (List.map display_sf ode.FEqn.sol_ids) in
  let text_sols = Wording.enumeration_of_ents sols in
  let text1, text2 = match List.length sols with
  | 0 -> <:par<No particular solutions>>, <:par<are known to the database>>
  | 1 -> <:par<A particular solution>>, <:par<is >>
  | _ -> <:par<Some particular solutions>>, <:par<are >> in
  let text_ode =
    <:par< of the differential equation <:dmath< $(symb: eqn) = 0 >>>> in
  let particular_solutions =
    DC.section
      <:text<Particular Solutions>>
      (text1 @:@ text_ode @:@ text2 @:@ text_sols @:@ <:par<.>>) in

  (* (1a) Genericity conditions *)
  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

  (* (2) Singular Points *)
  (* Show the singular points of the differential equation. *)
  let sings =
    CommonTools.symb_list_of_symb
      << DDMF:-singular_points($(eqn), y, $(var)) >> in
  let inhom = <:bool< eval($(eqn), y($(var)) = 0) <> 0 >>
  and nsing = List.length sings in
  let text_sps = <:par<The differential equation has >> @:@
    (match nsing with
    | 0 -> <:par<no singular points.>>
    | 1 -> <:par<one singular point:>>
    | _ -> <:par<$(int: nsing) singular points:>>) in
  let text_type sp =
    <:par<<:isymb< $(sp) >> is >> @:@
    (if <:bool< DDMF:-regular_singularity($(eqn), y, $(var), $(sp)) >>
    then <:par<a regular >>
    else <:par<an irregular >>) @:@
    <:par<singular point.>> in
  let singular_points =
    DC.section
      <:text<Singular Points>>
      text_sps @@@ (DC.ordered_list (List.map text_type sings)) in

  (* (3) Asymptotic Expansions at 0 and infinity *)
  (* We always display the local expansions at 0 and infinity. *)
  let warn =
    if inhom then
      DC.warning
        <:par<
          The given differential equation is not homogeneous. The expansions
          below are solutions to the corresponding homogeneous equation.
        >>
    else
      DC.ent_null
  and sec_0 =
    DC.inline_service
      (BasisOfSolutions.descr (eqn, var, <<0>>, seq_var, sum_var) None)
  and sec_inf =
    DC.inline_service
      (BasisOfSolutions.descr (eqn, var, <<infinity>>, seq_var, sum_var) None)
  in
  let exp_0inf =
    DC.section
      <:text<Asymptotic Expansions at <:isymb<0>> and <:isymb<infinity>>>>
      (warn @@@ sec_0 @@@ sec_inf) in

  (* (4) Asymptotic Expansions at other singular points *)
  (* Display the local expansions at singularities other than 0 and infinity. *)
  let sings =
    List.filter (fun a -> <:bool< $(a) <> 0 and $(a) <> infinity >>) sings in
  let one_sec s =
    DC.inline_service
      (BasisOfSolutions.descr (eqn, var, s, seq_var, sum_var) None) in
  let secs = List.map one_sec sings in
  let exp_sing =
    if sings = [] then
      DC.ent_null
    else
      DC.section
        <:text<Asymptotic Expansions at other singular points>>
        (List.fold_left (@@@) DC.ent_null secs) in

  (* (5) Parameters *)
  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: ode.FEqn.eqn_name) 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

  (* Final result of ode_main_page. *)
  particular_solutions @@@ genericity @@@ singular_points @@@
  exp_0inf @@@ exp_sing @@@ 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_ode ode_id parvals =
  let ode = DB.eqn_of_id ode_id in
  let var = FEqn.var_of_t ode in
  let parval_list =
    CommonTools.symb_of_symb_list
      (List.map (fun a -> << parse($(str: a)) >>) parvals) in
  if <:bool< has($(parval_list), {$(var), y}) >>
  then
    DC.warning
      <:par<
        Conflict between function <:isymb< y($(var)) >> and the parameters.
      >>
  else ode_main_page ode parvals


(* Define several services, corresponding to the number of parameters. *)
let title ode_id =
  <:text<The $(str: (DB.eqn_of_id ode_id).FEqn.eqn_name)>>

let_service Param0
  (ode_id : string):
  DC.sec_entities * unit with { title = title } =
  DC.section (title _req_params) (display_ode ode_id [ ]), ()

let_service Param1
  (ode_id : string)
  (p1 : string = "a") :
  DC.sec_entities * unit with { title = title } =
  DC.section (title _req_params) (display_ode ode_id [ p1 ]), ()

let_service Param2
  (ode_id : string)
  (p1 : string = "a")
  (p2 : string = "b") :
  DC.sec_entities * unit with { title = title } =
  DC.section (title _req_params) (display_ode ode_id [ p1 ; p2 ]), ()

let_service Param3
  (ode_id : string)
  (p1 : string = "a")
  (p2 : string = "b")
  (p3 : string = "c") :
  DC.sec_entities * unit with { title = title } =
  DC.section (title _req_params) (display_ode ode_id [ p1 ; p2 ; p3 ]), ()

let_service Paramn
  (ode_id : string) :
  DC.sec_entities * unit with { title = title } =
  let eqn_text = <:par<<:dmath< $(symb: (DB.eqn_of_id ode_id).FEqn.eqn) = 0 >>>>
  and warn_text = <:par<This differential equation has too many parameters.>> in
  DC.section (title _req_params) (DC.warning (eqn_text @:@ warn_text)), ()

Generated by GNU Enscript 1.6.5.90.