Skip to content

Instantly share code, notes, and snippets.

@Orbots
Created June 30, 2017 23:38
Show Gist options
  • Select an option

  • Save Orbots/504025e4f1510d7a7b00f7af4a79a2ab to your computer and use it in GitHub Desktop.

Select an option

Save Orbots/504025e4f1510d7a7b00f7af4a79a2ab to your computer and use it in GitHub Desktop.
Graph Laplacian on Constraints.ipynb
Display the source blob
Display the rendered blob
Raw
{
"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