(* Copyright INRIA and Microsoft Corporation, 2008-2013. *)(* DDMF is distributed under CeCILL-B license. *)INCLUDE"preamble.ml"lettitle _ = <:text<ClosedForm>>(* A wrapper function to call DDMF:-Hypergeometric:-generalTerms *)(* that does some pre- and post-processing. *)letcall_generalTerms recsys inits u n x lps =(* Write recsys in terms of positive shifts (required by generalTerms). *)letshift = << min(map(a -> op(1, a) - $(n), indets($(recsys),function))) >>inletrecsys = << subs($(n) = $(n) - $(shift), $(recsys)) >>in(* Compute closed forms of the unknown sequences u[i](n). *)letp = << indets([$(recsys), $(inits)], name) minus {$(n)} >>inletgeneral_terms = <<DDMF:-Hypergeometric:-generalTerms($(recsys), $(inits), $(n), $(x), $(p)) >>in<< [seq($(general_terms)[$(u)[i]], iin$(lps))] >>(* Compute a closed form expression of a transseries record. The closed form *)(* is returned as a Maple expression. The record itself is updated, when the *)(* closed form is computed for the first time. *)letclosed_form_of_transseries ser =(* Shorter name for the constituents of the transseries record. *)letx = << $(ser):-variable >>andram = << $(ser):-ramification >>andu = << $(ser):-sequence_name >>andn = << $(ser):-index_name >>in(* A local variable to ensure that the final expression is displayed in *)(* terms of ser:-variable, i.e., the "transf" given in the sf database, *)(* and to make intermediate operations simpler. *)letx_loc = << proc() local x_loc; x_locendproc() >>in(* Whether the power factor x^alpha is displayed inside the sum or not. *)letpow_factor, x_expon =if<:bool<type($(ram) * $(ser):-alpha, integer) >>then<< 1 >>, << $(ser):-alpha >>else<< combine($(x) ^ $(ser):-alpha,'power','symbolic') >>, << 0 >>in(* Maple expression of an element in the list :-general. *)letexpr_of_general_term gen =letx_part = << $(x_loc) ^ ($(gen):-period / $(ram) + $(x_expon)) >>andcf = << $(gen):-cform >>inletfacs = << `if`(op(0, $(cf)) = `*`, [op($(cf))], [$(cf)]) >>inletfacs = << [selectremove(has, $(facs), $(n))] >>inletout_fac = << `*`(op($(facs)[2])) >>andin_fac = << map(a -> sort(a, indets(a, name), descending), $(facs)[1]) >>inletin_fac = << __DynaMoW_times([op(sort($(in_fac))), $(x_part)]) >>inletin_fac = <<DDMF:-dynamow_times_to_frac($(in_fac), []) >>in<< $(out_fac) *Sum($(in_fac), $(n) = 0 .. infinity) >>in(* Update the transseries record, concerning the closed form sol which *)(* is related to index i (which corresponds to u[i](n) * log(x)^i). *)letupdate_index i sol =letln = << ln($(x_loc))^$(i) >>inif<:bool< $(sol):-isHyper >>then(* If a closed form is found, it is stored in the transseries record. *)letgen =CommonTools.symb_list_of_symb << $(sol):-general >>inletexprs =List.map expr_of_general_term geninletexpr = << `+`(op($(CommonTools.symb_of_symb_list exprs))) >>in(* If the solution is finite (no infinite sum involved), it goes to *)(* ser:-finite_part, otherwise to ser:-closed_form. *)(* In that case, we also update the recurrences and initial values. *)if<:bool< $(expr) = 0 >>thenletrec_inits = << proc(xx, u, i) local poly, deg, ord, recsys, inits, new_inits, eqns, sol; poly := subs(xx = xx^$(ram), $(sol):-poly); poly := combine(poly,'power','symbolic'); deg := degree(poly, xx); recsys := $(ser):-recurrences; inits := $(ser):-initial_conditions; ord := -min(map(a -> op(a) - $(n), indets(recsys, specfunc(anything, u)))); eqns := [seq(op(subs($(n) = ord + j, recsys)), j = 0 .. deg)]; eqns := subs( [seq(u[i](j) = coeff(poly, xx, j), j = 0 .. ord + deg)], eqns); new_inits := remove(a -> evalb(eval(op(2, a), u = 0) = 0), eqns); eqns := subs(inits, eqns); sol := solve(eqns, indets(eqns, specfunc(integer, u)));if[sol] = []thenerror("Error 666: no solution found.")endif; new_inits := select(has, [op(inits), op(sol)], indets(map2(op, 1, new_inits), specfunc(integer, u))); recsys := select(has, eval(recsys, u[i] = 0), u); inits := sort(remove(has, [op(inits), op(new_inits)], u[i])); return [recsys, inits];endproc($(x_loc), $(u), $(i)) >>in<:unit< $(ser):-finite_part := $(ser):-finite_part + $(ln) * $(sol):-poly; $(ser):-log_powers := remove(`=`, $(ser):-log_powers, $(i)); $(ser):-recurrences := $(rec_inits)[1]; $(ser):-initial_conditions := $(rec_inits)[2]; >>else<:unit< $(ser):-closed_form := $(ser):-closed_form + $(ln) * ($(sol):-poly + $(expr)); >>else(* If no closed form could be found, a symbolic expression in terms *)(* of the unknown coefficient sequences u[i](n) is stored in *)(* ser:-closed_form. *)letx_part = << $(x_loc) ^ ($(n) / $(ram) + $(x_expon)) >>inletsmnd = << __DynaMoW_times([$(u)[$(i)]($(n)), $(x_part)]) >>in<:unit< $(ser):-closed_form := $(ser):-closed_form + $(ln) *Sum($(smnd), $(n) = 0 .. infinity); >>in(* If this condition is true, it means that the closed form was never *)(* computed before and that we actually have to do something. *)if<:bool< $(ser):-closed_form = undefined >>thenbegin<:unit< $(ser):-closed_form := 0 >>;letlps = << $(ser):-log_powers >>inletclosed_forms = call_generalTerms << $(ser):-recurrences >> << $(ser):-initial_conditions >> u n << $(x_loc)^(1 / $(ram)) >> lpsin(* Update the transseries record for all indices i. *)List.iter (funi -> update_index << $(lps)[$(int: i)] >> << $(closed_forms)[$(int: i)] >>) (CommonTools.range <:int< nops($(lps)) >>);end;(* Now in any case the closed form is available in the record. *)<:unit< $(ser):-finite_part :=DDMF:-replace_and_combine($(ser):-finite_part, $(x_loc), $(x)); $(ser):-closed_form :=DDMF:-replace_and_combine($(ser):-closed_form, $(x_loc), $(x)); >>;letcf = << $(ser):-finite_part + $(ser):-closed_form >>inletrecsys, inits =if<:bool< has($(ser):-closed_form, $(u)) >>then<< $(ser):-recurrences >>, << $(ser):-initial_conditions >>else<< [] >>, << [] >>inletexp_factor = << combine($(ser):-exp_factor,'power','symbolic') >>in<< [$(exp_factor) * $(pow_factor) * $(cf), $(recsys), $(inits)] >>letclosed_form_of_linear_comb linear_comb =letsers =CommonTools.symb_list_of_symb << map(a -> a[2], $(linear_comb)) >>andcoeffs = << map(a -> a[1], $(linear_comb)) >>inletclosed_forms =CommonTools.symb_of_symb_list (List.map closed_form_of_transseries sers)inletrecsys = << map(a -> op(a[2]), $(closed_forms)) >>andinits = << map(a -> op(a[3]), $(closed_forms)) >>andclosed_forms = << map(a -> a[1], $(closed_forms)) >>in(* Assemble the linear combination of closed forms. *)letcf = << `+`(op(zip((a, b) -> `if`(op(0, b) = `+`, map(c -> a * c, b), a * b), $(coeffs), $(closed_forms)))) >>inletcf = << `if`(op(0, $(cf)) = `+`, [op($(cf))], [$(cf)]) >>in(* Sort the terms according to asymptotic behaviour. *)(* This is not perfectly done since for the sums it's difficult to see. *)letvar =ifsers = []then<< x >>else<< $(List.hd sers):-variable >>inletcf = << selectremove(has, sort($(cf), length),Sum) >>inletcf = << [op(sort($(cf)[2], proc(a, b) local da, db; da :=DDMF:-my_degree(a, ln($(var))); db :=DDMF:-my_degree(b, ln($(var))); `if`(da = db, [a, b] = sort([a, b]), da > db)endproc)), op($(cf)[1])] >>in(* Simplify coefficients, in particular in front of sums. *)letcf = << map(a -> `if`(op(0, a) = `*`, ((b, c) -> combine(`*`(op(c))) * (`*`(op(b))))(selectremove(has, [op(a)],Sum)), a), $(cf)) >>in(* Rewrite the parts of cf in terms of __DynaMoW_plus, _times and _frac. *)letcf = << map(a -> `if`(op(0, a) = `*`,DDMF:-dynamow_times_to_frac(__DynaMoW_times( map(b -> op(sort(b, (a1, a2) -> `if`(has(a1,Sum) = has(a2,Sum), [a1, a2] = sort([a1, a2]), has(a2,Sum)))), [selectremove(b -> not(has(b, indets($(var)))), [op(a)])])), [Sum, $(var), 1/$(var)]), a), $(cf)) >>inletcf = << `if`(nops($(cf)) > 1, __DynaMoW_plus($(cf)), `+`(op($(cf)))) >>in(* If there are unknown sequences (no closed form found), rename them, *)(* as to have consecutive indexing. *)letseq_names = << map(a -> a[2]:-sequence_name, $(linear_comb)) >>inletseq_names = << map(a -> `if`(op(0, a) ='symbol', a, op(0, a)), $(seq_names)) >>inif<:bool< nops({op($(seq_names))}) = 1 >>thenletrename = <<DDMF:-rename_sequences( [$(cf), $(recsys), $(inits)], $(seq_names)[1])[1] >>in<< $(rename)[1] >>, << $(rename)[2] >>, << $(rename)[3] >>elsecf, recsys, inits let_serviceClosedForm(linear_comb : any maple) (notation : string) :DC.sec_entities * (any maple * any maple)with{ title = title } =letlinear_comb = <<DDMF:-decode_linear_combination($(linear_comb)) >>inletcf, recsys, inits = closed_form_of_linear_comb linear_combinletcf = <<DDMF:-maple_to_dynamow($(cf)) >>in<:par<Taylorcoefficients: <:dmath< $(str: notation) = $(symb: cf). >>>>, (cf, <<DDMF:-encode_linear_combination($(linear_comb)) >>)

Generated by GNU Enscript 1.6.5.90.