1 | initial version |
A lazy alternative to @Max Alekseyev's excellent answer is to use one of Sage's symbolic solvers
2 | No.2 Revision |
A lazy alternative to @Max Alekseyev's excellent answer is to use one of Sage's symbolic solvers and to filter out the undeterminates returned by these solvers.
After running :
SymUnk=list(map(SR, (x, y, z)))
def foo():
Sols=[]
for fff in Combinations(Lf, 3):
if len((B:=RR.ideal(fff).groebner_basis()))==3:
SSol=solve([SR(u)==0 for u in B],
SymUnk,
solution_dict=True)
Sol=[]
for S in SSol:
SRR={}
for u in S.keys():
try:
SRR|={RR(u):RR(S[u])}
except:
continue
Sol+=[SRR]
Sols+=[Sol]
return Sols
Running :
sage: %time Sols=foo()
CPU times: user 2min 1s, sys: 105 ms, total: 2min 1s
Wall time: 1min 48s
sage: len(Sols)
245
returns 245 solutions. However, many of them are duplicates, as can be shown by indexing them on the `groebner_b
3 | No.3 Revision |
A lazy alternative to @Max Alekseyev's excellent answer is to use one of Sage's symbolic solvers solvers, which already take care of non-zero-dimension solutions, and to filter out the undeterminates returned by these solvers.
After running :
SymUnk=list(map(SR, (x, y, z)))
def foo():
Sols=[]
for fff in Combinations(Lf, 3):
if len((B:=RR.ideal(fff).groebner_basis()))==3:
SSol=solve([SR(u)==0 for u in B],
SymUnk,
solution_dict=True)
Sol=[]
for S in SSol:
SRR={}
for u in S.keys():
try:
SRR|={RR(u):RR(S[u])}
except:
continue
Sol+=[SRR]
Sols+=[Sol]
return Sols
Running :
sage: %time Sols=foo()
CPU times: user 2min 1s, sys: 105 ms, total: 2min 1s
Wall time: 1min 48s
sage: len(Sols)
245
returns 245 solutions. However, many of them are duplicates, as can be shown by indexing them on the `groebner_bgroebner_basis()
solved :
def bar():
Sols={}
for fff in Combinations(Lf, 3):
if len((B:=RR.ideal(fff).groebner_basis()))==3:
SSol=solve([SR(u)==0 for u in B],
SymUnk,
solution_dict=True)
Sol=[]
for S in SSol:
SRR={}
for u in S.keys():
try:
SRR|={RR(u):RR(S[u])}
except:
continue
Sol+=[SRR]
Sols|={B:Sol}
return Sols
sage: %time DSols=bar()
CPU times: user 2min 2s, sys: 84.4 ms, total: 2min 2s
Wall time: 1min 49s
sage: len(DSols)
156
These solutions to 156 distinct Groebner bases give 260 solutions :
sage: Set(flatten(list(DSols.values()))).cardinality()
260
In the present case, the laziness isn' too costly (2 minutes is way less than the time necessary tio rig up a general solution with polynomial rings tools...).
HTH
4 | No.4 Revision |
A lazy alternative to @Max Alekseyev's excellent answer is to use one of Sage's symbolic solvers, which already take care of non-zero-dimension solutions, and to filter out the undeterminates returned by these solvers.
After running :
SymUnk=list(map(SR, (x, y, z)))
def foo():
Sols=[]
for fff in Combinations(Lf, 3):
if len((B:=RR.ideal(fff).groebner_basis()))==3:
SSol=solve([SR(u)==0 for u in B],
SymUnk,
solution_dict=True)
Sol=[]
for S in SSol:
SRR={}
for u in S.keys():
try:
SRR|={RR(u):RR(S[u])}
except:
continue
Sol+=[SRR]
Sols+=[Sol]
return Sols
Running :
sage: %time Sols=foo()
CPU times: user 2min 1s, sys: 105 ms, total: 2min 1s
Wall time: 1min 48s
sage: len(Sols)
245
returns 245 solutions. However, many of them are duplicates, as can be shown by indexing them on the groebner_basis()
solved :
def bar():
Sols={}
for fff in Combinations(Lf, 3):
if len((B:=RR.ideal(fff).groebner_basis()))==3:
SSol=solve([SR(u)==0 for u in B],
SymUnk,
solution_dict=True)
Sol=[]
for S in SSol:
SRR={}
for u in S.keys():
try:
SRR|={RR(u):RR(S[u])}
except:
continue
Sol+=[SRR]
Sols|={B:Sol}
return Sols
sage: %time DSols=bar()
CPU times: user 2min 2s, sys: 84.4 ms, total: 2min 2s
Wall time: 1min 49s
sage: len(DSols)
156
These solutions to 156 distinct Groebner bases give 260 solutions :
sage: Set(flatten(list(DSols.values()))).cardinality()
260
In the present case, the laziness isn' too isn't too costly (2 minutes is way less than the time necessary tio to rig up a general solution with polynomial rings tools...).
HTH
5 | No.5 Revision |
A lazy alternative to @Max Alekseyev's excellent answer is to use one of Sage's symbolic solvers, which already take care of non-zero-dimension solutions, and to filter out the undeterminates returned by these solvers.
After running :
SymUnk=list(map(SR, (x, y, z)))
def foo():
Sols=[]
for fff in Combinations(Lf, 3):
if len((B:=RR.ideal(fff).groebner_basis()))==3:
SSol=solve([SR(u)==0 for u in B],
SymUnk,
solution_dict=True)
Sol=[]
for S in SSol:
SRR={}
for u in S.keys():
try:
SRR|={RR(u):RR(S[u])}
except:
continue
Sol+=[SRR]
Sols+=[Sol]
return Sols
Running :
sage: %time Sols=foo()
CPU times: user 2min 1s, sys: 105 ms, total: 2min 1s
Wall time: 1min 48s
sage: len(Sols)
245
returns 245 solutions. However, many of them are duplicates, as can be shown by indexing them on the groebner_basis()
solved :
def bar():
Sols={}
for fff in Combinations(Lf, 3):
if len((B:=RR.ideal(fff).groebner_basis()))==3:
SSol=solve([SR(u)==0 for u in B],
SymUnk,
solution_dict=True)
Sol=[]
for S in SSol:
SRR={}
for u in S.keys():
try:
SRR|={RR(u):RR(S[u])}
except:
continue
Sol+=[SRR]
Sols|={B:Sol}
return Sols
sage: %time DSols=bar()
CPU times: user 2min 2s, sys: 84.4 ms, total: 2min 2s
Wall time: 1min 49s
sage: len(DSols)
156
These solutions to 156 distinct Groebner bases give 260 solutions :
sage: Set(flatten(list(DSols.values()))).cardinality()
260
In the present case, the laziness isn't too costly (2 minutes is way less than the time necessary to rig up a general solution with polynomial rings tools...).
UPDATE :
It turns out that Sympy's solver does a better job than Sage's for dimension>0 ideals. An alternative way to write the solutions is :
# List of pairs (triplets, base) with Groebnar base of length 3
Triplets = [[u, b]
for u in Combinations(Lf, 3)
if len(b:=Rr.ideal(u).groebner_basis())==3]
# List of *distinct* bases
Bases = list(uniq([u[1] for u in Triplets]))
# Solve them *IN SR* using sympy :
# Precompute the unknowns
Unk = list(map(lambda u:SR(u), Rr.gens()))
# Solve
SSols = [solve([SR(u) for u in v], Unk, algorithm="sympy") for v in Bases]
FWIW :
sage: %time SSols = [solve([SR(u) for u in v], Unk, algorithm="sympy") for v in Bases]
CPU times: user 3.27 s, sys: 0 ns, total: 3.27 s
Wall time: 3.27 s
Sympy's solver seems also faster than Sage's...
Since neither the triplets nor the bases can be used as dictionary keys ("unhashable"), we need a bit of record-keeping :
# Record the base-solutions link
BS=list(map(list, zip(Bases, SSols)))
# Link triplets to their solutions
TBS=[[u[0]]+BS[Bases.index(u[1])] for u in Triplets]
Expressing the SR solutions in the original ring is lazily left to the reader...
HTH