Skip to content

Commit 12ba109

Browse files
upgraded to use Symbolics 5
1 parent b79569e commit 12ba109

File tree

10 files changed

+182
-177
lines changed

10 files changed

+182
-177
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "SymbolicNumericIntegration"
22
uuid = "78aadeae-fbc0-11eb-17b6-c7ec0477ba9e"
33
authors = ["Shahriar Iravanian <[email protected]>"]
4-
version = "1.1.0"
4+
version = "1.2.0"
55

66
[deps]
77
DataDrivenDiffEq = "2445eb08-9709-466a-b3fc-47e12bd697a2"

docs/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ SymbolicNumericIntegration = "78aadeae-fbc0-11eb-17b6-c7ec0477ba9e"
44

55
[compat]
66
Documenter = "0.27"
7-
SymbolicNumericIntegration = "0.9, 1"
7+
SymbolicNumericIntegration = "1"

docs/make.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Documenter, SymbolicNumericIntegration
22

3-
cp("./docs/Manifest.toml", "./docs/src/assets/Manifest.toml", force = true)
4-
cp("./docs/Project.toml", "./docs/src/assets/Project.toml", force = true)
3+
# cp("./docs/Manifest.toml", "./docs/src/assets/Manifest.toml", force = true)
4+
# cp("./docs/Project.toml", "./docs/src/assets/Project.toml", force = true)
55

66
include("pages.jl")
77

@@ -11,7 +11,7 @@ makedocs(sitename = "SymbolicNumericIntegration.jl",
1111
clean = true, doctest = false, linkcheck = true,
1212
strict = [
1313
:doctest,
14-
:linkcheck,
14+
# :linkcheck,
1515
:parse_error,
1616
:example_block,
1717
# Other available options are

src/candidates.jl

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ using DataStructures
44
function generate_basis(eq, x, try_kernel = true)
55
if !try_kernel
66
S = sum(generate_homotopy(expr(eq), x))
7-
return cache.(unique([one(x); [equivalent(t, x) for t in terms(S)]]))
7+
return cache.(unique([equivalent(t, x) for t in terms(S)]))
88
end
99

1010
S = 0
@@ -16,32 +16,36 @@ function generate_basis(eq, x, try_kernel = true)
1616
p = q / f
1717

1818
if isdependent(p, x)
19-
C₂ = generate_homotopy(p, x)
19+
C₂ = generate_homotopy(p, x)
2020
else
21-
C₂ = 1
21+
C₂ = 1
2222
end
23-
23+
2424
C₁ = closure(f, x)
25-
25+
2626
S += sum(c₁ * c₂ for c₁ in C₁ for c₂ in C₂)
2727
end
28-
return cache.(unique([one(x); [equivalent(t, x) for t in terms(S)]]))
28+
return cache.(unique([equivalent(t, x) for t in terms(S)]))
2929
end
3030

31-
function expand_basis(basis, x; Kmax=1000)
32-
b = sum(expr.(basis))
31+
function expand_basis(basis, x; Kmax = 1000)
32+
if isempty(basis)
33+
return basis, false
34+
end
35+
36+
b = sum(expr.(basis))
37+
38+
Kb = complexity(b)# Kolmogorov complexity
39+
if is_proper(Kb) && Kb > Kmax
40+
return basis, false
41+
end
3342

34-
Kb = complexity(b) # Kolmogorov complexity
35-
if is_proper(Kb) && Kb > Kmax
36-
return basis, false
37-
end
38-
39-
δb = sum(deriv!.(basis, x))
43+
δb = sum(deriv!.(basis, x))
4044
eq = (1 + x) * (b + δb)
4145
eq = expand(eq)
4246
S = Set{Any}()
4347
enqueue_expr!(S, eq, x)
44-
return cache.([one(x); [s for s in S]]), true
48+
return cache.([s for s in S]), true
4549
end
4650

4751
function closure(eq, x; max_terms = 50)
@@ -57,7 +61,7 @@ function closure(eq, x; max_terms = 50)
5761
y = dequeue!(q)
5862
enqueue_expr!(S, q, expand_derivatives(D(y)), x)
5963
end
60-
unique([one(x); [s for s in S]; [s * x for s in S]])
64+
unique([[s for s in S]; [s * x for s in S]])
6165
end
6266

6367
function candidate_pow_minus(p, k; abstol = 1e-8)

src/homotopy.jl

Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,56 +5,57 @@ function transformer(::Mul, eq)
55
end
66

77
function transformer(::Div, eq)
8-
a = transformer(arguments(eq)[1])
9-
b = transformer(arguments(eq)[2])
10-
b = [(1/q, k) for (q, k) in b]
8+
a = transformer(arguments(eq)[1])
9+
b = transformer(arguments(eq)[2])
10+
b = [(1 / q, k) for (q, k) in b]
1111
return [a; b]
1212
end
1313

1414
function transformer(::Pow, eq)
1515
y, k = arguments(eq)
1616
if is_number(k)
17-
r = nice_parameter(k)
18-
if denominator(r) == 1
19-
return [(y, k)]
20-
else
21-
return [(y^(1/denominator(r)), numerator(r))]
22-
end
23-
else
24-
return [(eq, 1)]
25-
end
17+
r = nice_parameter(k)
18+
if r isa Integer || r isa Rational
19+
if denominator(r) == 1
20+
return [(y, k)]
21+
else
22+
return [(y^(1 / denominator(r)), numerator(r))]
23+
end
24+
end
25+
end
26+
return [(eq, 1)]
2627
end
2728

2829
function transformer(::Any, eq)
29-
return [(eq, 1)]
30+
return [(eq, 1)]
3031
end
3132

3233
function transform(eq, x)
3334
p = transformer(eq)
34-
p = p[isdependent.(first.(p), x)]
35+
p = p[isdependent.(first.(p), x)]
3536
return p
3637
end
3738

3839
@syms u[20]
3940

40-
function rename_factors(p, ab)
41-
n = length(p)
42-
q = 1
43-
ks = Int[]
44-
sub = Dict()
45-
46-
for (a,b) in ab
47-
sub[a] = b
48-
end
49-
50-
for (i,(y,k)) in enumerate(p)
51-
μ = u[i]
52-
q *= μ ^ k
53-
sub[μ] = y
54-
push!(ks, k)
55-
end
56-
57-
return q, sub, ks
41+
function rename_factors(p, ab = ())
42+
n = length(p)
43+
q = 1
44+
ks = Int[]
45+
sub = Dict()
46+
47+
for (a, b) in ab
48+
sub[a] = b
49+
end
50+
51+
for (i, (y, k)) in enumerate(p)
52+
μ = u[i]
53+
q *= μ^k
54+
sub[μ] = y
55+
push!(ks, k)
56+
end
57+
58+
return q, sub, ks
5859
end
5960

6061
##############################################################################
@@ -79,29 +80,26 @@ function generate_homotopy(eq, x)
7980
eq = eq isa Num ? eq.val : eq
8081
x = x isa Num ? x.val : x
8182

82-
p = transform(eq, x)
83+
p = transform(eq, x)
8384
q, sub, ks = rename_factors(p, (si => Si, ci => Ci, ei => Ei, li => Li))
8485
S = 0
8586

8687
for i in 1:length(ks)
87-
μ = u[i]
88-
h₁, ∂h₁ = apply_partial_int_rules(sub[μ], x)
89-
h₁ = substitute(h₁, sub)
90-
91-
for j = 1:ks[i]
92-
h₂ = substitute((q / μ^j) / ∂h₁, sub)
93-
S += expand((ω + h₁) *+ h₂))
94-
end
95-
end
96-
88+
μ = u[i]
89+
h₁, ∂h₁ = apply_partial_int_rules(sub[μ], x)
90+
h₁ = substitute(h₁, sub)
91+
92+
for j in 1:ks[i]
93+
h₂ = substitute((q / μ^j) / ∂h₁, sub)
94+
S += expand((ω + h₁) *+ h₂))
95+
end
96+
end
97+
9798
S = substitute(S, Dict=> 1))
98-
99-
ζ = [x^k for k=1:maximum(ks)+1]
100-
101-
unique([one(x); ζ; [equivalent(t, x) for t in terms(S)]])
99+
unique([x; [equivalent(t, x) for t in terms(S)]])
102100
end
103101

