@@ -64,16 +64,16 @@ Symbolics.@register_symbolic Ei(z)
6464Symbolics. @register_symbolic Si (z)
6565Symbolics. @register_symbolic Ci (z)
6666Symbolics. @register_symbolic Li (z)
67- Symbolics. @register_symbolic erfi (z)
67+ Symbolics. @register_symbolic Erfi (z)
6868
6969
7070Symbolics. derivative (:: typeof (Ei), args:: NTuple{1, Any} , :: Val{1} ) = exp (args[1 ]) / args[1 ]
7171Symbolics. derivative (:: typeof (Si), args:: NTuple{1, Any} , :: Val{1} ) = sin (args[1 ]) / args[1 ]
7272Symbolics. derivative (:: typeof (Ci), args:: NTuple{1, Any} , :: Val{1} ) = cos (args[1 ]) / args[1 ]
7373Symbolics. derivative (:: typeof (Li), args:: NTuple{1, Any} , :: Val{1} ) = 1 / log (args[1 ])
74- Symbolics. derivative (:: typeof (erfi ), args:: NTuple{1, Any} , :: Val{1} ) = 2 / sqrt (2 ) * exp (args[1 ]^ 2 )
74+ Symbolics. derivative (:: typeof (Erfi ), args:: NTuple{1, Any} , :: Val{1} ) = 2 / sqrt (2 ) * exp (args[1 ]^ 2 )
7575
76- @syms 𝑥 si (𝑥) ci (𝑥) ei (𝑥) li (𝑥)
76+ @syms 𝑥 si (𝑥) ci (𝑥) ei (𝑥) li (𝑥) erfi_ (𝑥)
7777
7878# #############################################################################
7979
@@ -88,7 +88,7 @@ function generate_homotopy(eq, x)
8888 end
8989
9090 p = transform (eq, x)
91- q, sub, ks = rename_factors (p, (si => Si, ci => Ci, ei => Ei, li => Li))
91+ q, sub, ks = rename_factors (p, (si => Si, ci => Ci, ei => Ei, li => Li, erfi_ => Erfi ))
9292 S = 0
9393
9494 for i in 1 : length (ks)
@@ -114,7 +114,7 @@ partial_int_rules = [
114114 # trigonometric functions
115115 @rule 𝛷 (sin (~ x)) => (cos (~ x) + si (~ x), ~ x)
116116 @rule 𝛷 (cos (~ x)) => (sin (~ x) + ci (~ x), ~ x)
117- @rule 𝛷 (tan (~ x)) => (log (cos (~ x)) + ~ x * tan ( ~ x) , ~ x)
117+ @rule 𝛷 (tan (~ x)) => (log (cos (~ x)), ~ x)
118118 @rule 𝛷 (csc (~ x)) => (log (csc (~ x) + cot (~ x)) + log (sin (~ x)), ~ x)
119119 @rule 𝛷 (sec (~ x)) => (log (sec (~ x) + tan (~ x)) + log (cos (~ x)), ~ x)
120120 @rule 𝛷 (cot (~ x)) => (log (sin (~ x)), ~ x)
@@ -154,37 +154,105 @@ partial_int_rules = [
154154 @rule 𝛷 (asech (~ x)) => (asech (~ x), ~ x)
155155 @rule 𝛷 (acoth (~ x)) => (~ x * acot (~ x) + log (~ x + 1 ), ~ x)
156156 # logarithmic and exponential functions
157- @rule 𝛷 (log (~ x)) => (~ x + ~ x * log (~ x) +
158- sum (candidate_pow_minus (~ x, - 1 ); init = one (~ x)),
159- ~ x)
157+ @rule 𝛷 (log (~ x)) => (~ x + ~ x * log (~ x) + sum (pow_minus_rule (~ x, - 1 ); init = one (~ x)), ~ x)
160158 @rule 𝛷 (1 / log (~ x)) => (log (log (~ x)) + li (~ x), ~ x)
161- @rule 𝛷 (exp (~ x)) => (exp (~ x) + ei (~ x), ~ x)
159+ @rule 𝛷 (exp (~ x)) => (exp (~ x) + ei (~ x) + erfi_rule ( ~ x) , ~ x)
162160 @rule 𝛷 (^ (exp (~ x), ~ k:: is_neg )) => (^ (exp (- ~ x), - ~ k), ~ x)
163161 # square-root functions
164- @rule 𝛷 (^ (~ x, ~ k:: is_abs_half )) => (sum (candidate_sqrt (~ x, ~ k);
165- init = one (~ x)), ~ x);
166- @rule 𝛷 (sqrt (~ x)) => (sum (candidate_sqrt (~ x, 0.5 ); init = one (~ x)), ~ x);
167- @rule 𝛷 (1 / sqrt (~ x)) => (sum (candidate_sqrt (~ x, - 0.5 );
168- init = one (~ x)), ~ x);
162+ @rule 𝛷 (^ (~ x, ~ k:: is_abs_half )) => (sum (sqrt_rule (~ x, ~ k); init = one (~ x)), ~ x);
163+ @rule 𝛷 (sqrt (~ x)) => (sum (sqrt_rule (~ x, 0.5 ); init = one (~ x)), ~ x);
164+ @rule 𝛷 (1 / sqrt (~ x)) => (sum (sqrt_rule (~ x, - 0.5 ); init = one (~ x)), ~ x);
169165 # rational functions
170- @rule 𝛷 (1 / ^ (~ x:: is_poly , ~ k:: is_pos_int )) => (sum (candidate_pow_minus (~ x,
171- - ~ k);
172- init = one (~ x)),
173- ~ x)
174- @rule 𝛷 (1 / ~ x:: is_poly ) => (sum (candidate_pow_minus (~ x, - 1 );
175- init = one (~ x)), ~ x);
166+ @rule 𝛷 (1 / ^ (~ x:: is_univar_poly , ~ k:: is_pos_int )) => (sum (pow_minus_rule (~ x,- ~ k); init = one (~ x)), ~ x)
167+ @rule 𝛷 (1 / ~ x:: is_univar_poly ) => (sum (pow_minus_rule (~ x, - 1 ); init = one (~ x)), ~ x);
176168 @rule 𝛷 (^ (~ x, - 1 )) => (log (~ x), ~ x)
177- @rule 𝛷 (^ (~ x, ~ k:: is_neg_int )) => (sum (^ (~ x, i) for i in (~ k + 1 ): - 1 ),
178- ~ x)
169+ @rule 𝛷 (^ (~ x, ~ k:: is_neg_int )) => (sum (^ (~ x, i) for i in (~ k + 1 ): - 1 ), ~ x)
179170 @rule 𝛷 (1 / ~ x) => (log (~ x), ~ x)
180- @rule 𝛷 (^ (~ x, ~ k:: is_pos_int )) => (sum (^ (~ x, i + 1 )
181- for i in 1 : (~ k + 1 )),
182- ~ x)
171+ @rule 𝛷 (^ (~ x, ~ k:: is_pos_int )) => (sum (^ (~ x, i + 1 ) for i in 1 : (~ k + 1 )), ~ x)
183172 @rule 𝛷 (1 ) => (𝑥, 1 )
184173 @rule 𝛷 (~ x) => ((~ x + ^ (~ x, 2 )), ~ x)]
185174
186175function apply_partial_int_rules (eq, x)
187- y, dy = expand (Fixpoint (Prewalk (Chain (partial_int_rules))))(𝛷 (value (eq)))
188- D = Differential (x)
189- return y, guard_zero (expand_derivatives (D (dy)))
176+ y, dy = Chain (partial_int_rules)(𝛷 (value (eq)))
177+ return y, guard_zero (diff (dy, x))
190178end
179+
180+ # ###############################################################
181+
182+ function erfi_rule (eq)
183+ if is_univar_poly (eq)
184+ x = var (eq)
185+ return erfi_ (x)
186+ end
187+ return 0
188+ end
189+
190+ function pow_minus_rule (p, k; abstol = 1e-8 )
191+ if ! is_univar_poly (p)
192+ return [p^ k, p^ (k + 1 ), log (p)]
193+ end
194+
195+ x = var (p)
196+ d = poly_deg (p)
197+
198+ for j in 1 : 10 # will try 10 times to find the roots
199+ r, s = find_roots (p, x)
200+ if length (r) + length (s) >= d
201+ break
202+ end
203+ end
204+ s = s[1 : 2 : end ]
205+ r = nice_parameter .(r)
206+ s = nice_parameter .(s)
207+
208+ # ∫ 1 / ((x-z₁)(x-z₂)) dx = ... + c₁ * log(x-z₁) + c₂ * log(x-z₂)
209+ q = Any[log (x - u) for u in r]
210+ for i in eachindex (s)
211+ β = s[i]
212+ if abs (imag (β)) > abstol
213+ push! (q, atan ((x - real (β)) / imag (β)))
214+ push! (q, (1 + x) * log (x^ 2 - 2 * real (β) * x + abs2 (β)))
215+ else
216+ push! (q, log (x - real (β)))
217+ end
218+ end
219+ q = unique (q)
220+
221+ if k ≈ - 1
222+ return [[p^ k]; q]
223+ else
224+ return [[p^ k, p^ (k + 1 )]; q]
225+ end
226+ end
227+
228+ function sqrt_rule (p, k)
229+ h = Any[p^ k, p^ (k + 1 )]
230+
231+ if ! is_univar_poly (p)
232+ return h
233+ end
234+
235+ x = var (p)
236+
237+ if poly_deg (p) == 2
238+ r, s = find_roots (p, x)
239+ l = leading (p, x)
240+ if length (r) == 2
241+ if sum (r) ≈ 0
242+ r₁ = abs (r[1 ])
243+ if l > 0
244+ push! (h, acosh (x / r₁))
245+ else
246+ push! (h, asin (x / r₁))
247+ end
248+ end
249+ elseif real (s[1 ]) ≈ 0
250+ push! (h, asinh (x / imag .(s[1 ])))
251+ end
252+ end
253+
254+ Δ = expand_derivatives (Differential (x)(p))
255+ push! (h, log (0.5 * Δ + sqrt (p)))
256+ return h
257+ end
258+
0 commit comments