diff --git a/engine-proto/ConstructionViewer.jl b/engine-proto/ConstructionViewer.jl new file mode 100644 index 0000000..7cb0450 --- /dev/null +++ b/engine-proto/ConstructionViewer.jl @@ -0,0 +1,203 @@ +module Viewer + +using Blink +using Colors +using Printf + +export ConstructionViewer, display!, opentools!, closetools! + +# === Blink utilities === + +append_to_head!(w, type, content) = @js w begin + @var element = document.createElement($type) + element.appendChild(document.createTextNode($content)) + document.head.appendChild(element) +end + +style!(w, stylesheet) = append_to_head!(w, "style", stylesheet) + +script!(w, code) = append_to_head!(w, "script", code) + +# === construction viewer === + +mutable struct ConstructionViewer + win::Window + + function ConstructionViewer() + # create window and open developer console + win = Window(Blink.Dict(:width => 620, :height => 830)) + + # set stylesheet + style!(win, """ + body { + background-color: #ccc; + } + + /* the maximum dimensions keep Ganja from blowing up the canvas */ + #view { + display: block; + width: 600px; + height: 600px; + margin-top: 10px; + margin-left: 10px; + border-radius: 10px; + background-color: #f0f0f0; + } + + #control-panel { + width: 600px; + height: 200px; + box-sizing: border-box; + padding: 5px 10px 5px 10px; + margin-top: 10px; + margin-left: 10px; + overflow-y: scroll; + border-radius: 10px; + background-color: #f0f0f0; + } + + #control-panel > div { + margin-top: 5px; + padding: 4px; + border-radius: 5px; + border: solid; + font-family: monospace; + } + """) + + # load Ganja.js + loadjs!(win, "https://unpkg.com/ganja.js") + + # create global functions and variables + script!(win, """ + // create algebra + var CGA3 = Algebra(4, 1); + + // initialize element list and palette + var elements = []; + var palette = []; + + // declare handles for the view and its options + var view; + var viewOpt; + + // declare handles for the controls + var controlPanel; + var visToggles; + + // create scene function + function scene() { + commands = []; + for (let n = 0; n < elements.length; ++n) { + if (visToggles[n].checked) { + commands.push(palette[n], elements[n]); + } + } + return commands; + } + + function updateView() { + requestAnimationFrame(view.update.bind(view, scene)); + } + """) + + @js win begin + # create view + viewOpt = Dict( + :conformal => true, + :gl => true, + :devicePixelRatio => window.devicePixelRatio + ) + view = CGA3.graph(scene, viewOpt) + view.setAttribute(:id, "view") + view.removeAttribute(:style) + document.body.replaceChildren(view) + + # create control panel + controlPanel = document.createElement(:div) + controlPanel.setAttribute(:id, "control-panel") + document.body.appendChild(controlPanel) + end + + new(win) + end +end + +function display!(viewer::ConstructionViewer, elements::Matrix) + # load elements + elements_full = [ + [0; elt; fill(0, 26)] + for elt in eachcol(elements) + ] + @js viewer.win elements = $elements_full.map((elt) -> @new CGA3(elt)) + + # generate palette. this is Gadfly's `default_discrete_colors` palette, + # available under the MIT license + palette = distinguishable_colors( + length(elements_full), + [LCHab(70, 60, 240)], + transform = c -> deuteranopic(c, 0.5), + lchoices = Float64[65, 70, 75, 80], + cchoices = Float64[0, 50, 60, 70], + hchoices = range(0, stop=330, length=24) + ) + palette_packed = [RGB24(c).color for c in palette] + @js viewer.win palette = $palette_packed + + # create visibility toggles + @js viewer.win begin + controlPanel.replaceChildren() + visToggles = [] + end + for (elt, c) in zip(eachcol(elements), palette) + vec_str = join(map(t -> @sprintf("%.3f", t), elt), ", ") + color_str = "#$(hex(c))" + style_str = "background-color: $color_str; border-color: $color_str;" + @js viewer.win begin + @var toggle = document.createElement(:div) + toggle.setAttribute(:style, $style_str) + toggle.checked = true + toggle.addEventListener( + "click", + () -> begin + toggle.checked = !toggle.checked + toggle.style.backgroundColor = toggle.checked ? $color_str : "inherit"; + updateView() + end + ) + toggle.appendChild(document.createTextNode($vec_str)) + visToggles.push(toggle); + controlPanel.appendChild(toggle); + end + end + + # update view + @js viewer.win updateView() +end + +function opentools!(viewer::ConstructionViewer) + size(viewer.win, 1240, 830) + opentools(viewer.win) +end + +function closetools!(viewer::ConstructionViewer) + closetools(viewer.win) + size(viewer.win, 620, 830) +end + +end + +# ~~~ sandbox setup ~~~ + +# in the default view, e4 + e5 is the point at infinity +elements = sqrt(0.5) * BigFloat[ + 1 1 -1 -1 0; + 1 -1 1 -1 0; + 1 -1 -1 1 0; + 0 0 0 0 -sqrt(6); + 1 1 1 1 2 +] + +# show construction +viewer = Viewer.ConstructionViewer() +Viewer.display!(viewer, elements) \ No newline at end of file diff --git a/engine-proto/ganja-test/ganja-test.html b/engine-proto/ganja-test/ganja-test.html new file mode 100644 index 0000000..d6efc90 --- /dev/null +++ b/engine-proto/ganja-test/ganja-test.html @@ -0,0 +1,76 @@ + + +
+ + + + + + + + diff --git a/engine-proto/ganja-test/ganja-test.jl b/engine-proto/ganja-test/ganja-test.jl new file mode 100644 index 0000000..6c55061 --- /dev/null +++ b/engine-proto/ganja-test/ganja-test.jl @@ -0,0 +1,127 @@ +using Blink +using Colors + +# === utilities === + +append_to_head!(w, type, content) = @js w begin + @var element = document.createElement($type) + element.appendChild(document.createTextNode($content)) + document.head.appendChild(element) +end + +style!(w, stylesheet) = append_to_head!(w, "style", stylesheet) + +script!(w, code) = append_to_head!(w, "script", code) + +function add_element!(vec) + # add element + full_vec = [0; vec; fill(0, 26)] + n = @js win elements.push(@new CGA3($full_vec)) + + # generate palette. this is Gadfly's `default_discrete_colors` palette, + # available under the MIT license + palette = distinguishable_colors( + n, + [LCHab(70, 60, 240)], + transform = c -> deuteranopic(c, 0.5), + lchoices = Float64[65, 70, 75, 80], + cchoices = Float64[0, 50, 60, 70], + hchoices = range(0, stop=330, length=24) + ) + palette_packed = [RGB24(c).color for c in palette] + @js win palette = $palette_packed +end + +# === build page === + +# create window and open developer console +win = Window() +opentools(win) + +# set stylesheet +style!(win, """ + body { + background-color: #ffe0f0; + } + + /* needed to keep Ganja canvas from blowing up */ + canvas { + min-width: 600px; + max-width: 600px; + min-height: 600px; + max-height: 600px; + } +""") + +# load Ganja.js +loadjs!(win, "https://unpkg.com/ganja.js") + +# create global functions and variables +script!(win, """ + // create algebra + var CGA3 = Algebra(4, 1); + + // initialize element list and palette + var elements = []; + var palette = []; + + // declare visualization handle + var graph; + + // create scene function + function scene() { + commands = []; + for (let n = 0; n < elements.length; ++n) { + commands.push(palette[n], elements[n]); + } + return commands; + } + + function flip() { + let last = elements.length - 1; + for (let n = 0; n < last; ++n) { + // reflect + elements[n] = CGA3.Mul(CGA3.Mul(elements[last], elements[n]), elements[last]); + + // de-noise + for (let k = 6; k < elements[n].length; ++k) { + elements[n][k] = 0; + } + } + requestAnimationFrame(graph.update.bind(graph, scene)); + } +""") + +# set up controls +body!(win, """ + +""", async = false) + +# === set up visualization === + +# list elements. in the default view, e4 + e5 is the point at infinity +elements = sqrt(0.5) * BigFloat[ + 1 1 -1 -1 0; + 1 -1 1 -1 0; + 1 -1 -1 1 0; + 0 0 0 0 -sqrt(6); + 1 1 1 1 2 +] + +# load elements +for vec in eachcol(elements) + add_element!(vec) +end + +# initialize visualization +@js win begin + graph = CGA3.graph( + scene, + Dict( + "conformal" => true, + "gl" => true, + "grid" => true + ) + ) + document.body.appendChild(graph) +end \ No newline at end of file diff --git a/engine-proto/gram-test/descent-test.jl b/engine-proto/gram-test/descent-test.jl index 9b6fb7a..2f20143 100644 --- a/engine-proto/gram-test/descent-test.jl +++ b/engine-proto/gram-test/descent-test.jl @@ -10,10 +10,10 @@ using PolynomialRoots # the difference between the matrices `target` and `attempt`, projected onto the # subspace of matrices whose entries vanish at each empty index of `target` function proj_diff(target, attempt) - I, J, values = findnz(target) + J, K, values = findnz(target) result = zeros(size(target)...) - for (i, j, val) in zip(I, J, values) - result[i, j] = val - attempt[i, j] + for (j, k, val) in zip(J, K, values) + result[j, k] = val - attempt[j, k] end result end @@ -21,24 +21,24 @@ end # === example === # the Lorentz form -Q = diagm([-1, 1, 1, 1, 1]) +Q = diagm([1, 1, 1, 1, -1]) # initialize the partial gram matrix for an arrangement of seven spheres in # which spheres 1 through 5 are mutually tangent, and spheres 3 through 7 are # also mutually tangent -I = Int64[] J = Int64[] +K = Int64[] values = BigFloat[] -for i in 1:7 - for j in 1:7 - if (i <= 5 && j <= 5) || (i >= 3 && j >= 3) - push!(I, i) +for j in 1:7 + for k in 1:7 + if (j <= 5 && k <= 5) || (j >= 3 && k >= 3) push!(J, j) - push!(values, i == j ? 1 : -1) + push!(K, k) + push!(values, j == k ? 1 : -1) end end end -gram = sparse(I, J, values) +gram = sparse(J, K, values) # set the independent variable # @@ -54,11 +54,11 @@ gram[1, 6] = gram[6, 1] # in this initial guess, the mutual tangency condition is satisfied for spheres # 1 through 5 guess = sqrt(0.5) * BigFloat[ - 1 1 1 1 2 0.2 0.1; - 0 0 0 0 -sqrt(6) 0.3 -0.2; 1 1 -1 -1 0 -0.1 0.3; 1 -1 1 -1 0 -0.5 0.4; - 1 -1 -1 1 0 0.1 -0.2 + 1 -1 -1 1 0 0.1 -0.2; + 0 0 0 0 -sqrt(6) 0.3 -0.2; + 1 1 1 1 2 0.2 0.1; ] # search parameters @@ -108,11 +108,11 @@ println("\nLoss: ", loss, "\n") # === algebraic check === -R, gens = polynomial_ring(Generic.Rationals{BigInt}(), ["x", "t₁", "t₂", "t₃"]) +R, gens = polynomial_ring(AbstractAlgebra.Rationals{BigInt}(), ["x", "t₁", "t₂", "t₃"]) x = gens[1] t = gens[2:4] -S, u = polynomial_ring(Generic.Rationals{BigInt}(), "u") +S, u = polynomial_ring(AbstractAlgebra.Rationals{BigInt}(), "u") M = matrix_space(R, 7, 7) gram_symb = M(R[ diff --git a/engine-proto/gram-test/gram-test.jl b/engine-proto/gram-test/gram-test.jl index 4b2f859..0e88ff4 100644 --- a/engine-proto/gram-test/gram-test.jl +++ b/engine-proto/gram-test/gram-test.jl @@ -11,7 +11,7 @@ function printbad(msg) println(" ", msg) end -F, gens = rational_function_field(Generic.Rationals{BigInt}(), ["a₁", "a₂", "b₁", "b₂", "c₁", "c₂"]) +F, gens = rational_function_field(AbstractAlgebra.Rationals{BigInt}(), ["a₁", "a₂", "b₁", "b₂", "c₁", "c₂"]) a = gens[1:2] b = gens[3:4] c = gens[5:6] diff --git a/engine-proto/gram-test/overlap-test.jl b/engine-proto/gram-test/overlap-test.jl index beeaeca..e75531a 100644 --- a/engine-proto/gram-test/overlap-test.jl +++ b/engine-proto/gram-test/overlap-test.jl @@ -11,7 +11,7 @@ function printbad(msg) println(" ", msg) end -F, gens = rational_function_field(Generic.Rationals{BigInt}(), ["x", "t₁", "t₂", "t₃"]) +F, gens = rational_function_field(AbstractAlgebra.Rationals{BigInt}(), ["x", "t₁", "t₂", "t₃"]) x = gens[1] t = gens[2:4]