104-
##############################################################################
102+
########################## Main Integration Rules ##################################
105103

106104
@syms 𝛷(x)
107105

@@ -159,17 +157,22 @@ partial_int_rules = [
159157
@rule 𝛷(^(~x, ~k::is_abs_half)) => (sum(candidate_sqrt(~x, ~k);
160158
init = one(~x)), ~x);
161159
@rule 𝛷(sqrt(~x)) => (sum(candidate_sqrt(~x, 0.5); init = one(~x)), ~x);
162-
@rule 𝛷(1 / sqrt(~x)) => (sum(candidate_sqrt(~x, -0.5); init = one(~x)), ~x);
160+
@rule 𝛷(1 / sqrt(~x)) => (sum(candidate_sqrt(~x, -0.5);
161+
init = one(~x)), ~x);
163162
# rational functions
164-
@rule 𝛷(1 / ^(~x::is_poly, ~k::is_pos_int)) => (sum(candidate_pow_minus(~x, -~k);
165-
init = one(~x)), ~x)
163+
@rule 𝛷(1 / ^(~x::is_poly, ~k::is_pos_int)) => (sum(candidate_pow_minus(~x,
164+
-~k);
165+
init = one(~x)),
166+
~x)
166167
@rule 𝛷(1 / ~x::is_poly) => (sum(candidate_pow_minus(~x, -1);
167-
init = one(~x)), ~x)
168+
init = one(~x)), ~x);
168169
@rule 𝛷(^(~x, -1)) => (log(~x), ~x)
169170
@rule 𝛷(^(~x, ~k::is_neg_int)) => (sum(^(~x, i) for i in (~k + 1):-1),
170171
~x)
171172
@rule 𝛷(1 / ~x) => (log(~x), ~x)
172-
@rule 𝛷(^(~x, ~k::is_pos_int)) => (sum(^(~x, i+1) for i=1:~k+1), ~x)
173+
@rule 𝛷(^(~x, ~k::is_pos_int)) => (sum(^(~x, i + 1)
174+
for i in 1:(~k + 1)),
175+
~x)
173176
@rule 𝛷(1) => (𝑥, 1)
174177
@rule 𝛷(~x) => ((~x + ^(~x, 2)), ~x)]
175178

