Skip to content

Commit 5b38909

Browse files
authored
Merge pull request #600 from oameye/main
fix: fix total degree with many parameters threaded (#599)
2 parents 383d95d + 2f01fe8 commit 5b38909

File tree

6 files changed

+157
-51
lines changed

6 files changed

+157
-51
lines changed

benchmarks/bio-chemical-rection-networks.jl

Lines changed: 95 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,82 +6,135 @@ using HomotopyContinuation, DynamicPolynomials, LinearAlgebra
66
@polyvar x[1:3] p[1:10]
77

88
N = 1000
9-
results1_direct = fill(0,8)
10-
results1_template = fill(0,8)
11-
results2_direct = fill(0,8)
12-
results2_template = fill(0,8)
13-
results3_direct = fill(0,8)
14-
results3_template = fill(0,8)
15-
results4_direct = fill(0,8)
16-
results4_template = fill(0,8)
9+
results1_direct = fill(0, 8)
10+
results1_template = fill(0, 8)
11+
results2_direct = fill(0, 8)
12+
results2_template = fill(0, 8)
13+
results3_direct = fill(0, 8)
14+
results3_template = fill(0, 8)
15+
results4_direct = fill(0, 8)
16+
results4_template = fill(0, 8)
1717

1818
@time for i = 1:N
19-
pol = [ -x[1]*x[3]*p[3] - x[1]*p[2] + p[1],
20-
x[1]*x[2]*x[3]*p[8]*p[9] + x[1]*x[3]*p[7]*p[8]*p[9] - x[2]*x[3]*p[5]*p[6] - x[2]*p[5]*p[6]*p[10] - x[2]*x[3]*p[4] - x[2]*p[4]*p[10],
21-
x[2] + x[3] - 1.0 ]
22-
p_vals = [0.04,0.04,1.,1.,10.0,0.,0.04,35.,.1,.04]
19+
pol = [
20+
-x[1] * x[3] * p[3] - x[1] * p[2] + p[1],
21+
x[1] * x[2] * x[3] * p[8] * p[9] + x[1] * x[3] * p[7] * p[8] * p[9] -
22+
x[2] * x[3] * p[5] * p[6] - x[2] * p[5] * p[6] * p[10] - x[2] * x[3] * p[4] -
23+
x[2] * p[4] * p[10],
24+
x[2] + x[3] - 1.0,
25+
]
26+
p_vals = [0.04, 0.04, 1.0, 1.0, 10.0, 0.0, 0.04, 35.0, 0.1, 0.04]
2327
pol_pars = DynamicPolynomials.subs.(pol, Ref(p => p_vals))
24-
sol = solutions(solve(pol_pars, show_progress=false))
25-
results1_direct[length(sol)+1] +=1
28+
sol = solutions(solve(pol_pars, show_progress = false))
29+
results1_direct[length(sol)+1] += 1
2630

2731
p_template = randn(ComplexF64, 10)
2832
f_template = DynamicPolynomials.subs.(pol, Ref(p => p_template))
29-
result_template = solutions(solve(f_template, show_progress=false))
30-
sol_again = solutions(solve(pol, result_template, parameters=p, p₁=p_template,
31-
p₀=ComplexF64.(p_vals), show_progress=false))
33+
result_template = solutions(solve(f_template, show_progress = false))
34+
sol_again = solutions(
35+
solve(
36+
pol,
37+
result_template,
38+
parameters = p,
39+
p₁ = p_template,
40+
p₀ = ComplexF64.(p_vals),
41+
show_progress = false,
42+
),
43+
)
3244
results1_template[length(sol_again)+1] += 1
3345

34-
pol2 = [ -x[1]^5*x[2]*p[5] + x[1]^4*x[3]*p[6]*p[8] - x[1]*x[2]*p[3]^4*p[5] + x[3]*p[3]^4*p[6]*p[8] - x[1]^5*p[7] + x[1]^4*x[3]*p[4] - x[1]*p[3]^4*p[7] + x[3]*p[3]^4*p[4] + x[1]^4*p[1] + x[1]^4*p[2] + p[1]*p[3]^4,
35-
-x[1]^5*x[2]*p[5] - x[1]*x[2]*p[3]^4*p[5] - x[1]^4*x[2]*p[7] + x[1]^4*x[3]*p[4] - x[2]*p[3]^4*p[7] + x[3]*p[3]^4*p[4] + x[1]^4*p[1] + x[1]^4*p[2] + p[1]*p[3]^4,
36-
x[1]*x[2]*p[5] - x[3]*p[6]*p[8] - x[3]*p[4] - x[3]*p[7] ]
37-
p2_vals = [0.005, 0.1, 2.8, 10, 100, 0.1, 0.01, 0.]
46+
pol2 = [
47+
-x[1]^5 * x[2] * p[5] + x[1]^4 * x[3] * p[6] * p[8] - x[1] * x[2] * p[3]^4 * p[5] + x[3] * p[3]^4 * p[6] * p[8] - x[1]^5 * p[7] +
48+
x[1]^4 * x[3] * p[4] - x[1] * p[3]^4 * p[7] +
49+
x[3] * p[3]^4 * p[4] +
50+
x[1]^4 * p[1] +
51+
x[1]^4 * p[2] +
52+
p[1] * p[3]^4,
53+
-x[1]^5 * x[2] * p[5] - x[1] * x[2] * p[3]^4 * p[5] - x[1]^4 * x[2] * p[7] +
54+
x[1]^4 * x[3] * p[4] - x[2] * p[3]^4 * p[7] +
55+
x[3] * p[3]^4 * p[4] +
56+
x[1]^4 * p[1] +
57+
x[1]^4 * p[2] +
58+
p[1] * p[3]^4,
59+
x[1] * x[2] * p[5] - x[3] * p[6] * p[8] - x[3] * p[4] - x[3] * p[7],
60+
]
61+
p2_vals = [0.005, 0.1, 2.8, 10, 100, 0.1, 0.01, 0.0]
3862
pol2_pars = DynamicPolynomials.subs.(pol2, Ref(p => p2_vals))
39-
sol2 = solutions(solve(pol2_pars, show_progress=false))
40-
results2_direct[length(sol2)+1] +=1
63+
sol2 = solutions(solve(pol2_pars, show_progress = false))
64+
results2_direct[length(sol2)+1] += 1
4165

4266
p2_template = randn(ComplexF64, 8)
4367
f2_template = DynamicPolynomials.subs.(pol2, Ref(p => p2_template))
44-
solve_templ2 = solve(f2_template, show_progress=false)
68+
solve_templ2 = solve(f2_template, show_progress = false)
4569
result2_template = solutions(solve_templ2)
46-
sol2_again = solutions(solve(pol2, result2_template, precision=PRECISION_ADAPTIVE, parameters=p[1:8], p₁=p2_template, p₀=ComplexF64.(p2_vals), show_progress=false))
70+
sol2_again = solutions(
71+
solve(
72+
pol2,
73+
result2_template,
74+
precision = PRECISION_ADAPTIVE,
75+
parameters = p[1:8],
76+
p₁ = p2_template,
77+
p₀ = ComplexF64.(p2_vals),
78+
show_progress = false,
79+
),
80+
)
4781

48-
results2_template[length(sol2_again)+1] +=1
82+
results2_template[length(sol2_again)+1] += 1
4983

5084
pol3 = pol2
51-
p3_vals = [0.005, 0.1, 2.8, 10, 100, 0.1, 0.01, 1.] #Last parameter is 1 and not 0. Here there should be 3 real solutions instead of 1.
85+
p3_vals = [0.005, 0.1, 2.8, 10, 100, 0.1, 0.01, 1.0] #Last parameter is 1 and not 0. Here there should be 3 real solutions instead of 1.
5286
pol3_pars = DynamicPolynomials.subs.(pol3, Ref(p => p3_vals))
53-
sol3 = solutions(solve(pol3_pars, precision=PRECISION_ADAPTIVE, show_progress=false))
54-
results3_direct[length(sol3)+1] +=1
87+
sol3 =
88+
solutions(solve(pol3_pars, precision = PRECISION_ADAPTIVE, show_progress = false))
89+
results3_direct[length(sol3)+1] += 1
5590

5691
p3_template = randn(ComplexF64, 8)
5792
f3_template = DynamicPolynomials.subs.(pol3, Ref(p => p3_template))
58-
result3_template = solutions(solve(f3_template, show_progress=false))
59-
sol3_again = solutions(solve(pol3, result3_template, parameters=p[1:8], p₁=p3_template, p₀=ComplexF64.(p3_vals), show_progress=false))
60-
results3_template[length(sol3_again)+1] +=1
93+
result3_template = solutions(solve(f3_template, show_progress = false))
94+
sol3_again = solutions(
95+
solve(
96+
pol3,
97+
result3_template,
98+
parameters = p[1:8],
99+
p₁ = p3_template,
100+
p₀ = ComplexF64.(p3_vals),
101+
show_progress = false,
102+
),
103+
)
104+
results3_template[length(sol3_again)+1] += 1
61105

62-
pol4 = [-x[1]^3*p[3] - x[1]*p[2]^2*p[3] + x[1]^2*p[1]]
63-
p4_vals = [1., 0.2, 1.];
106+
pol4 = [-x[1]^3 * p[3] - x[1] * p[2]^2 * p[3] + x[1]^2 * p[1]]
107+
p4_vals = [1.0, 0.2, 1.0]
64108
pol4_pars = DynamicPolynomials.subs.(pol4, Ref(p => p4_vals))
65-
sol4 = solutions(solve(pol4_pars, show_progress=false))
66-
results4_direct[length(sol4)+1] +=1
109+
sol4 = solutions(solve(pol4_pars, show_progress = false))
110+
results4_direct[length(sol4)+1] += 1
67111

68112
p4_template = randn(ComplexF64, 3)
69113
f4_template = DynamicPolynomials.subs.(pol4, Ref(p => p4_template))
70-
result4_template = solutions(solve(f4_template, show_progress=false))
71-
sol4_again = solutions(solve(pol4, result4_template, parameters=p[1:3], p₁=p4_template, p₀=ComplexF64.(p4_vals), show_progress=false))
72-
results4_template[length(sol4_again)+1] +=1
114+
result4_template = solutions(solve(f4_template, show_progress = false))
115+
sol4_again = solutions(
116+
solve(
117+
pol4,
118+
result4_template,
119+
parameters = p[1:3],
120+
p₁ = p4_template,
121+
p₀ = ComplexF64.(p4_vals),
122+
show_progress = false,
123+
),
124+
)
125+
results4_template[length(sol4_again)+1] += 1
73126
end
74127

75128
# These numbers should all coincide
76129
println("Results for the first system")
77130
println(results1_direct)
78-
println(results1_template,"\n")
131+
println(results1_template, "\n")
79132
println("Results for the second system")
80133
println(results2_direct)
81-
println(results2_template,"\n")
134+
println(results2_template, "\n")
82135
println("Results for the third system")
83136
println(results3_direct)
84-
println(results3_template,"\n")
137+
println(results3_template, "\n")
85138
println("Results for the fourth system")
86139
println(results4_direct)
87140
println(results4_template)

benchmarks/cyclooctane.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ using HomotopyContinuation, LinearAlgebra, DynamicPolynomials
44
= 2
55
@polyvar z[1:3, 1:6]
66
z_vec = vec(z)[1:17] # the 17 variables in a vector
7-
Z = [zeros(3) z[:,1:5] [z[1,6]; z[2,6]; 0] [c²; 0; 0]] # the eight points in a matrix
7+
Z = [zeros(3) z[:, 1:5] [z[1, 6]; z[2, 6]; 0] [c²; 0; 0]] # the eight points in a matrix
88

99
# define the functions for cyclooctane:
10-
F1 = [(Z[:, i] - Z[:, i+1]) (Z[:, i] - Z[:, i+1]) -for i in 1:7]
11-
F2 = [(Z[:, i] - Z[:, i+2]) (Z[:, i] - Z[:, i+2]) - 8/3 for i in 1:6]
12-
F3 = (Z[:, 7] - Z[:, 1]) (Z[:, 7] - Z[:, 1]) - 8/3
13-
F4 = (Z[:, 8] - Z[:, 2]) (Z[:, 8] - Z[:, 2]) - 8/3
10+
F1 = [(Z[:, i] - Z[:, i+1]) (Z[:, i] - Z[:, i+1]) -for i = 1:7]
11+
F2 = [(Z[:, i] - Z[:, i+2]) (Z[:, i] - Z[:, i+2]) - 8 / 3 for i = 1:6]
12+
F3 = (Z[:, 7] - Z[:, 1]) (Z[:, 7] - Z[:, 1]) - 8 / 3
13+
F4 = (Z[:, 8] - Z[:, 2]) (Z[:, 8] - Z[:, 2]) - 8 / 3
1414
f = [F1; F2; F3; F4]
1515

1616
n = 2 # dimension of the cyclooctane variety

benchmarks/run_system_benchmark.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,4 @@ function run_benchmark(file_name)
5050

5151
BenchmarkTools.save(file_name, res)
5252
return res
53-
end
53+
end

benchmarks/tritangents.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ f = equations(tritangents())
55
res = solve(f)
66
println("# nonsingular: ", nnonsingular(res)) # should be 720
77

8-
res = solve(f; start_system=:polyhedral)
8+
res = solve(f; start_system = :polyhedral)
99
println("# nonsingular: ", nnonsingular(res)) # should be 720

src/solve.jl

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ function solver_startsolutions(
130130
)
131131
!isnothing(seed) && Random.seed!(seed)
132132

133+
133134
used_start_system = nothing
134135
if start_subspace !== nothing
135136
if target_parameters !== nothing
@@ -471,6 +472,7 @@ function solve(
471472
else
472473
solver, starts = solver_startsolutions(args...; kwargs...)
473474
end
475+
474476
if many_parameters
475477
solve(
476478
solver,
@@ -703,6 +705,7 @@ function solve(
703705
n = length(target_parameters)
704706

705707
progress = show_progress ? make_many_progress(n; delay = 0.3) : nothing
708+
706709
many_solve(
707710
S,
708711
starts,
@@ -757,10 +760,17 @@ function many_solve(
757760
threading::Bool,
758761
catch_interrupt::Bool,
759762
) where {flatten}
763+
764+
765+
if isa(starts, TotalDegreeStartSolutionsIterator)
766+
@warn "Solving for many parameters with total degree start system is not recommended. Instead, one should use a two-step approach: first solve a system with generic parameters, and track its solutions to the desired parameters. See https://www.juliahomotopycontinuation.org/guides/many-systems/."
767+
elseif isa(starts, PolyhedralStartSolutionsIterator)
768+
@error "Solving for many parameters with polyhedral start system is not implemented and also not recommended. Instead, one should use a two-step approach: solve a system with generic parameters, and track its solutions to the desired parameters. See https://www.juliahomotopycontinuation.org/guides/many-systems/."
769+
end
760770
q = first(many_target_parameters)
761771
target_parameters!(solver, transform_parameters(q))
762772
if threading
763-
res = threaded_solve(solver, starts; catch_interrupt = false)
773+
res = threaded_solve(solver, collect(starts); catch_interrupt = false)
764774
else
765775
res = serial_solve(solver, starts; catch_interrupt = false)
766776
end
@@ -775,11 +785,14 @@ function many_solve(
775785
k = 1
776786
m = length(starts)
777787
update_many_progress!(progress, results, k, m; flatten = flatten)
788+
789+
790+
778791
try
779792
for q in Iterators.drop(many_target_parameters, 1)
780793
target_parameters!(solver, transform_parameters(q))
781794
if threading
782-
res = threaded_solve(solver, starts; catch_interrupt = false)
795+
res = threaded_solve(solver, collect(starts); catch_interrupt = false)
783796
else
784797
res = serial_solve(solver, starts; catch_interrupt = false)
785798
end

test/solve_test.jl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,5 +583,45 @@
583583
intrinsic = false,
584584
)
585585
@test all(r -> nsolutions(first(r)) == 2, result1)
586+
587+
@testset "Many parameters threaded" begin
588+
@var u1, v1, ω, α, γ, λ, ω0
589+
590+
eqs = [
591+
-u1 * ω^2 +
592+
u1 * ω0^2 +
593+
(3 / 4) * u1^3 * α +
594+
(3 / 4) * u1 * v1^2 * α +
595+
(-1 / 2) * u1 * λ * ω0^2 +
596+
v1 * γ * ω,
597+
-v1 * ω^2 + v1 * ω0^2 + (3 / 4) * v1^3 * α - u1 * γ * ω +
598+
(3 / 4) * u1^2 * v1 * α +
599+
(1 / 2) * v1 * λ * ω0^2,
600+
]
601+
602+
F = System(eqs, parameters = [ω, α, γ, λ, ω0], variables = [u1, v1])
603+
604+
input_array = [
605+
[0.9, 1.0, 0.01, 0.01, 1.1],
606+
[0.9105263157894737, 1.0, 0.01, 0.01, 1.1],
607+
[0.9210526315789473, 1.0, 0.01, 0.01, 1.1],
608+
[0.9315789473684211, 1.0, 0.01, 0.01, 1.1],
609+
[0.9421052631578948, 1.0, 0.01, 0.01, 1.1],
610+
[0.9526315789473684, 1.0, 0.01, 0.01, 1.1],
611+
]
612+
613+
generic_parameters = randn(ComplexF64, 5)
614+
615+
R0 = solve(F; target_parameters = generic_parameters, threading = true)
616+
R1 = solve(
617+
F,
618+
solutions(R0);
619+
start_parameters = generic_parameters,
620+
target_parameters = input_array,
621+
threading = true,
622+
)
623+
624+
@test length(R1) == 6
625+
end
586626
end
587627
end

0 commit comments

Comments
 (0)