diff --git a/engine-proto/engine.jl b/engine-proto/Engine.jl similarity index 76% rename from engine-proto/engine.jl rename to engine-proto/Engine.jl index 2f7294a..a632581 100644 --- a/engine-proto/engine.jl +++ b/engine-proto/Engine.jl @@ -1,3 +1,5 @@ +include("HittingSet.jl") + module Engine export Construction, mprod @@ -6,6 +8,24 @@ import Subscripts using LinearAlgebra using AbstractAlgebra using Groebner +using ..HittingSet + +# --- commutative algebra --- + +# as of version 0.36.6, AbstractAlgebra only supports ideals in multivariate +# polynomial rings when the coefficients are integers. we use Groebner to extend +# support to rationals and to finite fields of prime order +Generic.reduce_gens(I::Generic.Ideal{U}) where {T <: FieldElement, U <: MPolyRingElem{T}} = + Generic.Ideal{U}(base_ring(I), groebner(gens(I))) + +function codimension(I::Generic.Ideal{U}, maxdepth = Inf) where {T <: RingElement, U <: MPolyRingElem{T}} + leading = [exponent_vector(f, 1) for f in gens(I)] + targets = [Set(findall(.!iszero.(exp_vec))) for exp_vec in leading] + length(HittingSet.solve(HittingSetProblem(targets), maxdepth)) +end + +dimension(I::Generic.Ideal{U}, maxdepth = Inf) where {T <: RingElement, U <: MPolyRingElem{T}} = + length(gens(base_ring(I))) - codimension(I, maxdepth) # --- primitve elements --- @@ -23,8 +43,6 @@ mutable struct Point{T} <: Element{T} ) where T = new(coords, vec, nothing) end -##coordnames(_::Point) = [:xₚ, :yₚ, :zₚ] - function buildvec!(pt::Point) coordring = parent(pt.coords[1]) pt.vec = [one(coordring), dot(pt.coords, pt.coords), pt.coords...] @@ -43,8 +61,6 @@ mutable struct Sphere{T} <: Element{T} ) where T = new(coords, vec, rel) end -##coordnames(_::Sphere) = [:rₛ, :sₛ, :xₛ, :yₛ, :zₛ] - function buildvec!(sph::Sphere) coordring = parent(sph.coords[1]) sph.vec = sph.coords @@ -130,10 +146,6 @@ function realize(ctx::Construction{T}) where T end end - display(collect(elemenum)) - display(coordnamelist) - println() - # construct coordinate ring coordring, coordqueue = polynomial_ring(parent_type(T)(), coordnamelist, ordering = :degrevlex) @@ -150,16 +162,14 @@ function realize(ctx::Construction{T}) where T # construct coordinate vectors for (_, elem) in elemenum buildvec!(elem) - display(elem.coords) - display(elem.vec) - println() end # turn relations into equations - vcat( + eqns = vcat( equation.(ctx.relations), [elem.rel for elem in ctx.elements if !isnothing(elem.rel)] ) + Generic.Ideal(coordring, eqns) end end @@ -172,22 +182,26 @@ a = Engine.Point{CoeffType}() s = Engine.Sphere{CoeffType}() a_on_s = Engine.LiesOn{CoeffType}(a, s) ctx = Engine.Construction{CoeffType}(elements = Set([a]), relations= Set([a_on_s])) -eqns_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") b = Engine.Point{CoeffType}() b_on_s = Engine.LiesOn{CoeffType}(b, s) Engine.push!(ctx, b) Engine.push!(ctx, s) Engine.push!(ctx, b_on_s) -eqns_ab_s = Engine.realize(ctx) +ideal_ab_s = Engine.realize(ctx) +println("Two points on a sphere: ", Engine.dimension(ideal_ab_s), " degrees of freeom") spheres = [Engine.Sphere{CoeffType}() for _ in 1:3] tangencies = [ Engine.AlignsWithBy{CoeffType}( spheres[n], spheres[mod1(n+1, length(spheres))], - -1//1 + CoeffType(-1//1) ) for n in 1:3 ] -ctx_chain = Engine.Construction{CoeffType}(elements = Set(spheres), relations = Set(tangencies)) \ No newline at end of file +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 freeom") \ No newline at end of file diff --git a/engine-proto/hitting-set.jl b/engine-proto/HittingSet.jl similarity index 89% rename from engine-proto/hitting-set.jl rename to engine-proto/HittingSet.jl index e9aacf4..347c4d2 100644 --- a/engine-proto/hitting-set.jl +++ b/engine-proto/HittingSet.jl @@ -1,13 +1,15 @@ module HittingSet +export HittingSetProblem, solve + HittingSetProblem{T} = Pair{Set{T}, Vector{Pair{T, Set{Set{T}}}}} -# `subsets` should be a collection of Set objects -function HittingSetProblem(subsets, chosen = Set()) - wholeset = union(subsets...) +# `targets` should be a collection of Set objects +function HittingSetProblem(targets, chosen = Set()) + wholeset = union(targets...) T = eltype(wholeset) unsorted_moves = [ - elt => Set(filter(s -> elt ∉ s, subsets)) + elt => Set(filter(s -> elt ∉ s, targets)) for elt in wholeset ] moves = sort(unsorted_moves, by = pair -> length(pair.second)) @@ -32,7 +34,6 @@ end function solve(pblm::HittingSetProblem{T}, maxdepth = Inf) where T problems = Dict(pblm) - println(typeof(problems)) while length(first(problems).first) < maxdepth subproblems = typeof(problems)() for (chosen, moves) in problems @@ -56,7 +57,7 @@ end function test(n = 1) T = [Int64, Int64, Symbol, Symbol][n] - subsets = Set{T}.([ + targets = Set{T}.([ [ [1, 3, 5], [2, 3, 4], @@ -98,7 +99,7 @@ function test(n = 1) [:b, :z, :t14] ] ][n]) - problem = HittingSetProblem(subsets) + problem = HittingSetProblem(targets) if isa(problem, HittingSetProblem{T}) println("Correct type") else