@@ -178,5 +181,3 @@ function apply_partial_int_rules(eq, x)
178181
D = Differential(x)
179182
return y, guard_zero(expand_derivatives(D(dy)))
180183
end
181-
182-

src/integral.jl

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,9 @@ function integrate_term(eq, x, l; kwargs...)
135135
args = Dict(kwargs)
136136
abstol, num_steps, num_trials, show_basis, symbolic, verbose, max_basis,
137137
radius = args[:abstol], args[:num_steps],
138-
args[:num_trials], args[:show_basis], args[:symbolic],
139-
args[:verbose],
140-
args[:max_basis], args[:radius]
138+
args[:num_trials], args[:show_basis], args[:symbolic],
139+
args[:verbose],
140+
args[:max_basis], args[:radius]
141141

142142
attempt(l, "Integrating term", eq)
143143

@@ -203,11 +203,11 @@ function integrate_term(eq, x, l; kwargs...)
203203
inform(l, "Failed numeric")
204204

205205
if i < num_steps
206-
basis1, ok1 = expand_basis(basis1, x)
207-
basis2, ok2 = expand_basis(basis2, x)
208-
209-
if !ok1 && ~ok2
210-
break
206+
basis1, ok1 = expand_basis(prune_basis(eq, x, basis1, radius; kwargs...), x)
207+
basis2, ok2 = expand_basis(prune_basis(eq, x, basis2, radius; kwargs...), x)
208+
209+
if !ok1 && ~ok2
210+
break
211211
end
212212

213213
if show_basis
@@ -230,8 +230,7 @@ end
230230
###############################################################################
231231

232232
"""
233-
the core of the randomized parameter-fitting algorithm
234-
233+
1try_integrate` is the main dispatch point to call different sparse solvers
235234
`try_integrate` tries to find a linear combination of the basis, whose
236235
derivative is equal to eq
237236
@@ -242,7 +241,10 @@ end
242241
function try_integrate(eq, x, basis, radius; kwargs...)
243242
args = Dict(kwargs)
244243
use_optim = args[:use_optim]
245-
basis = basis[2:end] # remove 1 from the beginning
244+
245+
if isempty(basis)
246+
return 0, Inf
247+
end
246248

247249
if use_optim
248250
return solve_optim(eq, x, basis, radius; kwargs...)
@@ -253,12 +255,13 @@ end
253255

254256
#################################################################################
255257

256-
# integrate_basis is used for debugging and should not be called in the course of normal execution
257-
function integrate_basis(eq, x = var(eq); abstol = 1e-6, radius = 1.0, complex_plane = true)
258+
"""
259+
integrate_basis is used for debugging and should not be called in the course of normal execution
260+
"""
261+
function integrate_basis(eq, x = var(eq); abstol = 1e-6, radius = 1.0, complex_plane = true)
258262
eq = cache(expand(eq))
259263
basis = generate_basis(eq, x, false)
260264
n = length(basis)
261-
A, X = init_basis_matrix(eq, x, basis, radius, complex_plane; abstol)
262-
return basis, A, X
265+
A, X = init_basis_matrix(eq, x, basis, radius, complex_plane; abstol)
266+
return basis, A, X
263267
end
264-

src/optim.jl

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,18 @@
11
using Optim
22

3-
function solve_optim(T, eq, x, basis, radius, rounds = 2; kwargs...)
3+
function solve_optim(eq, x, basis, radius; kwargs...)
44
args = Dict(kwargs)
55
abstol, complex_plane, verbose = args[:abstol], args[:complex_plane], args[:verbose]
66

77
n = length(basis)
88
λ = 1e-9
99

10-
A = zeros(Complex{T}, (2n, n))
11-
X = zeros(Complex{T}, 2n)
12-
init_basis_matrix!(T, A, X, x, eq, basis, radius, complex_plane; abstol)
13-
# modify_basis_matrix!(T, A, X, x, eq, basis, radius; abstol)
10+
A, X = init_basis_matrix(eq, x, basis, radius, complex_plane; abstol)
1411

1512
l = find_independent_subset(A; abstol)
1613
A, basis, n = A[:, l], basis[l], sum(l)
1714
p = rank_basis(A, basis)
1815

19-
# q, ϵ = find_minimizer(A, λ)
20-
21-
# if ϵ > abstol
22-
# return 0, ϵ
23-
# end
24-
25-
# qa = q
26-
# μ = maximum(abs.(qa))
27-
28-
# for ρ in exp10.(-1:-1:-8)
29-
# l = abs.(qa) .> ρ * μ
30-
3116
qm = zeros(n)
3217
ϵm = 1e6
3318
lm = qm .> 0

0 commit comments

Comments
 (0)