Seek sample solutions by cutting with a hyperplane

The example hyperplane yields a single solution, with multiplicity six. You can
find it analytically by hand, and homotopy continuation finds it numerically.
This commit is contained in:
Aaron Fenyes 2024-02-08 01:53:55 -05:00
parent 43cbf8a3a0
commit 45aaaafc8f

View File

@ -2,12 +2,13 @@ include("HittingSet.jl")
module Engine module Engine
export Construction, mprod export Construction, mprod, codimension, dimension
import Subscripts import Subscripts
using LinearAlgebra using LinearAlgebra
using AbstractAlgebra using AbstractAlgebra
using Groebner using Groebner
using HomotopyContinuation: Variable, Expression, System
using ..HittingSet using ..HittingSet
# --- commutative algebra --- # --- commutative algebra ---
@ -27,6 +28,34 @@ end
dimension(I::Generic.Ideal{U}, maxdepth = Inf) where {T <: RingElement, U <: MPolyRingElem{T}} = dimension(I::Generic.Ideal{U}, maxdepth = Inf) where {T <: RingElement, U <: MPolyRingElem{T}} =
length(gens(base_ring(I))) - codimension(I, maxdepth) length(gens(base_ring(I))) - codimension(I, maxdepth)
# hat tip Sascha Timme
# https://github.com/JuliaHomotopyContinuation/HomotopyContinuation.jl/issues/520#issuecomment-1317681521
function Base.convert(::Type{Expression}, f::MPolyRingElem)
variables = Variable.(symbols(parent(f)))
f_data = zip(coefficients(f), exponent_vectors(f))
sum(cf * prod(variables .^ exp_vec) for (cf, exp_vec) in f_data)
end
# create a ModelKit.System from an ideal in a multivariate polynomial ring. the
# variable ordering is taken from the polynomial ring
function System(I::Generic.Ideal)
eqns = Expression.(gens(I))
variables = Variable.(symbols(base_ring(I)))
System(eqns, variables = variables)
end
## [to do] not needed right now
# create a ModelKit.System from a list of elements of a multivariate polynomial
# ring. the variable ordering is taken from the polynomial ring
##function System(eqns::AbstractVector{MPolyRingElem})
## if isempty(eqns)
## return System([])
## else
## variables = Variable.(symbols(parent(f)))
## return System(Expression.(eqns), variables = variables)
## end
##end
# --- primitve elements --- # --- primitve elements ---
abstract type Element{T} end abstract type Element{T} end
@ -189,39 +218,75 @@ function realize(ctx::Construction{T}) where T
append!(eqns, [sum(sph.coords[k] for sph in ctx.spheres) for k in 3:4]) append!(eqns, [sum(sph.coords[k] for sph in ctx.spheres) for k in 3:4])
end end
Generic.Ideal(coordring, eqns) (Generic.Ideal(coordring, eqns), eqns)
end end
end end
# ~~~ sandbox setup ~~~ # ~~~ sandbox setup ~~~
using AbstractAlgebra
using HomotopyContinuation
CoeffType = Rational{Int64} CoeffType = Rational{Int64}
a = Engine.Point{CoeffType}() a = Engine.Point{CoeffType}()
s = Engine.Sphere{CoeffType}() s = Engine.Sphere{CoeffType}()
a_on_s = Engine.LiesOn{CoeffType}(a, s) a_on_s = Engine.LiesOn{CoeffType}(a, s)
ctx = Engine.Construction{CoeffType}(elements = Set([a]), relations= Set([a_on_s])) ctx = Engine.Construction{CoeffType}(elements = Set([a]), relations= Set([a_on_s]))
ideal_a_s = Engine.realize(ctx) ##ideal_a_s = Engine.realize(ctx)
println("A point on a sphere: ", Engine.dimension(ideal_a_s), " degrees of freeom") ##println("A point on a sphere: ", Engine.dimension(ideal_a_s), " degrees of freedom")
b = Engine.Point{CoeffType}() b = Engine.Point{CoeffType}()
b_on_s = Engine.LiesOn{CoeffType}(b, s) b_on_s = Engine.LiesOn{CoeffType}(b, s)
Engine.push!(ctx, b) Engine.push!(ctx, b)
Engine.push!(ctx, s) Engine.push!(ctx, s)
Engine.push!(ctx, b_on_s) Engine.push!(ctx, b_on_s)
ideal_ab_s = Engine.realize(ctx) ideal_ab_s, eqns_ab_s = Engine.realize(ctx)
println("Two points on a sphere: ", Engine.dimension(ideal_ab_s), " degrees of freeom") println("Two points on a sphere: ", Engine.dimension(ideal_ab_s), " degrees of freedom")
spheres = [Engine.Sphere{CoeffType}() for _ in 1:3] ##spheres = [Engine.Sphere{CoeffType}() for _ in 1:3]
tangencies = [ ##tangencies = [
Engine.AlignsWithBy{CoeffType}( ## Engine.AlignsWithBy{CoeffType}(
spheres[n], ## spheres[n],
spheres[mod1(n+1, length(spheres))], ## spheres[mod1(n+1, length(spheres))],
CoeffType(-1//1) ## CoeffType(-1//1)
) ## )
for n in 1:3 ## for n in 1:3
##]
##ctx_tan_sph = Engine.Construction{CoeffType}(elements = Set(spheres), relations = Set(tangencies))
##ideal_tan_sph = Engine.realize(ctx_tan_sph)
##println("Three mutually tangent spheres: ", Engine.dimension(ideal_tan_sph), " degrees of freedom")
# --- test rational cut ---
cut = [
sum(vcat(a.coords, (s.coords - [0, 0, 0, 0, 1])))
sum(vcat([2, 1, 1] .* a.coords, [1, 2, 1, 1, 1] .* s.coords - [0, 0, 0, 0, 1]))
sum(vcat([1, 2, 0] .* a.coords, [1, 1, 0, 1, 2] .* s.coords - [0, 0, 0, 0, 1]))
] ]
ctx_tan_sph = Engine.Construction{CoeffType}(elements = Set(spheres), relations = Set(tangencies)) cut_ideal_ab_s = Generic.Ideal(base_ring(ideal_ab_s), [gens(ideal_ab_s); cut])
ideal_tan_sph = Engine.realize(ctx_tan_sph) cut_dim = Engine.dimension(cut_ideal_ab_s)
println("Three mutually tangent spheres: ", Engine.dimension(ideal_tan_sph), " degrees of freeom") println("Two points on a sphere, after cut: ", cut_dim, " degrees of freedom")
if cut_dim == 0
vbls = Variable.(symbols(base_ring(ideal_ab_s)))
cut_system = System([eqns_ab_s; cut], variables = vbls)
cut_result = HomotopyContinuation.solve(cut_system)
println("non-singular solutions:")
for soln in solutions(cut_result)
display(soln)
end
println("singular solutions:")
for sing in singular(cut_result)
display(sing.solution)
end
# test corresponding witness set
cut_matrix = [1 1 1 1 0 1 1 0 1 1 0; 1 2 1 2 0 1 1 0 1 1 0; 1 1 0 1 0 1 2 0 2 0 0]
cut_subspace = LinearSubspace(cut_matrix, [1, 1, 1])
witness = witness_set(System(eqns_ab_s, variables = vbls), cut_subspace)
println("witness solutions:")
for wtns in solutions(witness)
display(wtns)
end
end