Created
June 30, 2017 23:38
-
-
Save Orbots/504025e4f1510d7a7b00f7af4a79a2ab to your computer and use it in GitHub Desktop.
Graph Laplacian on Constraints.ipynb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "metadata": { | |
| "collapsed": false, | |
| "trusted": true | |
| }, | |
| "cell_type": "code", | |
| "source": "#Pkg.add(\"StaticArrays\")\n#Pkg.add(\"DualNumbers\")\n#Pkg.add(\"Roots\")\n#Pkg.update()\n#Pkg.add(\"Iterators\")\nusing DualNumbers\nusing StaticArrays\nusing Roots\nusing Base.Test\nusing Base.LinAlg\nusing Iterators\n\nimport Base.norm\n\nPoint{T} = SVector{3,T}\nPoint64 = Point{Float64} \n\nstruct Triangle{T}\n pa::Point{T} \n pb::Point{T} \n pc::Point{T} \n n::Point{T}\nend \n\nTriangle{T}(pa::Point{T}, pb::Point{T}, pc::Point{T}) = \n Triangle(pa, pb, pc, normalize(cross(pb-pa, pc-pa))) \n\nstack{T}(P::Vector{Point{T}}) = reduce(vcat, map(Array,P))\nstack{T}(P::Array{T,2}) = vec(P')\nunstack{T}(onecol::Vector{T}, ncol::Int64 = 3) = reshape(onecol,ncol,Int64(length(onecol)/ncol))'\nvectorize{T}(vflat::Vector{T}) = map(Point{T},partition(vflat,3))\n\n", | |
| "execution_count": 1, | |
| "outputs": [ | |
| { | |
| "execution_count": 1, | |
| "output_type": "execute_result", | |
| "data": { | |
| "text/plain": "vectorize (generic function with 1 method)" | |
| }, | |
| "metadata": {} | |
| } | |
| ] | |
| }, | |
| { | |
| "metadata": { | |
| "collapsed": false, | |
| "trusted": true | |
| }, | |
| "cell_type": "code", | |
| "source": "abstract type Constraint end\nimport Base.indices\n\nisactive{T}(c::Constraint, p::Vector{Point{T}}) = true\n\nfromindices{CT<:Constraint,D}(c::CT, p::Vector{D}) = map(j->p[j], indices(c))\n\nC{CT<:Constraint,D}(c::CT, p::Vector{Point{D}}) = C(c, fromindices(c,p)...)\n\nstruct DistanceConstraint{T,F} <: Constraint\n indices::T\n d::F\nend\n\nindices{T,F}( dc::DistanceConstraint{T,F} ) = dc.indices\n\nfunction C{T,F,D}( c::DistanceConstraint{T,F}, p₁::Point{D}, p₂::Point{D} )\n norm(p₂-p₁) - c.d\nend\n\n@test C(DistanceConstraint([1,2],0.5), [Point([-1.0,-1.0,0.0]),Point([1.0,1.0,0.0])]...) == (sqrt(8) - 0.5)", | |
| "execution_count": 2, | |
| "outputs": [ | |
| { | |
| "execution_count": 2, | |
| "output_type": "execute_result", | |
| "data": { | |
| "text/plain": "\u001b[1m\u001b[32mTest Passed\n\u001b[39m\u001b[22m" | |
| }, | |
| "metadata": {} | |
| } | |
| ] | |
| }, | |
| { | |
| "metadata": { | |
| "collapsed": false, | |
| "trusted": true | |
| }, | |
| "cell_type": "code", | |
| "source": "function norm{F,T}(x::SVector{T,DualNumbers.Dual{F}})\n sqrt(dot(x,x) + eps(F))\nend\n\nfunction dual_vector{T}(v::Array{T,1}, del_index::Integer) \n [ dual(v[i], i==del_index ? one(T) : zero(T)) for i in 1:length(v) ]\nend\n\nfunction dual_vector_0ϵ{T}(v::Array{T,1}) \n [ dual(v[i], zero(T)) for i in 1:length(v) ]\nend\n\nfunction dual_vector{T}(v::SVector{3,T}, del_index::Integer) \n @SVector [ dual(v[i], i==del_index ? one(T) : zero(T)) for i in 1:3 ]\nend\n\nfunction dual_vector_0ϵ{T}(v::SVector{3,T}) \n @SVector [ dual(v[i], zero(T)) for i in 1:3 ]\nend\n\n@test (Point64([1,1,1]) |> v->dual_vector(v,2) |> v->v⋅v |> epsilon ) == 2.0\n\nfunction autogradient{T<:Real,CT<:Constraint}(c::CT, p::Vector{Point{T}})::Vector{Point{T}}\n const inds = indices(c)\n\n n = length(inds)\n const ∂p = [ dual_vector_0ϵ(pⱼ) for pⱼ in map(j->p[j], inds) ]\n ∇Pᵢ = map(inds) do i \n pᵢ = p[i]\n ∂pᵢ₁ = dual_vector(pᵢ,1)\n ∂pᵢ₂ = dual_vector(pᵢ,2)\n ∂pᵢ₃ = dual_vector(pᵢ,3)\n\n ∇Cpᵢ₁ = C(c, map( j->(inds[j] == i) ? ∂pᵢ₁ : ∂p[j], 1:n )...)\n ∇Cpᵢ₂ = C(c, map( j->(inds[j] == i) ? ∂pᵢ₂ : ∂p[j], 1:n )...)\n ∇Cpᵢ₃ = C(c, map( j->(inds[j] == i) ? ∂pᵢ₃ : ∂p[j], 1:n )...)\n\n [epsilon(∇Cpᵢ₁), epsilon(∇Cpᵢ₂), epsilon(∇Cpᵢ₃)]\n end\n \n ∇P = zeros(Point{T},length(p))\n for i in 1:length(inds)\n ∇P[inds[i]] += ∇Pᵢ[i]\n end\n ∇P\nend\n\ngradient{T<:Real,CT<:Constraint}(c::CT, p::Vector{Point{T}}) = autogradient(c,p)\n\n\"\"\"\nsolve constraints with gauss-siedel\n\"\"\"\nfunction solveλ{T<:Real,TC<:Constraint,TI<:Integer}(\n constraints::Vector{TC}, points::Vector{Point{T}}, tolerance::T = 1e-6, maxiter::TI = 100)\n activec = filter(c->isactive(c,points),constraints)\n converged = isempty(activec)\n niter = 0\n # println(\"start solve\")\n while !converged && maxiter > niter \n niter += 1\n for c in activec\n Cᵢ = C(c, points)\n ∇Cᵢ = gradient(c, points)\n \n λ = -Cᵢ/(∇Cᵢ⋅∇Cᵢ)\n points += λ*∇Cᵢ\n end\n \n activec = filter(c->isactive(c,points),constraints)\n converged = mapreduce(c->abs(C(c, points)), +, zero(T), activec) < tolerance\n converged = converged || isempty(activec)\n end\n # println(\"end solve\")\n \n #points\n (points, niter, #==mapreduce(c->abs(C(c, points)), +, zero(T), constraints),==# map(c->isactive(c,points),constraints))\nend", | |
| "execution_count": 3, | |
| "outputs": [ | |
| { | |
| "execution_count": 3, | |
| "output_type": "execute_result", | |
| "data": { | |
| "text/plain": "solveλ" | |
| }, | |
| "metadata": {} | |
| } | |
| ] | |
| }, | |
| { | |
| "metadata": { | |
| "collapsed": false, | |
| "trusted": true | |
| }, | |
| "cell_type": "code", | |
| "source": "function COM{T<:Real, TC<:Constraint}( constraint::TC, p::Vector{Point{T}}, m::Vector{T} )\n pᵢ = [fromindices(constraint, p)...]\n mᵢ = [fromindices(constraint, m)...]\n sum(diagm(mᵢ)*pᵢ)*one(T)/length(pᵢ)\nend\n\nCOM{T<:Real, TC<:Constraint}( constraint::TC, p::Vector{Point{T}} ) = COM(constraint, p, ones(T,length(p)))\n\nfunction PtoCOM{T<:Real, TC<:Constraint}( constraint::TC, p::Vector{Point{T}}, m::Vector{T} )\n pᵢ = fromindices(constraint, p)\n pₒ = COM(constraint, p, m)\n map(pⱼ->pⱼ-pₒ, pᵢ)\nend", | |
| "execution_count": 4, | |
| "outputs": [ | |
| { | |
| "execution_count": 4, | |
| "output_type": "execute_result", | |
| "data": { | |
| "text/plain": "PtoCOM (generic function with 1 method)" | |
| }, | |
| "metadata": {} | |
| } | |
| ] | |
| }, | |
| { | |
| "metadata": { | |
| "collapsed": false, | |
| "trusted": true | |
| }, | |
| "cell_type": "code", | |
| "source": "function laplacian{T<:Real,TC<:Constraint,TI<:Integer}( constraints::Vector{TC}, weights::Vector{T}, nP::TI )\n nC = length(constraints)\n A = zeros(nP,nP)\n D = zeros(nP)\n for i in 1:nC\n Cᵢ = constraints[i]\n Vᵢ = indices(Cᵢ)\n nᵢ = length(Vᵢ)\n aᵢ = 1.0/length(Vᵢ)\n for j in Vᵢ\n D[j] += aᵢ\n A[i,j] = aᵢ\n A[j,i] = aᵢ\n end\n end\n A = A-diagm(diag(A))\n diagm(D) - A\nend\n\n# calculate a rhs for solving constrained system using graph laplacian on P's connected by constraints\nfunction laplacian_rhs{TC<:Constraint, F}( constraints::Vector{TC}, P::Vector{Point{F}} )\n # the rhs should be the result of Δf(P) when all constraints are satisfied. i.e. C(P) == 0\n # so we need a function that fits this description\n #\n # Δ is the divergence of the gradient of a function. \n # From Wikipedia: the Laplacian Δf(p) of a function f at a point p, up to a constant depending on the dimension, is the rate at which the average value of f over spheres centered at p deviates from f(p) as the radius of the sphere grows.\n # let's try to parse that:\n # define spf(f,p,r) as average of a function f over a sphere centered at p with radius r. Δf(p) = ∂spf/∂r\n #\n # so the key is to define a function f(p) and specify what the result will be when operated on by the laplacian\n # we can then solve for f(p) \n # and finally f⁻¹(p) to recover p if f(p) isn't enough to do what we need, but we need f⁻¹(p) for that...\n #\n # gradient means something a bit different in the context of graph laplacian\n # the gradient part of graph laplacian is saying how a node ( vertex ) varies as any neighbour changes\n # so it's -1 if there is a connection, 0 otherwise, and an accumulation on diagonal to balance nieghbours\n # we will call this the graph gradient\n # \n # the gradient of our constraint function is part of the function we want to apply the graph laplacian operator to\n # the function we want to balance is \n \n # sum up C(P)*∇C(P) around each vertex. this is the divergence of the graph gradient at a point\n # Δ(C(P')*∇C(P')) = ∑C(P)*∇C(P)\n #\n #\n # \nend\n\nfunction laplacian_rhs{TC<:Constraint, F}( constraints::Vector{TC}, P::Vector{Point{F}} )\n b = zeros(eltype(P),length(P))\n for cᵢ in constraints\n Pᵢ = solveλ([cᵢ], P)[1]\n inds = indices(cᵢ)\n pᵢ = map(j->Pᵢ[j], inds)\n pₒ = COM(cᵢ, P)\n pᵢ = map(pⱼ->pⱼ-pₒ,pᵢ)\n for j in 1:length(inds)\n b[inds[j]] += pᵢ[j]\n end\n end\n \n b\nend\n\nrmcol(A,i) = [A[:,1:i-1] A[:,i+1:end]]\n\n\"\"\"\nif we prefactor, will need to store the columns we remove from Q\n\"\"\"\nfunction add_locked_boundary_LS{F}( Q::Array{F,2}, B::Vector{Point{F}}, P::Vector{Point{F}}, locked::Vector{Bool} )\n for i in length(locked):-1:1\n if locked[i] == true\n B -= map(Qᵢ->Qᵢ*P[i],Q[:,i])\n B[i] = P[i]\n Q = rmcol(Q,i)\n end\n end\n \n (Q,B)\nend\n\n#laplacian([DistanceConstraint([1,2],0.5),DistanceConstraint([2,3],0.5)], [1.0,1.0,1.0], 3)\n@test laplacian([DistanceConstraint([1,2],0.5),DistanceConstraint([2,3],0.5)], [1.0,1.0,1.0], 3) == [1.0 -1.0 0.0; -1.0 2.0 -1.0; 0.0 -1.0 1.0 ]*0.5", | |
| "execution_count": 13, | |
| "outputs": [ | |
| { | |
| "execution_count": 13, | |
| "output_type": "execute_result", | |
| "data": { | |
| "text/plain": "\u001b[1m\u001b[32mTest Passed\n\u001b[39m\u001b[22m" | |
| }, | |
| "metadata": {} | |
| } | |
| ] | |
| }, | |
| { | |
| "metadata": { | |
| "collapsed": false, | |
| "trusted": true | |
| }, | |
| "cell_type": "code", | |
| "source": "function solve_laplacian(Q,B)\n N = size(Q)[1]\n lasub = Q[1:(N-1),1:(N-1)]\n Fsub = cholfact(lasub);\n B3 = B |> stack |> unstack\n px = zeros(B3)\n for i = 1:3\n b = B3[1:end,i:i]\n b = b - mean(b)\n bs = b[1:(N-1)]\n xs = Fsub \\ bs;\n x = [xs;0]\n x = x - mean(x)\n px[1:end,i:i] = x\n end\n vectorize(stack(px))\nend\n\n\"\"\"\nsolve system using laplacian in a least sqaures fashion\n\"\"\"\n\nfunction solve_laplacian_LS(Q,B,P,locked)\n F = cholfact(Q'*Q);\n B3 = B |> stack |> unstack\n B3 = Q'*B3\n px = zeros(B3)\n for i = 1:3\n b = B3[1:end,i:i]\n b = b - mean(b)\n x = F \\ b;\n x = x - mean(x)\n px[1:end,i:i] = x\n end\n PX = vectorize(stack(px))\n iPX = 1\n Pfull = P\n for iP in 1:length(P)\n if locked[iP] == false\n Pfull[iP] = PX[iPX]\n iPX += 1\n end\n end\n Pfull\nend\n\nP = [Point([-1.0,-1.0,10.0]),Point([1.0,1.0,10.0]), Point([-2.0,2.0,10.0])]\nc = [DistanceConstraint([1,2],1.0),DistanceConstraint([2,3],1.1)]\nQ = laplacian(c, [1.0,1.0,1.0], length(P))\nfor i in 1:1\nb = laplacian_rhs(c, P)\nP = solve_laplacian(Q, b)\nend\nP\nnorm(P[1]-P[2]),norm(P[2]-P[3])\n\nnP = 6\nPr = [ Point64([rand(2);0]) for i in 1:nP]\nP = Pr\ncr = [ DistanceConstraint([i,i+1],0.05) for i in 1:nP-1]\nQr = laplacian(cr, ones(Float64,length(Pr)), length(Pr))\nbr = laplacian_rhs(cr, P)\nPf = copy(Pr)\nlocked = map(i->false, 1:nP)\nlocked[3] = true\n locked[nP-2] = true\n Pf[3] -= Point64([2.0,0,0])\n Pf[nP-2] += Point64([2.0,0.0,0])\nfor i in 1:1\n # P[2] += Point64([1.05,0,0])\n # for j in 1:40\nbr = laplacian_rhs(cr, P)\nPr = solve_laplacian(Qr, br)\n\nPfree = solve_laplacian_LS(Qr,br)\nQf,bf = add_locked_boundary_LS( Qr, br, Pf, locked )\nPf = solve_laplacian_LS(Qf,bf,Pf,locked)\n\n # end\n\nend\nP\n", | |
| "execution_count": 27, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stderr", | |
| "text": "\u001b[1m\u001b[33mWARNING: \u001b[39m\u001b[22m\u001b[33mreplacing docs for 'solve_laplacian_LS :: NTuple{4,Any}' in module 'Main'.\u001b[39m\n" | |
| }, | |
| { | |
| "execution_count": 27, | |
| "output_type": "execute_result", | |
| "data": { | |
| "text/plain": "6-element Array{SVector{3,Float64},1}:\n [0.824103, 0.530046, 0.0] \n [0.314122, 0.830278, 0.0] \n [0.886657, 0.0876211, 0.0]\n [0.724969, 0.751158, 0.0] \n [0.31056, 0.170568, 0.0] \n [0.927234, 0.641359, 0.0] " | |
| }, | |
| "metadata": {} | |
| } | |
| ] | |
| }, | |
| { | |
| "metadata": { | |
| "collapsed": false, | |
| "trusted": true | |
| }, | |
| "cell_type": "code", | |
| "source": "nP = 100\nP = [ Point64([rand(2);0]) for i in 1:nP]\nc = [ DistanceConstraint([i,i+1],0.05) for i in 1:nP-1]\nQ = laplacian(c, ones(Float64,length(P)), length(P))\n\nPf = copy(P)\nlocked = map(i->false, 1:nP)\nlocked[3] = true\nlocked[nP-3] = true\nPf[3] = Point64([-2.0,0,0])\nPf[nP-3] = Point64([2.0,0.0,0])\n\nfor i in 1:1\n b = laplacian_rhs(c, Pf)\n Qf,bf = add_locked_boundary_LS( Q, b, Pf, locked )\n Pf = solve_laplacian_LS(Qf,bf,Pf,locked)\nend\n", | |
| "execution_count": 48, | |
| "outputs": [] | |
| }, | |
| { | |
| "metadata": { | |
| "collapsed": false, | |
| "trusted": true | |
| }, | |
| "cell_type": "code", | |
| "source": "#Pkg.add(\"Plots\")\n#Pkg.add(\"PlotlyJS\")\nusing Plots\nplotlyjs()\nPxy = Pf |> stack |> unstack |> pxyz->pxyz[1:end,1:2]\nplot(Pxy[1:end,1:1],Pxy[1:end,2:2],marker=[:circle :d],xlim=(-3,3),ylim=(-3,3),leg=false)\n#Pxy = Pr |> stack |> unstack |> pxyz->pxyz[1:end,1:2]\n#plot(Pxy[1:end,1:1],Pxy[1:end,2:2],marker=[:hex :d],color=:green)", | |
| "execution_count": 49, | |
| "outputs": [ | |
| { | |
| "execution_count": 49, | |
| "output_type": "execute_result", | |
| "data": { | |
| "text/html": "<div id=\"23f114ce-d367-4c23-984c-ecf358c8decb\" class=\"plotly-graph-div\"></div>\n\n<script>\n window.PLOTLYENV=window.PLOTLYENV || {};\n window.PLOTLYENV.BASE_URL=\"https://plot.ly\";\n require(['plotly'], function(Plotly) {\n Plotly.newPlot('23f114ce-d367-4c23-984c-ecf358c8decb', [{\"xaxis\":\"x\",\"colorbar\":{\"title\":\"\"},\"yaxis\":\"y\",\"x\":[-45.03172073375972,-45.25529367032343,-2.0,-38.40541283805439,-31.361545255108382,-24.491217569089066,-17.884369643343373,-11.499901674702443,-5.366781507034325,0.5663569658976897,6.220841211086473,11.655841062799766,16.84966477701341,21.739565477713896,26.3998223714038,30.85856906610522,35.01772470119296,38.90353692809106,42.60648747046643,45.955976480962136,49.13544080500323,51.98895788140413,54.62338931896457,57.01344179950607,59.085749899014985,60.98592755881104,62.55341681198077,63.94227293093974,65.01747170640428,65.85325125749395,66.50753997801922,66.8218608602533,66.99521299261184,66.85873930155654,66.53722039157583,65.97787199753246,65.13903737652481,64.07714992489716,62.90137246156952,61.421101658433614,59.83607631748758,57.98334620240486,55.91303353269299,53.74998352267353,51.32664169805673,48.764046656902025,46.03306954247276,43.21481943079121,40.15376596219461,37.023343120039655,33.79283116477798,30.346346809275715,26.789686749980575,23.19947999637033,19.449527780711463,15.686774209727503,11.876339198937579,7.916471243193051,3.991364753321619,0.007480879140118191,-4.050617612928519,-8.094848186040153,-12.079523119761337,-16.150026296665356,-20.10372478645727,-24.092436999458666,-28.01683604278577,-31.829112015923002,-35.62386236778796,-39.24347311267214,-42.8433901143496,-46.23887180176662,-49.584837219860354,-52.713770083129276,-55.651316674252826,-58.45949492549883,-61.011374511731205,-63.32493087104312,-65.48290979107695,-67.38725265069002,-69.00850674388067,-70.26461030722817,-71.29052539198084,-71.90864201007354,-72.27887160592157,-72.26382600272139,-71.7836284436915,-70.99583240975093,-69.69667560492924,-67.98386193385987,-65.85622353241789,-63.142682985022304,-60.01022539769675,-56.332995999889754,-52.03859707547499,-47.203322139092435,2.0,-43.62556003810559,-44.82477682303322,-45.477025676316515],\"showlegend\":true,\"mode\":\"lines+markers\",\"name\":\"y1\",\"marker\":{\"symbol\":\"circle\",\"color\":\"rgba(0, 154, 250, 1.000)\",\"line\":{\"color\":\"rgba(0, 0, 0, 1.000)\",\"width\":1},\"size\":8},\"line\":{\"color\":\"rgba(0, 154, 250, 1.000)\",\"width\":1,\"dash\":\"solid\",\"shape\":\"linear\"},\"y\":[210.41064633278336,209.37441029380767,0.0,203.91192345814486,199.66716541545014,194.46019260773423,188.2910877950648,181.41059920469584,173.68663362849202,165.37333206243127,156.35003481233076,146.86644396443694,136.78930068324775,126.28750575446169,115.48198241969575,104.26551384419739,92.85922424682953,81.13936806846701,69.27188341789383,57.287888396655774,45.26951618482329,33.230867792467535,21.116406452881364,9.152058786371612,-2.7259642285803523,-14.519840090272425,-26.079426149686867,-37.493335976160694,-48.67424448135745,-59.48184767173697,-70.01417025514021,-80.22408930562179,-90.04213680622362,-99.51104373601962,-108.46550665804429,-117.06334772036215,-125.16064304826702,-132.74153495001602,-139.8169778193201,-146.36741397831676,-152.35365090496086,-157.72935661824343,-162.5807631728243,-166.80519290354735,-170.4832873506463,-173.4769103056524,-175.85544426968116,-177.67244140636168,-178.85369409016064,-179.44308554899735,-179.3380659556399,-178.60634683013026,-177.24314065085636,-175.31133188246108,-172.70969322720165,-169.53997785193965,-165.68613214272816,-161.2698333589752,-156.22143927953104,-150.68317295818795,-144.50148171218106,-137.85574576263602,-130.63409314464874,-122.88473878556047,-114.68294103914693,-105.94812215568837,-96.8558352645866,-87.25562281564984,-77.33890928430102,-67.01810381215122,-56.325955976735514,-45.3300125891534,-34.100783388015174,-22.6647524558403,-10.939247562354979,0.8745624942000063,12.903190670591414,24.966910476272773,37.05806925317029,49.22608201139005,61.27740610357327,73.27465211801436,85.19074896506595,96.89468183614012,108.35585811532276,119.57244741848199,130.39803227252264,140.84170939684964,150.80059586025277,160.33566515919128,169.24949629766542,177.5506881494448,185.11810867674257,191.91262532189114,197.8860167202583,203.05500628490967,0.0,210.28942100950334,212.30535196102704,213.28951713665273],\"type\":\"scatter\"}],\n {\"showlegend\":false,\"xaxis\":{\"tickvals\":[-3.0,-2.0,-1.0,0.0,1.0,2.0,3.0],\"ticks\":\"inside\",\"range\":[-3.0,3.0],\"domain\":[0.03619130941965587,0.9934383202099738],\"tickmode\":\"array\",\"linecolor\":\"rgba(0, 0, 0, 1.000)\",\"showgrid\":true,\"title\":\"\",\"tickangle\":0,\"titlefont\":{\"color\":\"rgba(0, 0, 0, 1.000)\",\"family\":\"sans-serif\",\"size\":15},\"tickcolor\":\"rgba(0, 0, 0, 1.000)\",\"ticktext\":[\"-3\",\"-2\",\"-1\",\"0\",\"1\",\"2\",\"3\"],\"zeroline\":false,\"type\":\"-\",\"tickfont\":{\"color\":\"rgba(0, 0, 0, 1.000)\",\"family\":\"sans-serif\",\"size\":11},\"anchor\":\"y\"},\"paper_bgcolor\":\"rgba(255, 255, 255, 1.000)\",\"annotations\":[],\"height\":400,\"margin\":{\"l\":0,\"b\":20,\"r\":0,\"t\":20},\"plot_bgcolor\":\"rgba(255, 255, 255, 1.000)\",\"yaxis\":{\"tickvals\":[-3.0,-2.0,-1.0,0.0,1.0,2.0,3.0],\"ticks\":\"inside\",\"range\":[-3.0,3.0],\"domain\":[0.03762029746281716,0.9901574803149606],\"tickmode\":\"array\",\"linecolor\":\"rgba(0, 0, 0, 1.000)\",\"showgrid\":true,\"title\":\"\",\"tickangle\":0,\"titlefont\":{\"color\":\"rgba(0, 0, 0, 1.000)\",\"family\":\"sans-serif\",\"size\":15},\"tickcolor\":\"rgba(0, 0, 0, 1.000)\",\"ticktext\":[\"-3\",\"-2\",\"-1\",\"0\",\"1\",\"2\",\"3\"],\"zeroline\":false,\"type\":\"-\",\"tickfont\":{\"color\":\"rgba(0, 0, 0, 1.000)\",\"family\":\"sans-serif\",\"size\":11},\"anchor\":\"x\"},\"width\":600}, {showLink: false});\n\n });\n </script>\n" | |
| }, | |
| "metadata": {} | |
| } | |
| ] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "name": "julia-0.6", | |
| "display_name": "Julia 0.6.0-rc2", | |
| "language": "julia" | |
| }, | |
| "language_info": { | |
| "mimetype": "application/julia", | |
| "file_extension": ".jl", | |
| "version": "0.6.0", | |
| "name": "julia" | |
| }, | |
| "gist": { | |
| "id": "", | |
| "data": { | |
| "description": "Graph Laplacian on Constraints.ipynb", | |
| "public": true | |
| } | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 2 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment