One Hat Cyber Team
Your IP :
216.73.216.135
Server IP :
194.44.31.54
Server :
Linux zen.imath.kiev.ua 4.18.0-553.77.1.el8_10.x86_64 #1 SMP Fri Oct 3 14:30:23 UTC 2025 x86_64
Server Software :
Apache/2.4.37 (Rocky Linux) OpenSSL/1.1.1k
PHP Version :
5.6.40
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
share
/
Macaulay2
/
View File Name :
AlgebraicSplines.m2
-- Copyright 2014-2015: Mike Dipasquale -- You may redistribute this file under the terms of the GNU General Public -- License as published by the Free Software Foundation, either version 2 -- of the License, or any later version. ------------------------------------------ ------------------------------------------ -- Header ------------------------------------------ ------------------------------------------ newPackage( "AlgebraicSplines", Version => "0.1.0", Date => "27. May 2015", Authors => { {Name => "Michael DiPasquale", Email => "mdipasq@okstate.edu", HomePage => "http://math.okstate.edu/people/mdipasq/"}, {Name => "Gwyn Whieldon", Email => "whieldon@hood.edu", HomePage => "http://cs.hood.edu/~whieldon"}, {Name => "Eliana Duarte", Email => "emduart2@illinois.edu", HomePage => "https://faculty.math.illinois.edu/~emduart2/"}, {Name => "Daniel Irving Bernstein", Email=> "dibernst@ncsu.edu", HomePage =>"http://www4.ncsu.edu/~dibernst"} }, Headline => "splines on simplicial complexes, polytopal complexes, and graphs", Keywords => {"Applied Algebraic Geometry"}, Configuration => {}, DebuggingMode => false, PackageImports => { "OldChainComplexes", "Elimination" }, PackageExports => { "FourierMotzkin" } ) export { "BaseRing", "splineMatrix", "splineModule", "InputType", "RingType", "ByFacets", "ByLinearForms", "Homogenize", "VariableName", "GenVar", "IdempotentVar", "Trim", "VariableGens", "splineDimensionTable", "postulationNumber", "hilbertComparisonTable", "generalizedSplines", "ringStructure", "formsList", "cellularComplex", "idealsComplex", "splineComplex", "courantFunctions", "stanleyReisner", "stanleyReisnerPresentation" --Remove after testing --"getCodim1Intersections", --"simpBoundary", --"facetsN", --"boundaryComplex", --"polyBoundary", --"prune1", --"pruneR", --"expressInGens" } ------------------------------------------ ------------------------------------------ -- Data Types and Constructors ------------------------------------------ ------------------------------------------ --may include the following data types in a future iteration --Create an object that gives ALL splines --on a given subdivision. --Splines = new Type of HashTable --splines = method(Options => { -- symbol InputType => "ByFacets", -- symbol Homogenize => true, -- symbol VariableName => getSymbol "t", -- symbol CoefficientRing => QQ, -- symbol BaseRing => null}) --splines(List,List,List,ZZ) := Matrix => opts -> (V,F,E,r) -> ( -- AD := splineMatrix(V,F,E,r,opts); -- K := ker AD; -- b := #F; -- new Splines from { -- symbol cache => new CacheTable from {"name" => "Unnamed Spline"}, -- symbol VertexCoordinates => V, -- symbol Regions => F, -- symbol SplineModule => image (gens K)^(toList(0..b-1)) -- } --) --net Splines := S -> S.SplineModule ------------------------------------------ ------------------------------------------ -- Methods ------------------------------------------ ------------------------------------------ ------------------------------------------ subsetL=method() ------------------------------------------ --Containment function for lists-- subsetL(List,List):=Boolean=>(L1,L2)->( all(L1,f->member(f,L2)) ) ------------------------------------------ ------------------------------------------ getCodim1Intersections = method(Options=>{ symbol InputType => "Polyhedral" } ) ------------------------------------------ ------------------------------------------ --Inputs: ------------------------------------------ --F = list of facets of a polytopal --or a simplicial complex ------------------------------------------ --Outputs: ----------------------------------------- --E = largest (under containment) intersections --of facets. If input is hereditary, this is --the list of interior codim 1 intersections ----------------------------------------- getCodim1Intersections(List) := List => opts -> F ->( n := #F; if opts.InputType==="Polyhedral" then( --For each pair of facets, take their intersection: intersectFacets := unique flatten apply(#F-1, i-> apply(toList(i+1..#F-1), j-> sort select(F_i, v-> member(v,F_j)))); --Remove any non-maximal faces in this intersections: codim1int:=select(intersectFacets, f -> ( (number(intersectFacets, g-> all(f, j-> member(j,g)))) === 1 )) ) else if opts.InputType==="Simplicial" then( d := #(F_0); --For each non-final facet, construct all codimension 1 subsets. codim1faces := apply(n-1, i -> subsets(F_i,d-1)); --Check if a codimension 1 subset is contained in another facet, --store it as a codim 1 intersection. codim1int=sort flatten apply(#codim1faces, i -> select(codim1faces_i, s -> any(F_{i+1..n-1}, f-> subsetL(s,f)))); ); codim1int ) ------------------------------------------ ------------------------------------------ getCodimDFacesSimplicial = method() ------------------------------------------ ------------------------------------------ --Inputs: ------------------------------------------ --F = list of facets of a simplicial complex --d = desired codimension ------------------------------------------ --Outputs: ----------------------------------------- --E = list of (all) codim d faces ----------------------------------------- getCodimDFacesSimplicial(List,ZZ) := List => (F,D) -> ( d := #first(F); unique flatten apply(F, f-> subsets(f,d-D)) ) ----------------------------------------- formsList=method(Options=>{ symbol InputType => "ByFacets", symbol Homogenize => true, symbol VariableName => getSymbol "t", symbol CoefficientRing => QQ, symbol BaseRing => null}) ---------------------------------------------------- --This method returns a list of forms corresponding to codimension one faces -------- --Input: --V= vertex list --E= codim 1 face list --r= smoothness parameter -------- --Output: --List of forms defining input list of codimension one faces --raised to (r+1) power ------------------------------------------------------------ formsList(List,List,ZZ):= List => opts->(V,E,r)->( --To homogenize, we append a 1 as the final coordinate of each vertex coord in list V. --If not homogenizing, still need 1s for computing equations d := #(first V); V = apply(V, v-> append(v,1)); if opts.BaseRing === null then ( S := createSplineRing(d,opts); ) else ( S = opts.BaseRing; ); if opts.Homogenize then ( varlist := vars S; ) else ( varlist = (vars S)|(matrix {{sub(1,S)}}); ); varCol := transpose varlist; M := (transpose(matrix(S,V))); mM := numrows M; minorList := apply(E, e-> gens gb minors(mM,matrix(M_e)|varCol)); if any(minorList, I-> ideal I === ideal 1) then ( error "Some vertices on entered face are not in codimension 1 face." ); flatten apply(minorList, m -> (m_(0,0))^(r+1)) ) createSplineRing = method(Options => { symbol InputType => "ByFacets", symbol Homogenize => true, symbol VariableName => getSymbol "t", symbol CoefficientRing => QQ, symbol BaseRing => null } ) createSplineRing(ZZ):= PolynomialRing => opts -> (d) -> ( t := opts.VariableName; if opts.BaseRing === null then ( if opts.Homogenize then ( S := (opts.CoefficientRing)[t_0..t_d]; ) else ( S = (opts.CoefficientRing)[t_1..t_d]; ); ) else ( S = opts.BaseRing ); S ) ----------------------------------------- ----------------------------------------- splineMatrix = method(Options => { symbol InputType => "ByFacets", symbol Homogenize => true, symbol VariableName => getSymbol "t", symbol CoefficientRing => QQ, symbol BaseRing => null}) ------------------------------------------ ------------------------------------------ ------------------------------------------ ------------------------------------------ -- splineMatrix "ByFacets" ------------------------------------------ --Inputs: ------------------------------------------ --("ByFacets") --L = {L_0,L_1,L_2} (i.e. {V,F,E}) --r = degree of desired continuity -- -- OR!!!! -- --("ByLinearForms") --L = {L_0,L_1} (i.e. {B,L}) --r = degree of desired continuity ------------------------------------------ --Outputs: -- BM = matrix with columns corresponding -- to facets and linear forms separating facets. ------------------------------------------ splineMatrix(List,ZZ) := Matrix => opts -> (L,r) -> ( --Use this if your list L = {V,F,E} contains --The inputs as a single list L. if opts.InputType === "ByFacets" then ( splineMatrix(L_0,L_1,L_2,r) ); if opts.InputType == "ByLinearForms" then ( splineMatrix(L_0,L_1,r,InputType=>"ByLinearForms") ) ) ------------------------------------------ ------------------------------------------ --Inputs: ------------------------------------------ --("ByFacets") --V = list of coordinates of vertices --F = ordered lists of facets --E = list of edges --r = degree of desired continuity ------------------------------------------ --Outputs: -- BM = matrix with columns corresponding -- to facets and linear forms separating facets. ------------------------------------------ splineMatrix(List,List,List,ZZ) := Matrix => opts -> (V,F,E,r) -> ( if opts.InputType === "ByFacets" then ( d := # (first V); --Compute which facets are adjacent to each edge: facetEdgeH := apply(#E, e-> positions(F, f-> all(E_e,v-> member(v,f)))); --Compute indices of interior edges, and replace edge list and --facet adjacencies to only include these interior edges: indx := positions(facetEdgeH, i-> #i === 2); E = E_indx; facetEdgeH = facetEdgeH_indx; --Compute top boundary map for complex: BM := matrix apply( facetEdgeH, i-> apply( #F, j-> if ( j === first i) then 1 else if ( j===last i) then -1 else 0)); --List of forms defining interior codim one faces (raised to (r+1) power) flist := formsList(V,E,r,opts); T := diagonalMatrix(flist); splineM := BM|T; ) else if opts.InputType === "ByLinearForms" then ( print "Wrong inputs, put in lists of adjacent facets and linear forms and continuity r." ); splineM ) ------------------------------------------ ------------------------------------------ --Inputs: ------------------------------------------ ------------------------------------------ -- ("ByFacets") --V = list of vertex coordinates --F = list of facets --r = degree of desired continuity -- -- OR!!!! -- --("ByLinearForms") --B = list of adjacent facets --L = list of ordered linear forms --defining codim 1 faces, ordered as in B --r = degree of desired continuity ------------------------------------------ --Outputs: -- BM = matrix with columns corresponding -- to facets and linear forms separating facets. ------------------------------------------ splineMatrix(List,List,ZZ) := Matrix => opts -> (V,F,r) ->( --Warn user if they are accidentally using ByFacets method with too few inputs. --This code assumes that the polytopal complex is hereditary. if opts.InputType === "ByFacets" then ( if issimplicial(V,F) then( E := getCodim1Intersections(F,InputType=>"Simplicial"); SM := splineMatrix(V,F,E,r,opts) ) else( E = getCodim1Intersections(F); SM = splineMatrix(V,F,E,r,opts) ); ); --If user DOES want to define complex by regions and dual graph. if opts.InputType === "ByLinearForms" then ( B := V; L := F; m := max flatten B; A := matrix apply(B, i-> apply(toList(0..m), j-> if (j=== first i) then 1 else if (j===last i) then -1 else 0)); D := matrix apply(#L, i-> apply(#L, j-> if i===j then L_i^(r+1) else 0)); SM = A|D; ); SM ) ------------------------------------------ ------------------------------------------ splineModule = method(Options => { symbol InputType => "ByFacets", symbol Homogenize => true, symbol VariableName => getSymbol "t", symbol CoefficientRing => QQ, symbol BaseRing => null} ) ------------------------------------------ ------------------------------------------ -- This method computes the splineModule -- of a complex Delta, given by either -- facets, codim 1 faces, and vertex coors, -- or by pairs of adjacent faces and -- linear forms. ------------------------------------------ --Inputs: ------------------------------------------ --V = list of vertices --F = list of facets --E = list of edges --r = desired continuity of splines ------------------------------------------ --Outputs: --Spline module S^r(Delta) ------------------------------------------ splineModule(List,List,List,ZZ) := Matrix => opts -> (V,F,E,r) -> ( AD := splineMatrix(V,F,E,r,opts); K := ker AD; b := #F; image submatrix(gens K, toList(0..b-1),) ) ------------------------------------------ --Inputs: ------------------------------------------ --V = list of vertices --F = list of facets --r = desired continuity of splines -- -- OR!!!! -- --V = list of pairs of adjacent faces --F = list of linear forms defining codim 1 faces. --r = desired continuity of splines ------------------------------------------ --Outputs: --Spline module S^r(Delta) ------------------------------------------ splineModule(List,List,ZZ) := Matrix => opts -> (V,F,r) -> ( AD := splineMatrix(V,F,r,opts); K := ker AD; b := #F; if opts.InputType==="ByLinearForms" then ( b = #(unique flatten V) ); image submatrix(gens K, toList(0..b-1),) ) ------------------------------------------ ------------------------------------------- ------------------------------------------- splineDimensionTable=method() ------------------------------------------- -----Inputs: ------------------------------------------- ----- a= lower bound of dim table ----- b= upper bound of dim table ----- M= module -------------------------------------------- ------ Outputs: -------------------------------------------- ------ A net with the degrees between a and b on top row ------ and corresponding dimensions of graded pieces ------ of M in bottom row ------------------------------------------- splineDimensionTable(ZZ,ZZ,Module):=Net=>(a,b,M)->( r1:=prepend("Degree",toList(a..b)); r2:=prepend("Dimension",apply(toList(a..b),i->hilbertFunction(i,M))); netList {r1,r2} ) ------------------------------------------- -----Inputs: ------------------------------------------- ----- a= lower bound of range ----- b= upper bound of range ----- L= list {V,F,E}, where V is a list of vertices, F a list of facets, E a list of codim 1 faces ----- r= degree of desired continuity ------------------------------------------- -----Outputs: ------------------------------------------- -------A table with the dimensions of the graded pieces ------ of the spline module in the range (a,b) ------------------------------------------- splineDimensionTable(ZZ,ZZ,List,ZZ):= Net=>(a,b,L,r)->( M := splineModule(L_0,L_1,L_2,r); splineDimensionTable(a,b,M) ) ------------------------------------------- -----Inputs: ------------------------------------------- ----- a= lower bound of range ----- b= upper bound of range ----- L= list {V,F}, where V is list of vertices, F a list of facets ------------- -----OR!! ------------------------------------------- ----- a= lower bound of range ----- b= upper bound of range ----- L= list {V,F}, where V is a list of adjacent facets, F a list of forms -----------defining codim 1 faces along which adjacent facets meet ------------------------------------------- -------Outputs: ------------------------------------------- -------A table with the dimensions of the graded pieces ------ of the spline module in the range (a,b) ------------------------------------------- splineDimensionTable(ZZ,ZZ,List,ZZ):= Net => (a,b,L,r)->( M := splineModule(L_0,L_1,r); splineDimensionTable(a,b,M) ) ------------------------------------------- ------------------------------------------- postulationNumber=method() ------------------------------------------- -----Inputs: ------------------------------------------- ----- M, a graded module -------------------------------------------- ------ Outputs: -------------------------------------------- ------ The postulation number (largest integer ------ for which Hilbert function and polynomial ------ of M disagree). -------------------------------------------- postulationNumber(Module):= (N) ->( k := regularity N; h := hilbertPolynomial(N); while hilbertFunction(k,N)==h(k) do (k=k-1); k ) ------------------------------------------ ----------------------------------------- hilbertComparisonTable=method() ------------------------------------------- -----Inputs: ------------------------------------------- ----- a= an integer, lower bound ----- b= an integer, upper bound ----- M= graded module over a polynomial ring -------------------------------------------- ------ Outputs: -------------------------------------------- ------ A table whose top two rows are the same as ------ the output of splineDimensionTable and whose ------ third row compares the first two to the ------ Hilbert Polynomial -------------------------------------------- hilbertComparisonTable(ZZ,ZZ,Module):= (a,b,M) ->( h := hilbertPolynomial(M); r1 := prepend("Degree",toList(a..b)); r2 := prepend("Dimension",apply(toList(a..b),i->hilbertFunction(i,M))); r3 := prepend("HilbertPoly",apply(toList(a..b),i->h(i))); netList {r1,r2,r3} ) --------------------------------------------- ---------------------------------------------- courantFunctions=method(Options => { symbol InputType => "ByFacets", symbol Homogenize => true, symbol VariableName => getSymbol "t", symbol CoefficientRing => QQ, symbol BaseRing => null}) ----------------------------------------------- --Inputs: ---V: List of vertices (of a simplicial complex) ---F: List of facets --Outputs: ---CF: #F\times #V matrix of Courant functions which are ---1 at a chosen vertex and 0 elsewhere ------------------------------------------------ courantFunctions(List,List) := Matrix => opts -> (V,F) -> ( if not issimplicial(V,F) then( error "Input must be simplicial." )else( --To homogenize, we append a 1 as the final coordinate of each vertex coord in list V. --If not homogenizing, still need 1s for computing equations d := #(first V); Vh := apply(V, v-> append(v,1)); if opts.BaseRing === null then ( S := createSplineRing(d,opts); ) else ( S = opts.BaseRing; ); if opts.Homogenize then ( varlist := vars S; int := set {} ) else ( varlist = (vars S)|(matrix {{1_S}}); int = set(F_0); scan(toList(1..length(F)-1),i->( int = set(F_i)*int )) ); varCol := transpose varlist; M := transpose(matrix(S,Vh)); matrix table(length F,toList(0..(length V)-1)-int,(i,j)->( if member(j,F_i) then( lk := (F_i)-set({j}); Num := det(M_lk|varCol); Den := sub(det(M_lk|M_{j}),QQ); Num/Den )else( 0 ))) )) ------------------------------------------ generalizedSplines = method(Options=>{ symbol RingType => "Ambient" } ) ------------------------------------------ ------------------------------------------ -- This method computes the generalized spline module -- associated to a graph whose edges are labeled by ideals. ------------------------------------------ --Inputs: ------------------------------------------ --E = list of edges. Each edge is a list with two vertices. --OR --G=graph object --ideals = list of ideals that label the edges. Ideals must --be entered in same order as corresponding edges in E, or if --a graph G is entered, in the same order as the edges are listed --in edges(G). The default order for edges(G) is lexicographic. --If a list of ring elements is entered, it is assumed these are --generators for principal ideals. --If RingType is an integer,n, then this can be a list --of integers that label the edges. ------------------------------------------------- --if RingType is an integer, n, then the ring is defined --internally as ZZ/n. --If RingType is "Ambient", an ambient ring must already --be defined so that ideals can be entered. ------------------------------------------ --Outputs: ------------------------------------------ --Module of generalized splines on the graph given by the edgelist. ------------------------------------------ generalizedSplines(List,List) := Module => opts -> (E,ideals) ->( if opts.RingType === "Ambient" then( S := ring first ideals; --make sure ideals all lie in same ambient ring-- ideals = apply(ideals, I->sub(I,S)); --make sure ideals list consists of ideals. If ring elements are --entered will automatically make these ideals. ideals = apply(ideals, I->(if class(I)===S then(ideal I)else(I))) ) else if toString(class(opts.RingType))==="ZZ" then( m := opts.RingType; R := ZZ[{}]; S = R/ideal(m_R); ideals = apply(ideals,i-> ideal(i_S)); ); vert := sort unique flatten E; n := #vert; T := directSum(apply(ideals,I->coker gens I)); --Boundary Map from Edges to vertices (this encodes spline conditions) M := matrix apply(E, e->apply(vert, v->if(v===first e) then 1 else if(v===last e) then -1 else 0)); ker(map(T,S^n,sub(M,S))) ) --generalizedSplines(Graph,List) := Module => opts -> (G,ideals) ->( --E:=apply(edges G,e->elements e); --generalizedSplines(E,ideals,opts) --) -------------------------------------- ringStructure = method(Options=>{ symbol GenVar => getSymbol "Y", symbol IdempotentVar => getSymbol "e", symbol Trim => false, symbol VariableGens => true } ) -------------------------------------- --Input: A submodule, M, of the ring S^k (ring structure of direct sum), -----which is known to have the structure of a sub-ring of S^k --Output: A map whose image is M as a sub-ring of S^k and whose source -----is a polynomial ring in as many variables as there are generators -----of M as a sub-ring of S^k. -------------------------------------- ringStructure(Module) := RingMap => opts -> M ->( S := M.ring; ng := rank (ambient M); if opts.VariableGens then ( --diagonal embedding of polynomial ring-- ident := matrix apply(ng,i->{1_S}); --remove identity (if it exists) as a generator of M-- pos := select(numcols gens M,i->(flatten entries((gens M)_{i}))!=(flatten entries ident)); --add variables under diagonal embedding to generators of M-- newM :=((ident)*(vars S))|((gens M)_(pos)); )else( newM = (gens M) ); dg := (degrees(newM))_1; --build direct sum-- K := if (S===ZZ) then (ZZ) else coefficientRing(S); e := opts.IdempotentVar; T := K[e_0..e_(ng-1)]; --ideal of idempotent relations-- PR := apply(subsets(ng,2),L->(T_(first L)*T_(last L))); SR := apply(ng,i->T_i^2-T_i); Rel := ideal( join(PR,SR) ); DS :=(T/Rel)**S; --turn module generators into ring generators mat := (sub(vars T,DS))*(sub(newM,DS)); Y := opts.GenVar; Am := K[Y_0..Y_(numcols(newM)-1),Degrees=>dg]; phi := map(DS,Am,flatten entries mat); if opts.Trim then( phi = pruneR(phi) ); phi ) ---------------------------------------------- prune1=method() --------------------------------------------- --Input: a ring map whose source is a polynomial ring and the kernel of that map --Output: a ring map whose source is a sub-ring of the same polynomial ring, ---with one extraneous generator removed --------------------------------------------- prune1(RingMap,Ideal):=RingMap=> (phi,Kr) ->( H :=source phi; G :=gens H; extGen := select(1,G,var->(any(Kr_*,g->member(var,flatten entries monomials g)))); --dg := apply(G,var->degree(var)); --H1:= K[reverse(G),Degrees=>reverse(dg),MonomialOrder=>Lex]; --I := sub(Kr,H1); --extGen := select(1,gens H,var->( -- nv := sub(var,H1); -- (nv%I)!=nv -- )); K :=coefficientRing(H); T := target phi; I2 :=eliminate(Kr,extGen); G2 :=G-set(extGen); d2 :=apply(G2,g->degree(g)); H2 :=K[G2,Degrees=>d2]; phi2 := map(T,H2,apply(G2,g->phi(sub(g,H)))); K2 := sub(I2,H2); (phi2,K2) ) -------------------------------------------------------- pruneR=method() -------------------------------------------------------- --Input: a ring map whose source is a polynomial ring --Output: a ring map whose source is a sub-ring of the same polynomial ring, ---with all extraneous generators removed --------------------------------------------- pruneR(RingMap):=RingMap=> phi ->( G := gens (source phi); Kr := ker phi; (phi2,Kr2) := prune1(phi,Kr); G2 := gens(source phi2); while #G2<#G do( phi = phi2; G = G2; Kr = Kr2; (phi2,Kr2) = prune1(phi,Kr); G2 = gens(source phi2) ); phi2 ) ----------------------------------------------------------- stanleyReisner=method(Options=>{ symbol InputType => "ByFacets", symbol Homogenize => true, symbol VariableName => getSymbol "t", symbol CoefficientRing => QQ, symbol BaseRing => null} ) ----------------------------------------------------------- --Input: V, list of vertices and F, list of facets --Output: A ring map phi whose image is the ring of continuous piecewise polynomials on (V,F). If --(V,F) is simplicial, the basis of Courant functions is chosen, so ker phi --is the stanleyReisner ideal of (F) ----------------------------------------------------------- stanleyReisner(List,List):=Ring=>opts->(V,F)->( if issimplicial(V,F) then( CF := courantFunctions(V,F,opts); phi := ringStructure(image CF,VariableGens=>false,GenVar => getSymbol "X") )else( C0 := splineModule(V,F,0,opts); phi = ringStructure(C0,Trim=>true,GenVar => getSymbol "X") ); phi ) ----------------------------------------------------------- expressInGens=method(Options=>{ symbol GenVar => getSymbol "Z"} ) ----------------------------------------------------------- --Input: ring map phi, matrix representing element of free module R^k ----which is contained in the image of phi --Output: expression for phi^{-1}(f) ----------------------------------------------------------- expressInGens(RingMap,Matrix):= RingElement => opts -> (phi,f) -> ( ng := rank (ambient image f); H := source phi; dg := flatten apply(gens H,var->degree(var)); T := target phi; K := coefficientRing(H); Z := opts.GenVar; nH := K[prepend(Z,gens H),Degrees=>join((degrees f)_1_0,dg),MonomialOrder=>Lex]; nG := drop(gens nH,1); img := apply(nG,var->phi(sub(var,H))); vList := matrix {apply(ng,i->T_i)}; nf := matrix apply(flatten entries f,p->{sub(p,T)}); I := ker map(T,nH,prepend((vList*nf)_(0,0),img)); sub((nH_0)%I,H) ) ----------------------------------------------------------- stanleyReisnerPresentation=method(Options=>{ symbol GenVar => getSymbol "Y", symbol IdempotentVar => getSymbol "e", symbol Trim => false, symbol VariableGens => true, symbol InputType => "ByFacets", symbol Homogenize => true, symbol VariableName => getSymbol "t", symbol CoefficientRing => QQ, symbol BaseRing => null} ) ----------------------------------------------------------- --Input: V, list of vertices, F, list of facets, r, smoothness --Output: Presentation of ring C^r(\Delta) as sub-ring of ---Stanley Reisner ring of \Delta ----------------------------------------------------------- stanleyReisnerPresentation(List,List,ZZ):=Matrix=>opts->(V,F,r)->( d := #(first V); S := createSplineRing(d,BaseRing=>opts.BaseRing,InputType=>opts.InputType,Homogenize=>opts.Homogenize,VariableName=>opts.VariableName,CoefficientRing=>opts.CoefficientRing); CR := splineModule(V,F,r,BaseRing=>S,InputType=>opts.InputType,Homogenize=>opts.Homogenize,VariableName=>opts.VariableName,CoefficientRing=>opts.CoefficientRing); ng := rank(ambient CR); ident := matrix apply(ng,i->{1_S}); GCR := apply(numcols gens CR,i->(gens CR)_{i}); --take away identity module generator GCR = select(GCR,f->(f!=ident)); --add variables under diagonal embedding to ring generators of M-- GCR = join(apply(gens S,v->(ident)*matrix{{v}}),GCR); dg := apply(GCR,f->(degrees f)_1_0_0); --create Stanley Reisner ring phi := stanleyReisner(V,F,BaseRing=>S,InputType=>opts.InputType,Homogenize=>opts.Homogenize,VariableName=>opts.VariableName,CoefficientRing=>opts.CoefficientRing); T := source phi; I := ker phi; Y := opts.GenVar; K := coefficientRing(S); H := K[apply(length GCR,i->Y_i),Degrees=>dg]; MP := apply(GCR,f->sub(expressInGens(phi,f),T)); phiN := map(T/I,H,MP); if opts.Trim then( phiN = pruneR(phiN) ); phiN ) ------------------------------------------ simpBoundary = method() ------------------------------------------ --Input: --F = list of codim i faces --E = list of codim i+1 faces ------------------------------------------ --Output: --B = boundary map matrix between codim i and codim i+1 faces ------------------------------------------ --Example: --F = {{0,1,2},{0,1,3},{1,3,4},{1,2,4},{2,4,5},{0,2,5},{0,3,5}} --E = {{0,1},{1,2},{0,2},{3,0},{1,3},{1,4},{2,4},{2,5},{0,5},{3,4},{4,5}} --V = {{0},{1},{2},{4}} ------------------------------------------ simpBoundary(List,List) := Matrix => (F,E) -> ( F = apply(F, f-> sort f); E = apply(E, e-> sort e); if #F==0 then return( map(image matrix{{0}},image matrix{{0}},matrix{{0}}) )else( if #E==0 then return( map(image matrix{{0}},ZZ^(length F),matrix{apply(length F,i->0)}) )else( tempLF := {}; rowList := {}; apply(F, f-> ( tempLF = hashTable apply(#f, v-> position(E,e-> e == drop(f,{v,v})) => (-1)^v); rowList = append(rowList,apply(#E, j->if member(j,keys tempLF) then tempLF#j else 0)); ) ); return transpose matrix rowList ))) ------------------------------------------ orient = method() ------------------------------------------ --Input: --I = the ideal generated by forms vanishing --on codim one faces containing a face P ------------------------------------------ --Output: --L = list of length dim P, smallest variables --(w.r.t. standard lex order) --which are dependent on the affine span of P ------------------------------------------ orient(Ideal):=List=> I->( LT:= leadTerm I; reverse sort flatten apply(LT_*,f-> support f) ) ------------------------------------------ polyBoundaryPair=method() ------------------------------------------ ----This method is for use when there are precomputed ----lists of ideals and orientations ------------------------------------------ --Input: --V = vertices of complex --L1 = {G,IG,OG} --L2 = {H,IH,OH} --G = codim (i+1) face (list of indices of vertices) --IG = ideal of G --OG = orientation of G --H = codim i face (list of indices of vertices) --IH = ideal of H --OH = orientation of H ------------------------------------------ --Output: --O = +1,-1, or 0, encoding compatibility --of orientations between G and H ------------------------------------------ polyBoundaryPair(List,List,List):=ZZ=>(V,L2,L1)->( G:=L1_0; H:=L2_0; --if G is not a face of H then return 0 -- if not subsetL(G,H) then ( ort:=0) else( --get ambient ring-- S:=ring (L1_1); --make sure ideals and variables sit inside same ambient ring-- IG:=sub(L1_1,S); OG:=apply(L1_2,var->sub(var,S)); IH:=sub(L2_1,S); OH:=apply(L2_2,var->sub(var,S)); --get a vertex of H that is not a vertex of G-- --if homogenized, append 1 if (numcols vars S)==(#(V_0)+1) then( testVindex :=select(1,H,v->not member(v,G)); testV := transpose matrix({append(flatten V_testVindex,1)}) --else, don't append 1-- ) else ( testVindex = select(1,H,v->not member(v,G)); testV = transpose matrix(V_testVindex) ); --get a generator of IG that is not a generator of IH-- outVect :=first select(1,flatten entries gens IG,f->(f%IH!=0)); --get row vector whose entries are coefficients of outVect matV :=transpose jacobian ideal outVect; --modify outVect so vector corresponding to outVect points --outward from H if sub(((matV*testV)_(0,0)),ZZ)<0 then(outVect=-outVect); --reduce outVect modulo IH-- outVect =(outVect%IH); --Get independent variables on the affine span of H and G-- indH :=select(flatten entries vars S,v->not member(v,OH)); indG :=select(flatten entries vars S,v-> not member(v,OG)); --There is one independent variable on H that is dependent on G. --Reduce it mod IG-- pos :=position(indH,v->not member(v,indG)); redHG :=(indH_pos)%IG; --Get coefficients of contraction of outVect with indH-- inCont :=matrix{apply(length indH,i->( (-1)^i*coefficient(indH_i,outVect) ))}; --Get list of coefficients for pulling back inCont to G-- conv :=matrix{apply(length indH,i->( omit := drop(indH,{i,i}); if member(indH_pos,omit) then( posN := position(omit,v->(v==(indH_pos))); pmvar := position(indG,v->(v==(indH_i))); missvar :=indG_pmvar; coef :=(-1)^posN*coefficient(missvar,redHG)*(-1)^pmvar ) else (coef=1); coef))}; sgn :=(inCont*(transpose conv))_(0,0); if (sgn>0) then(ort=1) else (ort=-1); ); ort ) ------------------------------------------ polyBoundary=method() ------------------------------------------ ----This method is for use when there are precomputed ----lists of ideals and orientations ------------------------------------------ --Input: --V = vertices of complex --L1 = {G,IG,OG} --L2 = {H,IH,OH} --G = codim (i+1) faces (list of indices of vertices) --IG = ideals of G --OG = orientations of G --H = codim i faces (list of indices of vertices) --IH = ideals of H --OH = orientations of H ------------------------------------------ --Output: --O = +1,-1, or 0, encoding compatibility --of orientations between G and H ------------------------------------------ polyBoundary(List,List,List):=Matrix=>(V,L2,L1)->( G := L1_0; H := L2_0; if #H==0 then( return map(image matrix{{0}},image matrix{{0}},matrix{{0}}); )else( if #G==0 then( return map(image matrix{{0}},ZZ^(#H),matrix {apply(#H,i->0)}); )else( IG:=L1_1; OG:=L1_2; IH:=L2_1; OH:=L2_2; return matrix table(#G,#H,(i,j)->( L1n :={G_i,IG_i,OG_i}; L2n :={H_j,IH_j,OH_j}; polyBoundaryPair(V,L2n,L1n) )); ))) ------------------------------------------ boundaryComplex = method() ------------------------------------------ --Input: --F= list of facets of a simplicial complex ----which is a pseudomanifold (Important!) ------------------------------------------ --Output: --A list of codim one faces on the boundary ------------------------------------------ boundaryComplex(List) := List => F -> ( n := #F; d := #(F_0); codim1faces := unique flatten apply(n,i-> subsets(F_i,d-1)); select(codim1faces, f-> number(F, g-> all(f, v-> member(v,g))) === 1) ) ------------------------------------------ --Input: --V= vertex list --F= list of facets of a complex (polyhedral or simplicial) ------------------------------------------------ --Output: --A list of codim one faces on the boundary ------------------------------------------------ boundaryComplex(List,List):= List => (V,F)-> ( candidateList := flatten apply(F,f->facetsN(V,f)); select(candidateList, f->#(positions(candidateList,l->l==f))==1) ) facetsN = method() ------------------------------------------------ --Input: --V=vertex list --(Optional) F=list of indices of V to take for convex hull ------------------------------------------------ --Output: List of facets of convex hull of V_F ------------------------------------------------ facetsN(List,List):= List => (V,L)->( V = apply(V_L,v->prepend(1,v)); --get minimal list of inequalities defining the conical hull of V H := fourierMotzkin transpose matrix V; halfspaces := H#0; --apply inequalities to vertex list to see which vertices are contained in faces M := (transpose halfspaces)*(transpose matrix V); facetList := apply(numrows M, i->select(numcols M,j-> M_(i,j)==0)); --label facet indices by elements of the list L apply(facetList,l->L_l) ) facetsN(List):= List => V ->( n := #V; F := toList(0..n-1); facetsN(V,F) ) ------------------------------------------------ cellularComplex = method( Options =>{ symbol InputType => "Polyhedral", symbol Homogenize => true, symbol VariableName => getSymbol "t", symbol CoefficientRing => QQ, symbol BaseRing => null } ) ------------------------------------------------ ---This method computes the cellular chain complex of a simplicial or ---polyhedral complex with coefficients in a polynomial ---ring, modulo the boundary ------------------------------------------------ ---Inputs (if simplicial): A list of facets ------------------------------------------------ ---Outputs: The cellular chain complex whose homology --- is the homology of the simplicial complex relative --- to its boundary. -------------------------------------------------- cellularComplex(List) := ChainComplex => opts -> (F) -> ( if opts.InputType === "Polyhedral" then ( print "Need a List of Vertices"; chain := null; ); if opts.InputType === "Simplicial" then ( d := (# first F)-1; S := createSplineRing(d,opts); boundaryF := boundaryComplex(F); C := apply(d+1, i-> getCodimDFacesSimplicial(F,i)); boundaryC := join({{}},apply(d, i-> getCodimDFacesSimplicial(boundaryF,i))); intC := apply(#C, i -> select(C_i, f -> not member(f,boundaryC_i))); chain = chainComplex(reverse apply(#intC-1, c-> sub(simpBoundary(intC_c,intC_(c+1)),S))) ); chain ) ------------------------------------------------ ---Inputs: -- V= list of vertices -- F= list of facets ------------------------------------------------ ---Outputs: The cellular chain complex whose homology --- is the homology of the simplicial or polyhedral complex relative --- to its boundary. --To verify working correctly, try the following input. --Cube and Octahedron-- --V={{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}, {-2, -2, -2}, {-2, 2, -2}, {2, 2, -2}, {2, -2, -2}, {-2, -2, 2}, {-2, 2, 2}, {2, 2, 2}, {2, -2, 2}}; --F={{0, 1, 2, 3, 4, 5}, {0, 8, 9, 12, 13}, {1, 6, 7, 10, 11}, {2, 7, 8, 11, 12}, {3, 6, 9, 10, 13}, {4, 10, 11, 12, 13}, {5, 6, 7, 8, 9}, {0, 2, 8, 12}, {0, 3, 9, 13}, {0, 4, 12, 13}, {0, 5, 8, 9}, {1, 2, 7, 11}, {1, 3, 6, 10}, {1, 4, 10, 11}, {1, 5, 6, 7}, {2, 4, 11, 12}, {3, 4, 10, 13}, {3, 5, 6, 9}, {2, 5, 7, 8}, {0, 2, 4, 12}, {0, 2, 5, 8}, {0, 3, 4, 13}, {0, 3, 5, 9}, {1, 2, 4, 11}, {1, 2, 5, 7}, {1, 3, 4, 10}, {1, 3, 5, 6}}; -------------------------------------------------- --With this input, output should be an acyclic complex except for HH_3 -------------------------------------------------- cellularComplex(List,List) := ChainComplex => opts -> (V,F) -> ( d := (# first V); S := createSplineRing(d,opts); if issimplicial(V,F) then ( boundaryF := boundaryComplex(F); C := apply(d+1, i-> getCodimDFacesSimplicial(F,i)); boundaryC := join({{}},apply(d, i-> getCodimDFacesSimplicial(boundaryF,i))); intC := apply(#C, i -> select(C_i, f -> not member(f,boundaryC_i))); chain := chainComplex(reverse apply(#intC-1, c-> sub(simpBoundary(intC_c,intC_(c+1)),S ))) ) else ( bComp := boundaryComplex(V,F); --Construct list whose ith element is interior intersections of codim i-- current :=F; intC ={current}; scan(d,i->( current=select(getCodim1Intersections(current),f->(not any(bComp,F->subsetL(f,F)))); intC =append(intC,current) )); --get the forms defining codimension 1 faces-- fList :=formsList(V,intC_1,0, Homogenize => opts.Homogenize, VariableName => opts.VariableName, CoefficientRing => opts.CoefficientRing, BaseRing => S); --create a list whose ith element is ideals of codim i faces-- idList :={apply(F,f->ideal(0_S)),apply(fList,f->ideal f)}; scan(d-1,i->( idList=append(idList,apply(intC_(i+2),G->( ind:=codim1Cont(intC_1,G); sub(ideal fList_ind,S) ))) )); --set orientations of all faces (lexicographically lowest dependent --variables on each face) orList := apply(idList, L->apply(L,I->orient I)); --set up the chain complex chain = chainComplex(reverse apply(#intC-1, c-> ( L1 := {intC_(c+1),idList_(c+1),orList_(c+1)}; L2 := {intC_c,idList_c,orList_c}; sub(polyBoundary(V,L2,L1),S) ))) ); chain ) ------------------------------------------ idealsComplex=method(Options=>{ symbol Homogenize => true, symbol VariableName => getSymbol "t", symbol CoefficientRing => QQ, symbol BaseRing => null } ) ------------------------------------------ --This function computes the Schenck-Stillman chain complex --of ideals for a simplicial or polyhedral complex ------------------------------------------ --Inputs: --V: vertex list --F: facet list --r: desired order of smoothness ------------------------------------------ --Outputs: The Schenck-Stillman complex of ideals ------------------------------------------ idealsComplex(List,List,ZZ):=ChainComplex => opts -> (V,F,r)->( d := #(first V); S := createSplineRing(d,opts); if issimplicial(V,F) then ( --list of interior faces in order of increasing codimension-- boundaryF := boundaryComplex(F); C := apply(d+1, i-> getCodimDFacesSimplicial(F,i)); boundaryC := join({{}},apply(d, i-> getCodimDFacesSimplicial(boundaryF,i))); intC := apply(#C, i -> select(C_i, f -> not member(f,boundaryC_i))); --if there are no interior faces of large codimension, get rid of the empty lists --intC = select(intC,L->( (length L)>0)); --list of forms defining codim 1 interior faces intformslist :=formsList(V,intC_1,r, Homogenize => opts.Homogenize, VariableName => opts.VariableName, CoefficientRing => opts.CoefficientRing, BaseRing => S); --list of modules which will define chain complex-- fullmodulelist := apply(#intC,i->( if #(intC_i)==0 then( newMod := image matrix{{0_S}}; )else( newMod = directSum apply(intC_i,e->( CE := positions(intC_1,f->subsetL(e,f)); sub(module ideal (intformslist_CE),S) )); ); newMod )); --defining the chain complex CCSS :=chainComplex(reverse apply(#intC-1, c-> ( inducedMap(fullmodulelist_(c+1),fullmodulelist_c,sub(simpBoundary(intC_c,intC_(c+1)),S)) )) ) ) else ( bComp := boundaryComplex(V,F); --Construct list whose ith element is interior intersections of codim i-- current :=F; intC ={current}; scan(d,i->( current=select(getCodim1Intersections(current),f->(not any(bComp,F->subsetL(f,F)))); intC =append(intC,current) )); --if there are no intersections of larger codimension, get rid of the empty lists --intC = select(intC,L->((length L)>0)); --get the forms defining codimension 1 faces-- fList :=formsList(V,intC_1,0, Homogenize => opts.Homogenize, VariableName => opts.VariableName, CoefficientRing => opts.CoefficientRing, BaseRing => S); --create a list whose ith element is ideals of codim i faces-- idList :={apply(F,f->ideal(0_S)),apply(fList,f->ideal f)}; scan(#intC-2,i->( idList=append(idList,apply(intC_(i+2),G->( ind:=codim1Cont(intC_1,G); sub(ideal fList_ind,S) ))) )); --set orientations of all faces (lexicographically lowest dependent --variables on each face) orList := apply(idList, L->apply(L,I->orient I)); --set up list of forms to r+1 power-- intformslist =apply(fList,f->f^(r+1)); --list of modules which will define chain complex-- fullmodulelist = apply(#intC,i->( if #(intC_i)==0 then( newMod := image matrix{{0_S}}; )else( newMod = directSum apply(intC_i,e->( CE := positions(intC_1,f->subsetL(e,f)); sub(module ideal (intformslist_CE),S) )); ); newMod )); --set up the chain complex CCSS = chainComplex(reverse apply(#intC-1, c-> ( L1 := {intC_(c+1),idList_(c+1),orList_(c+1)}; L2 := {intC_c,idList_c,orList_c}; M := sub(polyBoundary(V,L2,L1),S); inducedMap(fullmodulelist_(c+1),fullmodulelist_c,M) ))) ); CCSS ) ------------------------------------------ splineComplex=method(Options=>{ symbol Homogenize => true, symbol VariableName => getSymbol "t", symbol CoefficientRing => QQ, symbol BaseRing => null } ) ------------------------------------------ --This function computes the Schenck-Stillman chain complex --of quotient rings for a simplicial or polyhedral complex, --called the spline complex ------------------------------------------ --Inputs: --V: vertex list --F: facet list --r: desired order of smoothness ------------------------------------------ --Outputs: The Schenck-Stillman spline complex ------------------------------------------ --To verify working correctly, try the following input. --Cube and Octahedron-- --V={{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}, {-2, -2, -2}, {-2, 2, -2}, {2, 2, -2}, {2, -2, -2}, {-2, -2, 2}, {-2, 2, 2}, {2, 2, 2}, {2, -2, 2}}; --F={{0, 1, 2, 3, 4, 5}, {0, 8, 9, 12, 13}, {1, 6, 7, 10, 11}, {2, 7, 8, 11, 12}, {3, 6, 9, 10, 13}, {4, 10, 11, 12, 13}, {5, 6, 7, 8, 9}, {0, 2, 8, 12}, {0, 3, 9, 13}, {0, 4, 12, 13}, {0, 5, 8, 9}, {1, 2, 7, 11}, {1, 3, 6, 10}, {1, 4, 10, 11}, {1, 5, 6, 7}, {2, 4, 11, 12}, {3, 4, 10, 13}, {3, 5, 6, 9}, {2, 5, 7, 8}, {0, 2, 4, 12}, {0, 2, 5, 8}, {0, 3, 4, 13}, {0, 3, 5, 9}, {1, 2, 4, 11}, {1, 2, 5, 7}, {1, 3, 4, 10}, {1, 3, 5, 6}}; --r=1 -------------------------------------------------- --With this input, minimal associated primes of HH_2 should be --ideals of every vertex in V along with ideals corresponding to (0:0:0:1),(0:0:1:0),(0:1:0:0) (there should be three ideals having t_0 as --a generator) -------------------------------------------------- splineComplex(List,List,ZZ):=ChainComplex => opts -> (V,F,r)->( d := #(first V); S := createSplineRing(d,opts); if issimplicial(V,F) then ( --list of interior faces in order of increasing codimension-- boundaryF := boundaryComplex(F); C := apply(d+1, i-> getCodimDFacesSimplicial(F,i)); boundaryC := join({{}},apply(d, i-> getCodimDFacesSimplicial(boundaryF,i))); intC := apply(#C, i -> select(C_i, f -> not member(f,boundaryC_i))); --if there are no interior faces of large codimension, get rid of the empty lists --intC = select(intC,L->( (length L)>0)); --list of forms defining codim 1 interior faces intformslist := formsList(V,intC_1,r, Homogenize => opts.Homogenize, VariableName => opts.VariableName, CoefficientRing => opts.CoefficientRing, BaseRing => S); --list of modules which will define chain complex-- fullmodulelist := {S^(#F)}; scan(#intC-1,i->( if #(intC_(i+1))==0 then( newMod := image matrix{{0_S}}; )else( newMod = directSum apply(intC_(i+1),e->( CE := codim1Cont(intC_1,e); return coker sub(gens ideal (intformslist_CE),S) )); ); fullmodulelist = append(fullmodulelist,newMod) )); --defining the chain complex CCSS :=chainComplex(reverse apply(#intC-1, c-> ( map(fullmodulelist_(c+1),fullmodulelist_c,sub(simpBoundary(intC_c,intC_(c+1)),S)) )) ); ) else ( bComp := boundaryComplex(V,F); --Construct list whose ith element is interior intersections of codim i-- current :=F; intC ={current}; scan(d,i->( current=select(getCodim1Intersections(current),f->(not any(bComp,F->subsetL(f,F)))); intC =append(intC,current) )); --if there are no intersections of larger codimension, get rid of the empty lists --intC = select(intC,L->((length L)>0)); --get the forms defining codimension 1 faces-- fList :=formsList(V,intC_1,0, Homogenize => opts.Homogenize, VariableName => opts.VariableName, CoefficientRing => opts.CoefficientRing, BaseRing => S); --create a list whose ith element is ideals of codim i faces-- idList :={apply(F,f->ideal(0_S)),apply(fList,f->ideal f)}; scan(#intC-2,i->( idList=append(idList,apply(intC_(i+2),G->( ind:=codim1Cont(intC_1,G); sub(ideal fList_ind,S) ))) )); --set orientations of all faces (lexicographically lowest dependent --variables on each face) orList := apply(idList, L->apply(L,I->orient I)); --set up list of forms to r+1 power-- intformslist =apply(fList,f->f^(r+1)); --list of modules which will define chain complex-- fullmodulelist = {S^(#F)}; scan(#intC-1,i->( if #(intC_(i+1))==0 then( newMod := image matrix{{0_S}}; )else( newMod = directSum apply(intC_(i+1),e->( CE := codim1Cont(intC_1,e); return coker sub(gens ideal (intformslist_CE),S) )); ); fullmodulelist = append(fullmodulelist,newMod) )); --set up the chain complex CCSS = chainComplex(reverse apply(#intC-1, c-> ( L1 := {intC_(c+1),idList_(c+1),orList_(c+1)}; L2 := {intC_c,idList_c,orList_c}; M := sub(polyBoundary(V,L2,L1),S); map(fullmodulelist_(c+1),fullmodulelist_c,M) ))) ); CCSS ) ------------------------------------------ --may be included in future iteration --splineComplexMap=method(Options=>{ -- symbol Homogenize => true, -- symbol VariableName => getSymbol "t", -- symbol CoefficientRing => QQ -- } -- ) ------------------------------------------ --Builds the three complexes idealsComplex, --cellularComplex, splineComplex, along with --chain maps between these complexes ------------------------------------------ --Inputs: --V: vertex list --F: facet list --r: desired order of smoothness ------------------------------------------ --Outputs: The three chain complexes with --maps between them ------------------------------------------ --splineComplexMap(List,List,ZZ):=List=>opts->(V,F,r)->( -- ) ------------------------------------------ codim1Cont=method() ------------------------------------------ ----Inputs: ----E = list of codim one intersections ----G = a face of the complex (V,F) ------------------------------------------ ----Output: Indices of E corresponding to ----- codim one faces containing G ----------------------------------------- codim1Cont(List,List):=List=> (E,G)->( --positions of codim one faces containing G positions(E,e->subsetL(G,e)) ) ------------------------------------------ issimplicial = method() ------------------------------------------ -- Assumes that the inputted complex is pure ------------------------------------------ --Inputs: -- V = vertex coordinates of Delta -- F = list of facets of Delta ------------------------------------------ --Outputs: --Boolean, if Delta is simplicial, --checking that each facet is a simplex --of the appropriate dimension. ------------------------------------------ issimplicial(List,List) := Boolean => (V,F) ->( n := #first(V); all(F,f->#f==(n+1)) ) ----------------------------------------- ------------------------------------------ ------------------------------------------ -- Documentation ------------------------------------------ ------------------------------------------ beginDocumentation() -- Front Page doc /// Key AlgebraicSplines Headline a package for working with splines on simplicial complexes, polytopal complexes, and graphs Description Text This package provides methods for computations with piecewise polynomial functions (splines) over polytopal complexes. Text Let $\Delta$ be a partition (simplicial,polytopal,cellular,rectilinear, etc.) of a space $\RR^n$. The spline module $S^{r}(\Delta)$ is the module of all functions $f$ continuously differentiable to order $r$ such that $f$ is a polynomial when restricted to each facet $\sigma\in\Delta$. The vector space $S^r_d(\Delta)$ consists of splines whose polynomial restrictions have degree at most $d$. Its dimension is of particular interest in approximation theory (see [10]). The foundations of the algebraic approach to splines (as it applies to numerical analysis) was developed by Billera and Rose in [1],[2],[3]. In particular, it is shown in [3] that dim$S^r_d(\Delta)=$dim$S^r(c\Delta)_d$, where $S^r(c\Delta)_d$ is the vector space of splines of degree exactly $d$ on the cone $c\Delta$ over $\Delta$. So the statistic dim$S^r_d(\Delta)$ is the Hilbert function of $S^r(c\Delta)$. The functions @TO splineMatrix@ and @TO splineModule@ construct the matrix from [3] whose kernel is $S^r(\Delta)$, and the module $S^r(\Delta)$, respectively. The functions @TO splineDimensionTable@ and @TO hilbertComparisonTable@ display the statistic dim$S^r_d(\Delta)$ and compare it to the long term dimension formula, respectively. In [1], Billera uses a homological approach to solve a conjecture of Strang on the dimension of the space $S^1_d(\Delta)$. The chain complex which he defines in [1] was later modified by Schenck and Stillman in [10]; we will call this the Billera-Schenck-Stillman chain complex. It has appeared in many papers due to its use in finding dim$S^r_d(\Delta)$; perhaps most notable is [11]. In [10] the chain complex is also used to compute dimension formulas in the polytopal setting. The Billera-Schenck-Stillman complex is implemented by the method @TO splineComplex@. The Billera-Schenck-Stillman chain complex is a quotient of the cellular chain complex of $\Delta$ (relative to the boundary of $\Delta$); the latter is computed by @TO cellularComplex@. The kernel of this surjection is given by @TO idealsComplex@. The functions mentioned thus far are concerned only with the structure of $S^r(\Delta)$ as a module over the polynomial ring. The method @TO ringStructure@ constructs $S^r(\Delta)$ as a quotient of a polynomial ring, thus recovering its ring structure. In [2], Billera shows that there is a natural isomorphism between the affine Stanley-Reisner ring $K_a[\Delta]$ (see explanation in documentation for @TO ringStructure@) of a simplicial complex and the ring $S^0(\Delta)$ of continuous piecewise polynomials on $\Delta$. The isomorphism identifies the variable corresponding to a vertex with the Courant function for that vertex. The method @TO courantFunctions@ computes these functions, and the method @TO stanleyReisner@ constructs the isomorphism identified in [2]. Moreover, the rings $S^r(\Delta)$ live inside $S^0(\Delta)$ - this is of particular interest when $\Delta$ is simplicial due to Billera's result. The method @TO stanleyReisnerPresentation@ constructs $S^r(\Delta)$ as a quotient of a ring map from a polynomial ring into $S^0(\Delta)$; in particular the generators of $S^r(\Delta)$ are presented in terms of generators of $S^0(\Delta)$. If $\Delta$ is simplicial these are selected to be the Courant functions. In topology, splines arise as equivariant cohomology of spaces with a torus action via GKM theory - see [14] for a survey of how this relates to splines in numerical analysis; and [6] for the precise relationship between continuous splines and the equivariant Chow cohomology of toric varieties. From this perspective, the notion of generalized splines on graphs was introduced in [5]. The method @TO generalizedSplines@ computes splines in this more flexible setting. The relationship to splines in numerical analysis is via the dual graph described by Rose in [7],[8]. Additionally, there are connections between splines and the module of multi-derivations of a hyperplane arrangement. A basic structural connection was noticed in [3]. For the braid arrangement and its sub-arrangements, the module of derivations is isomorphic to a ring of splines in a natural way (see [11] and [4]). Methods in this package borrow from code written by Hal Schenck. References:\break [1] Louis J. Billera. Homology of smooth splines: generic triangulations and a conjecture of Strang. Trans. Amer. Math. Soc., 310(1):325–340, 1988.\break [2] Louis J. Billera, The Algebra of Continuous Piecewise Polynomials, Adv. in Math. 76, 170-183 (1989).\break [3] Louis J. Billera and Lauren L. Rose. A dimension series for multivariate splines. Discrete Comput. Geom., 6(2):107–128, 1991.\break [4] Michael DiPasquale. Generalized Splines and Graphic Arrangements. J. Algebraic Combin. 45 (2017), no. 1, 171-189.\break [5] Simcha Gilbert, Julianna Tymoczko, and Shira Viel. Generalized splines on arbitrary graphs. Pacific J. Math. 281 (2016), no. 2, 333-364.\break [6] Sam Payne, Equivariant Chow cohomology of toric varieties, Math. Res. Lett. 13 (2006), 29-41.\break [7] Lauren Rose, Combinatorial and topological invariants of modules of piecewise polynomials, Adv. Math. 116 (1995), 34-45.\break [8] Lauren Rose, Graphs, syzygies, and multivariate splines, Discrete Comput. Geom. 32 (2004), 623-637.\break [9] T. McDonald, H. Schenck, Piecewise polynomials on polyhedral complexes, Adv. in Appl. Math. 42 (2009), 82-93.\break [10] Hal Schenck and Mike Stillman. Local cohomology of bivariate splines. J. Pure Appl. Algebra,117/118:535–548, 1997. Algorithms for algebra (Eindhoven, 1996).\break [11] Hal Schenck, A Spectral Sequence for Splines, Adv. in Appl. Math. 19, 183-199 (1997).\break [12] Schenck, Hal . Splines on the Alfeld split of a simplex and type A root systems. J. Approx. Theory 182 (2014), 1-6.\break [13] Gilbert Strang, Piecewise Polynomials and the Finite Element Method, Bull. Amer. Math. Soc. 79 (1973) 1128-1137.\break [14] Julianna Tymoczko. Splines in geometry and topology. Comput. Aided Geom. Design 45 (2016), 32-47. /// ------------------------------------------ -- Data type & constructor ------------------------------------------ -- Spline Matrix Constructor doc /// Key splineMatrix (splineMatrix,List,List,ZZ) (splineMatrix,List,List,List,ZZ) (splineMatrix,List,ZZ) InputType ByFacets ByLinearForms Homogenize BaseRing VariableName Headline compute matrix whose kernel is the module of $C^r$ splines on $\Delta$ Usage S = splineMatrix(V,F,E,r) S = splineMatrix(V,F,r) S = splineMatrix(L,r) S = splineMatrix(B,H,r) Inputs V:List list of coordinates of vertices of $\Delta$ F:List list of facets of $\Delta$ (each facet is recorded as a list of indices of vertices taken from V) E:List list of codimension one faces of $\Delta$ (interior or not); each codimension one face is recorded as a list of indices of vertices taken from V r:ZZ degree of desired continuity L:List list $\{V,F,E\}$ of vertices, facets, and codimension one faces of $\Delta$ H:List list of forms defining codimension one faces of $\Delta$ InputType=>String BaseRing=>Ring Homogenize=>Boolean CoefficientRing=>Ring VariableName=>Symbol Outputs S:Matrix resulting matrix whose kernel is the spline module Description Text This creates the basic spline matrix that has splines as its kernel. Example V = {{0,0},{1,0},{1,1},{-1,1},{-2,-1},{0,-1}};-- the coordinates of vertices F = {{0,2,1},{0,2,3},{0,3,4},{0,4,5},{0,1,5}}; -- a list of facets (pure complex) E = {{0,1},{0,2},{0,3},{0,4},{0,5}}; -- list of edges splineMatrix(V,F,E,1) Text If each codimension one face of $\Delta$ is the intersection of exactly two facets, then the list of edges is unnecessary. Example V = {{0,0},{1,0},{1,1},{-1,1},{-2,-1},{0,-1}};-- the coordinates of vertices F = {{0,2,1},{0,2,3},{0,3,4},{0,4,5},{0,1,5}}; -- a list of facets (pure complex) splineMatrix(V,F,1) Text Splines are automatically computed on the cone over the given complex $\Delta$, and the last variable of the polynomial ring is always the variable used to homogenize. If the user desires splines over $\Delta$, use the option Homogenize=>false. Example V = {{0,0},{1,0},{1,1},{-1,1},{-2,-1},{0,-1}};-- the coordinates of vertices F = {{0,2,1},{0,2,3},{0,3,4},{0,4,5},{0,1,5}}; -- a list of facets (pure complex) splineMatrix(V,F,1,Homogenize=>false) Text If the user would like to define the underlying ring (e.g. for later reference), this may be done using the option BaseRing=>R, where R is a polynomial ring defined by the user. Example V = {{0,0},{1,0},{1,1},{-1,1},{-2,-1},{0,-1}};-- the coordinates of vertices F = {{0,2,1},{0,2,3},{0,3,4},{0,4,5},{0,1,5}}; -- a list of facets (pure complex) R = QQ[x,y] --desired polynomial ring splineMatrix(V,F,1,Homogenize=>false,BaseRing=>R) Text Here is an example where the output is homogenized. Notice that homogenization occurs with respect to the last variable of the polynomial ring. Example V = {{0,0},{1,0},{1,1},{-1,1},{-2,-1},{0,-1}};-- the coordinates of vertices F = {{0,2,1},{0,2,3},{0,3,4},{0,4,5},{0,1,5}}; -- a list of facets (pure complex) R = QQ[x,y,z] --desired polynomial ring splineMatrix(V,F,1,BaseRing=>R) Text Alternately, the spline matrix can be created directly from the dual graph (with edges labeled by linear forms). Note: This way of entering data requires the ambient polynomial ring to be defined. See also the @TO generalizedSplines@ method. Example R = QQ[x,y] B = {{0,1},{1,2},{2,3},{3,4},{4,0}} H = {x-y,y,x,y-2*x,x+y} splineMatrix(B,H,1,InputType=>"ByLinearForms") /// doc /// Key splineModule (splineModule,List,List,List,ZZ) (splineModule,List,List,ZZ) Headline compute the module of all splines on partition of a space Usage M = splineModule(V,F,E,r) M = splineModule(V,F,r) Inputs V:List list of coordinates of vertices of $\Delta$ F:List list of facets of $\Delta$; each facet is recorded as a list of indices of vertices taken from V E:List list of codimension one faces of $\Delta$ (interior or not); each codimension one face is recorded as a list of indices of vertices taken from V r:ZZ desired degree of smoothness BaseRing=>Ring Homogenize=>Boolean CoefficientRing=>Ring VariableName=>Symbol InputType=>String Outputs M:Module module of splines on $\Delta$ Description Text This method returns the spline module. It is presented as the image of a matrix whose columns generate splines as a module over the polynomial ring. Each column represents a spline whose entries are the polynomials restricted to the facets of the complex $\Delta$. Example V = {{0,0},{1,0},{1,1},{0,1}} F = {{0,1,2},{0,2,3}} E = {{0,1},{0,2},{0,3},{1,2},{2,3}} splineModule(V,F,E,1) SeeAlso splineMatrix /// doc /// Key splineDimensionTable (splineDimensionTable,ZZ,ZZ,Module) (splineDimensionTable,ZZ,ZZ,List,ZZ) Headline a table with the dimensions of the graded pieces of a graded module Usage T=splineDimensionTable(a,b,M) T=splineDimensionTable(a,b,L,r) Inputs a:ZZ lowest degree in the table b:ZZ largest degree in the table M:Module graded module L:List a list {V,F,E} of the vertices, facets and codimension one faces of a polyhedral complex r:ZZ degree of smoothnes Outputs T:Table T= table with the dimensions of the graded pieces of M in the range a,b Description Text The output table gives you the dimensions of the graded pieces of the module M where the degree is between a and b. Example V = {{0,0},{1,0},{1,1},{0,1}}; F = {{0,1,2},{0,2,3}}; E = {{0,1},{0,2},{0,3},{1,2},{2,3}}; M=splineModule(V,F,E,2); splineDimensionTable(0,8,M) Text The table above records the dimensions dim$S^2_d(\Delta)$ (i.e. splines on $\Delta$ of smoothness 2 and degree at most d) for $d=$0,..,8. Text You may instead input the list L={V,F,E} (or L={V,F}) of the vertices, facets and codimension one faces of the complex $\Delta$. Example V = {{0,0},{1,0},{1,1},{0,1}}; F = {{0,1,2},{0,2,3}}; L = {V,F,E}; splineDimensionTable(0,8,L,2) Text The following complex, known as the Morgan-Scot partition, illustrates the subtle changes in dimension of spline spaces which may occur depending on geometry. Example V = {{-1,-1},{1,-1},{0,1},{10,10},{-10,10},{0,-10}}; V'= {{-1,-1},{1,-1},{0,1},{10,10},{-10,10},{1,-10}}; F = {{0,1,2},{2,3,4},{0,4,5},{1,3,5},{1,2,3},{0,2,4},{0,1,5}}; M = splineModule(V,F,1); M' = splineModule(V',F,1); splineDimensionTable(0,4,M) splineDimensionTable(0,4,M') Text Notice that the dimension of the space of $C^1$ quadratic splines changes depending on the geometry of $\Delta$. /// doc /// Key postulationNumber (postulationNumber,Module) Headline computes the largest degree at which the Hilbert function of the graded module M is not equal to the hilbertPolynomial Usage v = postulationNumber(M) Inputs M:Module graded module Outputs v:ZZ largest degree at which the Hilbert function of the graded module M is not equal to the hilbertPolynomial Description Text This function computes the postulation number of M which is defined as the largest degree at which the Hilbert function of the graded module M is not equal to the hilbertPolynomial Example V = {{0,0},{1,0},{1,1},{0,1}}; F = {{0,1,2},{0,2,3}}; E = {{0,1},{0,2},{0,3},{1,2},{2,3}}; M = splineModule(V,F,E,2) postulationNumber(M) /// doc /// Key hilbertComparisonTable (hilbertComparisonTable,ZZ,ZZ,Module) Headline a table to compare the values of the hilbertFunction and hilbertPolynomial of a graded module Usage T = hilbertComparisonTable(a,b,M) Inputs a:ZZ lowest degree in the table b:ZZ largest degree in the table M:Module graded module Outputs T:Table table with the degrees and values of the hilbertFunction and hilbertPolynomial Description Text The first row of the output table contains the degrees, the second row contains the values of the hilbertFunction, the third row contains the values of the hilbertPolynomial. In the following example, the hilbertFunction and polynomial always agree. Example V = {{0,0},{1,0},{1,1},{0,1}} F = {{0,1,2},{0,2,3}} E = {{0,1},{0,2},{0,3},{1,2},{2,3}} hilbertComparisonTable(0,8,splineModule(V,F,E,1)) Text The dimension of splines of degree at most d on a complex $\Delta$ is eventually given by a polynomial in d, which is the Hilbert polynomial of the spline module. Below we illustrate with the Morgan-Scot partition. Notice that the Hilbert polynomial for the symmetric Morgan-Scot partition and the asymmetric Morgan-Scot partition are the same, however the Hilbert functions disagree in degree 2. Example V = {{-1,-1},{1,-1},{0,1},{10,10},{-10,10},{0,-10}}; V'= {{-1,-1},{1,-1},{0,1},{10,10},{-10,10},{1,-10}}; F = {{0,1,2},{2,3,4},{0,4,5},{1,3,5},{1,2,3},{0,2,4},{0,1,5}}; M = splineModule(V,F,1); hilbertPolynomial(M,Projective=>false) M' = splineModule(V',F,1); hilbertPolynomial(M',Projective=>false) hilbertComparisonTable(0,4,M) postulationNumber(M) --final integer for which Hilbert function and polynomial disagree hilbertComparisonTable(0,4,M') postulationNumber(M') Text In the following example, we compare the Hilbert polynomial and Hilbert function of splines over a centrally triangulated octahedron; the behavior is very similar to the Morgan-Scot partition, except there is an extra degree of symmetry available which alters the Hilbert polynomials. Notice the use of the option Homogenize=>false to consider splines of degree precisely d instead of splines of degree at most d. Example V={{0,0,0},{1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1}}; --most symmetric variant V'={{0,0,0},{0,2,-1},{-1,-1,-1},{1,-1,-1},{0,-2,2},{1,1,2},{-1,1,2}}; --somewhat symmetric variant V''={{0,0,0},{10,1,1},{-1,10,1},{-1,1,10},{-10,1,-1},{1,-10,1},{-1,-1,-10}}; --asymmetric variant F={{0,1,2,3},{0,1,2,6},{0,1,3,5},{0,1,5,6},{0,2,3,4},{0,2,4,6},{0,3,4,5},{0,4,5,6}}; M=splineModule(V,F,1,Homogenize=>false); hilbertPolynomial(M,Projective=>false) M'=splineModule(V',F,1,Homogenize=>false); hilbertPolynomial(M',Projective=>false) M''=splineModule(V'',F,1,Homogenize=>false); hilbertPolynomial(M'',Projective=>false) hilbertComparisonTable(0,6,M) postulationNumber(M) --largest integer for which Hilbert function and polynomial disagree hilbertComparisonTable(0,6,M') postulationNumber(M') hilbertComparisonTable(0,6,M'') postulationNumber(M'') /// doc /// Key formsList (formsList,List,List,ZZ) Headline list of powers of (affine) linear forms cutting out a specified list of codimension one faces. Usage L = formsList(V,E,r) Inputs V:List list of coordinates of vertices E:List list of codimension 1 faces (each codimension 1 face is recorded as a list of indices of vertices taken from V) r:ZZ desired degree of smoothness BaseRing=>Ring Homogenize=>Boolean CoefficientRing=>Ring VariableName=>Symbol InputType=>String Outputs L:List L = list of (affine) linear forms cutting out codimension one faces specified by E, raised to the power (r+1) Description Text This method returns a list of (affine) linear forms cutting out codimension one faces, raised to the power (r+1). Example V = {{0,0},{1,0},{1,1},{0,1}}; E = {{0,1},{0,2},{0,3},{1,2},{2,3}}; formsList(V,E,0) S=QQ[x,y];--can specify the polynomial ring to use, and whether to homogenize formsList(V,E,0,BaseRing=>S,Homogenize=>false) /// doc /// Key generalizedSplines (generalizedSplines,List,List) RingType Headline the module of generalized splines associated to a simple graph with an edge labelling Usage M = generalizedSplines(E,I) -- M = generalizedSplines(G,I) Inputs E:List list of edges of a graph (an edge is represented as a list with two elements) I:List list of ideals in a ring RingType=>ZZ Outputs M:Module module of generalized splines on the graph with edges E and edge labels I Description Text This method returns the module of generalized splines on a graph with edgeset E on v vertices, whose edges are labelled by ideals of some ring R. By definition this is the submodule of $R^v$ consisting of tuples of polynomials such that the difference of polynomials corresponding to adjacent vertices are congruent module the ideal labelling the edge between them. Example S = QQ[x_0,x_1,x_2]; --the underlying ring E = {{0,1},{1,2},{0,2}} --edges of the graph (in this case a triangle) I = {x_0-x_1,x_1-x_2,x_2-x_0} --ideals of S (elements of S are interpreted as principal ideals) generalizedSplines(E,I) --in this case this is the module of derivations on the $A_2$ arrangement -- Text -- The input can also be a graph. Care must be taken that ideals in the list I are listed in the -- same order edges(G). -- Example -- G = completeGraph(4); -- S = QQ[apply(vertices G,i->x_i)]; -- I = apply(edges G,e->(E=elements(e); x_(E_0)-x_(E_1)) ); -- generalizedSplines(G,I) --module of derivations on $A_3$ Text If edge labels are integers, generalizedSplines is computed as a ZZ module by default. Example E={{0,1},{1,2},{2,3},{0,3}}; I={3,4,5,6}; generalizedSplines(E,I) Text The above splines may also be computed over ZZ modulo some integer. Example E={{0,1},{1,2},{2,3},{0,3}}; I={3,4,5,6}; generalizedSplines(E,I,RingType=>9) --computes spline module with underlying ring ZZ/9 Text Arbitrary ideals may also be entered as edge labels. Example S=QQ[x,y,z] E={{1,2},{2,3},{3,4}} I={ideal(x,y),ideal(y),ideal(z)} generalizedSplines(E,I) Text This method can be used to compute splines over non-linear partitions. The example below can be found in Exercise 13 of Section 8.3 in the book Using Algebraic Geometry by Cox,Little, and O'Shea. Example E={{0,1},{1,2},{0,2}}; S=QQ[x,y]; I={y-x^2,x+y^2,y-x^3};--these three curves meet at the origin generalizedSplines(E,I)--this is the module of C^0 splines on the partition /// doc /// Key cellularComplex (cellularComplex,List,List) (cellularComplex,List) Headline create the cellular chain complex whose homologies are the singular homologies of the complex $\Delta$ relative to its boundary Usage C = cellularComplex(F,InputType=>Simplicial) --for use only if $\Delta$ is simplicial C = cellularComplex(V,F) Inputs V:List list of coordinates of vertices of $\Delta$ F:List list of facets of $\Delta$ (each facet is recorded as a list of indices of vertices taken from V) BaseRing=>Ring Homogenize=>Boolean CoefficientRing=>Ring VariableName=>Symbol InputType=>String Outputs C:ChainComplex cellular chain complex of $\Delta$ relative to its boundary Description Text This method returns the cellular chain complex of $\Delta$ relative to its boundary. If $\Delta$ is homeomorphic to a disk, the homologies will vanish except for the top dimension. Example V = {{0,0},{1,0},{0,1},{-1,-1}}; F = {{0,1,2},{0,2,3},{0,1,3}}; C = cellularComplex(V,F) prune HH C Text If the complex is simplicial, there is no need for a vertex list. Example F = {{0,1,2},{0,1,3},{0,2,3}}; C = cellularComplex(F,InputType=>"Simplicial") Text Arbitrary dimensions and polyhedral input are allowed. Example V = {{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}, {-2, -2, -2}, {-2, 2, -2}, {2, 2, -2}, {2, -2, -2}, {-2, -2, 2}, {-2, 2, 2}, {2, 2, 2}, {2, -2, 2}}; F = {{0, 1, 2, 3, 4, 5}, {0, 8, 9, 12, 13}, {1, 6, 7, 10, 11}, {2, 7, 8, 11, 12}, {3, 6, 9, 10, 13}, {4, 10, 11, 12, 13}, {5, 6, 7, 8, 9}, {0, 2, 8, 12}, {0, 3, 9, 13}, {0, 4, 12, 13}, {0, 5, 8, 9}, {1, 2, 7, 11}, {1, 3, 6, 10}, {1, 4, 10, 11}, {1, 5, 6, 7}, {2, 4, 11, 12}, {3, 4, 10, 13}, {3, 5, 6, 9}, {2, 5, 7, 8}, {0, 2, 4, 12}, {0, 2, 5, 8}, {0, 3, 4, 13}, {0, 3, 5, 9}, {1, 2, 4, 11}, {1, 2, 5, 7}, {1, 3, 4, 10}, {1, 3, 5, 6}}; C = cellularComplex(V,F); prune HH C SeeAlso idealsComplex splineComplex /// doc /// Key idealsComplex (idealsComplex, List,List,ZZ) Headline creates the Billera-Schenck-Stillman chain complex of ideals Usage C = idealsComplex(V,F,r) Inputs V:List list of vertex coordinates of $\Delta$ F:List list of facets of $\Delta$ (each facet is recorded as a list of indices of vertices taken from V) r:ZZ integer, desired degree of smoothness BaseRing=>Ring Homogenize=>Boolean CoefficientRing=>Ring VariableName=>Symbol Outputs C:ChainComplex Billera-Schenck-Stillman chain complex of ideals Description Text This method returns the Billera-Schenck-Stillman chain complex of ideals whose top homology is the module of non-trivial splines on $\Delta$. Example V = {{0,0},{1,0},{0,1},{-1,-1}}; F = {{0,1,2},{0,2,3},{0,1,3}}; C = idealsComplex(V,F,1); prune HH C Text The output from the above example shows that there is only one nonvanishing homology, and it is free as a module over the polynomial ring in three variables. Example V = {{-1,-1},{1,-1},{0,1},{-2,-2},{2,-2},{0,2}}; F = {{0,1,2},{0,1,3,4},{1,2,4,5},{0,2,3,5}}; C = idealsComplex(V,F,1); prune HH C Text The output from the above example shows that there are two nonvanishing homologies, but the spline module, which is (almost) the homology HH_1, is still free. This shows that freeness of the spline module does not depend on vanishing of lower homologies if the underlying complex is polyhedral. SeeAlso cellularComplex splineComplex /// doc /// Key courantFunctions (courantFunctions, List,List) Headline returns the Courant functions of a simplicial complex Usage M=courantFunctions(V,F) Inputs V:List a list of vertex coordinates F:List a list of facets, recorded as indices of V BaseRing=>Ring Homogenize=>Boolean CoefficientRing=>Ring VariableName=>Symbol InputType=>String Outputs M:Matrix a matrix so that column $i$ is the Courant function corresponding to vertex $V_i$ Description Text This method returns a matrix with as many rows as facets and as many columns as vertices. Column $i$ of the matrix is the Courant function corresponding to vertex $V_i$. This is the piecewise linear function which takes the value $1$ at the vertex $V_i$ and $0$ at all other vertices. Example V={{0,0},{0,1},{-1,-1},{1,0}}; F={{0,1,2},{0,2,3},{0,1,3}}; courantFunctions(V,F) Text If the option Homogenize=>false is given, the Courant function corresponding to a cone vertex (if there is one) will be discarded. Example S=QQ[x,y]; courantFunctions(V,F,Homogenize=>false,BaseRing=>S) Text The Courant functions are used to construct the Stanley Reisner ring of a simplicial complex. See @TO stanleyReisner@. SeeAlso stanleyReisner ringStructure stanleyReisnerPresentation /// doc /// Key stanleyReisner (stanleyReisner, List, List) Headline Creates a ring map whose image is the ring of piecewise continuous polynomials on $\Delta$. If $\Delta$ is simplicial, the Stanley Reisner ring of $\Delta$ is returned. Usage phi=stanleyReisner(V,F) Inputs V:List a list of vertex coordinates F:List a list of facets, recorded as indices of V BaseRing=>Ring Homogenize=>Boolean CoefficientRing=>Ring VariableName=>Symbol InputType=>String Outputs phi:RingMap a ring map whose image is the ring of piecewise polynomials on $\Delta$. Description Text This method returns the ring of continuous piecewise polynomials on the complex $\Delta$ with vertices $V$ and facets $F$. If $\Delta$ is a simplicial complex, write $\Delta_0$ for its vertices and $K[\Delta]$ for the Stanley-Reisner ring of $\Delta$, which is the quotient of the polynomial ring $K[X_v:v\in\Delta_0]$ by monomials corresponding to non-faces. Then, as a ring, $C^0(\Delta)$ is isomorphic to the so-called affine Stanley Reisner ring $K_a[\Delta]=\frac{K[\Delta]}{(1-\sum_{v} X_v)K[\Delta]}$. If $\Delta$ is a cone, then $K_a[\Delta]=K[\Delta_{dc}]$, where $\Delta_{dc}$ is the decone of $\Delta$. The map $K_a[\Delta]\rightarrow C^0(\Delta)$ is given by $X_v\rightarrow C_v$, where $C_v$ is the Courant function at the vertex $v$. See @TO courantFunctions@. Example V={{0,0},{0,1},{-1,-1},{1,0}}; F={{0,1,2},{0,2,3},{0,1,3}}; phi=stanleyReisner(V,F) ker phi--decone of homogenized simplicial complex is three triangles meeting at a vertex Example R=QQ[x,y]; phi=stanleyReisner(V,F,BaseRing=>R,Homogenize=>false) ker phi--decone of simplicial complex is a three-cycle Text The Stanley Reisner ring of a simplicial complex is obtained using the function @TO ringStructure@, where the ring generators are chosen to be the Courant functions. Example V={{0,0},{0,1},{-1,-1},{1,0}}; F={{0,1,2},{0,2,3},{0,1,3}}; R=QQ[x,y]; CF = courantFunctions(V,F,Homogenize=>false,BaseRing=>R); phi=ringStructure(image CF,VariableGens=>false) ker phi Text If $\Delta$ is not simplicial, then the image of the map is a minimal set of generators for the ring $C^0(\Delta)$. There is no canonical choice of generators, and $C^0(\Delta)$ is no longer a combinatorial object. Example V={{0,1},{-1,-1},{1,-1},{0,10},{-2,-2},{2,-2}};--symmetric triangular prism V'={{0,1},{-1,-1},{1,-1},{1,10},{-2,-2},{2,-2}};--asymmetric triangular prism F={{0,1,2},{0,1,3,4},{0,2,3,5},{1,2,4,5}}; S=QQ[x,y,z]; phi=stanleyReisner(V,F,BaseRing=>S) --four generators in degree one phi'=stanleyReisner(V',F,BaseRing=>S) --six generators in degrees one and two ker phi --kernel generated by single polynomial of degree four mingens ker phi' --kernel has six minimal generators of degree four SeeAlso courantFunctions ringStructure stanleyReisnerPresentation /// doc /// Key ringStructure (ringStructure, Module) GenVar IdempotentVar Trim VariableGens Headline given a sub-module of a free module (viewed as a ring with direct sum structure) which is also a sub-ring, creates a ring map whose image is the module with its ring structure Usage phi=ringStructure(M) Inputs M:Module a sub-module of a free module over a polynomial ring which is also a sub-ring GenVar=>Symbol IdempotentVar=>Symbol Trim=>Symbol VariableGens=>Symbol Outputs phi:RingMap map of rings whose image is the module M with its ring structure, assuming M contains the identity element Description Text Let M be a sub-module of the free module $R^k$, where $R=K[x_0,\ldots,x_n]$ for some field K. We view $R^k=Re_0+Re_1+\cdots+Re_{k-1}$ as a ring with component-wise multiplication (i.e. $e_0,\ldots,e_{k-1}$ are idempotents). Suppose further that the identity element of $R^k$, namely $e=e_0+\cdots+e_{k-1}$, is an element of M. Then the M is also a ring; this method creates a map whose image is M with its ring structure. Example V={{0,1},{1,0},{0,-1},{-1,0}}; F={{0,1,2},{0,2,3}};--two triangles meeting along an edge R=QQ[x,y]; M=splineModule(V,F,1,BaseRing=>R,Homogenize=>false);--create spline module phi=ringStructure(M) Text The target of the map is $R^k$ as a ring. Example T=target phi; describe T --direct sum of two copies of R, one for each face; e_i corresponds to the face F_i Text As above, write $e$ for the identity of $R^k$. Then the generators for $M$ as a sub-ring of $R^k$ are the generators of $M$ as an $R$-module (other than $e$), together with the generators $x_0e,x_1e,\ldots,x_ne$. The source of the map created by ringStructure(M) is a polynomial ring in variables $Y_0,\ldots,Y_n,Y_{n+1},\cdots,Y_m$, where $Y_0,\cdots,Y_n$ correspond to the generators $x_0e,\ldots,x_ne$ and $Y_{n+1},\cdots,Y_m$ correspond to the usual generators of M (except for e, if it happens to be a generator of M). Example H=source phi; describe H --polynomial ring in three variables, one for each generator of R and each (non-identity) generator of M scan(3,i->print phi(H_i))--these are the splines the variables map to Text The kernel of the map created by ringStructure(M) is the ideal of relations on the ring generators. If M is graded, the grading on the source of the map matches up with the grading on M. Example degrees H --degrees of variables are same as degrees of generators of M I=ker phi--the ideal of relations among generators reduceHilbert(hilbertSeries (H/I))--cokernel of phi has the same graded structure as M reduceHilbert(hilbertSeries M) Text It often happens that module generators are redundant as ring generators. These can be eliminated with the option Trim=>true. The remaining variables in the source ring retain their indexing from the output of ringStructure without the Trim=>true option. Example V={{0,0},{0,1},{-1,-1},{1,0}}; F={{0,1,2},{0,2,3},{0,1,3}};--three triangles meeting at (and surrounding) a vertex R=QQ[x,y]; M=splineModule(V,F,0,BaseRing=>R,Homogenize=>false); phi = ringStructure(M); ker phi --notice a generator involves an isolated variable phi' = ringStructure(M,Trim=>true); ker phi' --now all variables correspond to irredundant generators Text If $\Delta$ is a simplicial complex, write $\Delta_0$ for its vertices and $K[\Delta]$ for the Stanley-Reisner ring of $\Delta$, which is the quotient of the polynomial ring $K[X_v:v\in\Delta_0]$ by monomials corresponding to non-faces. Then, as a ring, $C^0(\Delta)$ is isomorphic to the so-called affine Stanley Reisner ring $\frac{K[\Delta]}{(1-\sum_{v} X_v)K[\Delta]}$. If $\Delta$ is a cone, as above, then the affine Stanley Reisner ring is just the Stanley Reisner ring of the decone of $\Delta$. In the above example the decone is an empty triangle, so $C^0(\Delta)$ should be isomorphic to a polynomial ring in three variables modulo the ideal generated by the product of the variables. The isomorphism can be seen by the following change of variables. Alternatively, the ring structure of $C^0(\Delta)$ with this preferred set of generators is obtained with the command @TO stanleyReisner@. Example f = (ker phi')_0 sub(f,{Y_0=>Y_0-Y_1,Y_1=>Y_0-Y_2,Y_2=>Y_0}) Text To obtain the sub-ring of $R^k$ which is generated by a specific set of module generators of M, i.e. without adding $x_0e,\ldots,x_ne$ as ring generators, use the option VariableGens=>false. This may be done if the user has a particular choice of ring generators they would like to use - for instance the Courant functions. See @TO courantFunctions@. Text We may also use ringStructure to create the ring of splines for more general spline modules created using the @TO generalizedSplines@ method. Example E={{0,1},{1,2},{0,2}}; S=QQ[x,y]; I={y-x^2,x+y^2,y-x^3}; C0=generalizedSplines(E,I);--splines on a non-linear partition ringStructure(C0) Caveat The Trim option will not work for quotients of polynomial rings over ZZ or ZZ modulo a non-prime integer. SeeAlso courantFunctions stanleyReisner stanleyReisnerPresentation /// doc /// Key stanleyReisnerPresentation (stanleyReisnerPresentation, List,List,ZZ) Headline creates a ring map whose image is the sub-ring of $C^0(\Delta)$ generated by $C^r(\Delta)$. If $\Delta$ is simplicial, $C^0(\Delta)$ is the Stanley Reisner ring of $\Delta$. Usage phi = stanleyReisnerPresentation(V,F,r) Inputs V:List list of vertex coordinates of $\Delta$ F:List list of facets of $\Delta$ (each facet is recorded as a list of indices of vertices taken from V) r:ZZ integer, desired degree of smoothness BaseRing=>Ring Homogenize=>Boolean CoefficientRing=>Ring VariableName=>Symbol GenVar=>Symbol IdempotentVar=>Symbol Trim=>Symbol VariableGens=>Symbol InputType=> String Outputs phi:RingMap ring map whose image is $C^r(\Delta)$ as a sub-ring of $C^0(\Delta)$ Description Text This method creates a ring map whose image is the sub-ring of $C^r$ splines expressed in terms of $C^0$ generators. If $\Delta$ is simplicial, $C^0(\Delta)$ is expressed as the Stanley Reisner ring. Example V={{0,0},{0,1},{-1,-1},{1,0}}; F={{0,1,2},{0,2,3},{0,1,3}}; R=QQ[x,y]; phi=stanleyReisnerPresentation(V,F,1,Homogenize=>false,BaseRing=>R) H=source phi; scan(gens H, g->print phi(g))--see the expression of each generator in the Stanley Reisner ring Text The kernel of the map is the same as the kernel of the map returned by @TO ringStructure@, but the generators are expressed differently. Example M=splineModule(V,F,1,Homogenize=>false,BaseRing=>R); phi1=ringStructure(M); H=source phi; H1=source phi1; gens H gens H1 psi=map(H,H1,gens H);--phi1 has "same" source as H, but they are viewed as different rings by Macaulay2 scan(gens H1,g->print {g,phi1(g),phi(psi(g))})--phi expresses generators of M in the Stanley Reisner ring, while phi1 expresses generators in the free module R^3 (ker phi)==psi(ker phi1)--the kernels are the same Text The option Trim=>true may be used to get a minimal number of ring generators. Example V={{0,0,0},{1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1}}; F={{0,1,2,3},{0,1,2,6},{0,2,3,4},{0,2,4,6},{0,1,3,5},{0,3,4,5},{0,4,5,6},{0,1,5,6}};--centrally triangulated octahedron S=QQ[x,y,z]; stanleyReisnerPresentation(V,F,1,Homogenize=>false,BaseRing=>S) stanleyReisnerPresentation(V,F,1,Homogenize=>false,BaseRing=>S,Trim=>true) Text The geometry effects $C^1$ simplicial splines, although it doesn't effect $C^0$ simplicial splines. Example V'={{0,0,0},{1,0,0},{0,1,0},{1,1,1},{-1,0,0},{0,-1,0},{0,0,-1}}; --centrally triangulated octahedron that has been perturbed F={{0,1,2,3},{0,1,2,6},{0,2,3,4},{0,2,4,6},{0,1,3,5},{0,3,4,5},{0,4,5,6},{0,1,5,6}}; stanleyReisnerPresentation(V',F,1,Homogenize=>false,BaseRing=>S,Trim=>true) Text If $\Delta$ is not simplicial, $C^0(\Delta)$ does not have the same nice structure. Example V={{0,1},{-1,-1},{1,-1},{0,2},{-2,-2},{2,-2}}; F={{0,1,2},{0,1,3,4},{0,2,3,5},{1,2,4,5}}; --symmetric triangular prism-- S=QQ[x,y,z]; stanleyReisnerPresentation(V,F,1,BaseRing=>S,Trim=>true) SeeAlso courantFunctions stanleyReisner ringStructure /// doc /// Key splineComplex (splineComplex, List,List,ZZ) Headline creates the Billera-Schenck-Stillman chain complex Usage C = splineComplex(V,F,r) Inputs V:List list of vertex coordinates of $\Delta$ F:List list of facets of $\Delta$ (each facet is recorded as a list of indices of vertices taken from V) r:ZZ integer, desired degree of smoothness BaseRing=>Ring Homogenize=>Boolean CoefficientRing=>Ring VariableName=>Symbol Outputs C:ChainComplex Billera-Schenck-Stillman spline complex Description Text This method returns the Billera-Schenck-Stillman chain complex whose top homology is the module of splines on $\Delta$. Example V = {{0,0},{1,0},{0,1},{-1,-1}}; F = {{0,1,2},{0,2,3},{0,1,3}}; C = splineComplex(V,F,1); prune HH C Text The output from the above example shows that there is only one nonvanishing homology, and it is free as a module over the polynomial ring in three variables. Notice that the rank is one more than the corresponding nonvanishing homology given by idealsComplex. Example V = {{-1,-1},{1,-1},{0,1},{-2,-2},{2,-2},{0,2}}; F = {{0,1,2},{0,1,3,4},{1,2,4,5},{0,2,3,5}}; C = splineComplex(V,F,1); prune HH C Text The output from the above example shows that there are two nonvanishing homologies, but the spline module, which is (almost) the homology HH_1, is still free. This shows that freeness of the spline module does not depend on vanishing of lower homologies if the underlying complex is polyhedral. Example R = (ZZ/4021)[x,y,z]; V = {{-1,-1},{1,-1},{0,1},{10,10},{-10,10},{0,-10}}; V'= {{-1,-1},{1,-1},{0,1},{10,10},{-10,10},{1,-10}}; F = {{0,1,2},{2,3,4},{0,4,5},{1,3,5},{1,2,3},{0,2,4},{0,1,5}}; C = splineComplex(V,F,1,BaseRing=>R); C' = splineComplex(V',F,1,BaseRing=>R); prune HH C prune HH C' Text The above example is known as the Morgan-Scot partition. It shows how subtle spline calculations can be. Note that the spline module over the symmetric Morgan-Scot partition above (vertices V) is not free, while the spline module over the non-symmetric Morgan-Scot partition is free. Example R = QQ[x,y,z]; V = {{-1,-1},{1,-1},{0,1},{10,10},{-10,10},{0,-10}}; F = {{0,1,2},{2,3,4},{0,4,5},{1,3,5},{1,2,3},{0,2,4},{0,1,5}}; Id = idealsComplex(V,F,1,BaseRing=>R); C = cellularComplex(V,F,BaseRing=>R); phi = inducedMap(C,Id); SC = splineComplex(V,F,1,BaseRing=>R); SC == (coker phi) Text The above example shows that the Billera-Schenck-Stillman spline complex is the cokernel of the natural map between the complex of ideals (given by idealsComplex) and the cellular chain complex of $\Delta$ relative to its boundary. Example V = {{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}, {-2, -2, -2}, {-2, 2, -2}, {2, 2, -2}, {2, -2, -2}, {-2, -2, 2}, {-2, 2, 2}, {2, 2, 2}, {2, -2, 2}}; F = {{0, 1, 2, 3, 4, 5}, {0, 8, 9, 12, 13}, {1, 6, 7, 10, 11}, {2, 7, 8, 11, 12}, {3, 6, 9, 10, 13}, {4, 10, 11, 12, 13}, {5, 6, 7, 8, 9}, {0, 2, 8, 12}, {0, 3, 9, 13}, {0, 4, 12, 13}, {0, 5, 8, 9}, {1, 2, 7, 11}, {1, 3, 6, 10}, {1, 4, 10, 11}, {1, 5, 6, 7}, {2, 4, 11, 12}, {3, 4, 10, 13}, {3, 5, 6, 9}, {2, 5, 7, 8}, {0, 2, 4, 12}, {0, 2, 5, 8}, {0, 3, 4, 13}, {0, 3, 5, 9}, {1, 2, 4, 11}, {1, 2, 5, 7}, {1, 3, 4, 10}, {1, 3, 5, 6}}; C = splineComplex(V,F,1); associatedPrimes annihilator HH_2 C Text The above example showcases a fairly complex three dimensional polyhedral complex. It is a three-dimensional analog of the Morgan-Scot partition in the sense that it consists of an octahedron inside of a cube (note these are dual polytopes). Its facets consist of the octahedron, twelve tetrahedra coming from joining dual edges on the cube and the octahedron, and six 'Egyptian pyramids' coming from joining each vertex of the octahedron to a square face on the cube. The homologies of this spline complex are quite interesting. The two lower homologies vanish (the lowest always does). The top homology (HH_3) is the spline module. The second homology is nonzero and illustrates the fact that the associated primes of the homologies of the spline complex are all linear. There is an associated prime for every vertex of the complex, plus three more that lie on the hyperplane at infinity, plus the maximal ideal. SeeAlso cellularComplex idealsComplex /// TEST /// V = {{0,0},{1,0},{1,1},{-1,1},{-2,-1},{0,-1}} F = {{0,2,1},{0,2,3},{0,3,4},{0,4,5},{0,1,5}} E = {{0,1},{0,2},{0,3},{0,4},{0,5}} S = QQ[x,y,z] R = QQ[u,v] assert(splineMatrix(V,F,E,0) == matrix {{1, 0, 0, 0, -1, t_1, 0, 0, 0, 0}, {1, -1, 0, 0, 0, 0, t_0-t_1, 0, 0, 0}, {0, 1, -1, 0, 0, 0, 0, t_0+t_1, 0, 0}, {0, 0, 1, -1, 0, 0, 0, 0, t_0-2*t_1, 0}, {0, 0, 0, 1, -1, 0, 0, 0, 0, t_0}}) assert(splineMatrix(V,F,E,0,Homogenize=>false) == matrix {{1, 0, 0, 0, -1, t_2, 0, 0, 0, 0}, {1, -1, 0, 0, 0, 0, t_1-t_2, 0, 0, 0}, {0, 1, -1, 0, 0, 0, 0, t_1+t_2, 0, 0}, {0, 0, 1, -1, 0, 0, 0, 0, t_1-2*t_2, 0}, {0, 0, 0, 1, -1, 0, 0, 0, 0, t_1}}) assert(splineMatrix(V,F,E,1) == matrix {{1, 0, 0, 0, -1, t_1^2, 0, 0, 0, 0}, {1, -1, 0, 0, 0, 0, t_0^2-2*t_0*t_1+t_1^2, 0, 0, 0}, {0, 1, -1, 0, 0, 0, 0, t_0^2+2*t_0*t_1+t_1^2, 0, 0}, {0, 0, 1, -1, 0, 0, 0, 0, t_0^2-4*t_0*t_1+4*t_1^2, 0}, {0, 0, 0, 1, -1, 0, 0, 0, 0, t_0^2}}) assert(splineMatrix(V,F,0,BaseRing=>S)==matrix {{1, 0, 0, 0, -1, y, 0, 0, 0, 0}, {1, -1, 0, 0, 0, 0, x-y, 0, 0, 0}, {0, 1, -1, 0, 0, 0, 0, x+y, 0, 0}, {0, 0, 1, -1, 0, 0, 0, 0, x-2*y, 0}, {0, 0, 0, 1, -1, 0, 0, 0, 0, x}}) assert(splineMatrix(V,F,0,Homogenize=>false,BaseRing=>R)==matrix {{1, 0, 0, 0, -1, v, 0, 0, 0, 0}, {1, -1, 0, 0, 0, 0, u-v, 0, 0, 0}, {0, 1, -1, 0, 0, 0, 0, u+v, 0, 0}, {0, 0, 1, -1, 0, 0, 0, 0, u-2*v, 0}, {0, 0, 0, 1, -1, 0, 0, 0, 0, u}}) assert(splineModule(V,F,1,BaseRing=>S)==image matrix {{1, 6*y^2, -4*y^2, 4*x*y^2, -4*y^3}, {1, 3*x^2-6*x*y+9*y^2, -x^2+2*x*y-5*y^2, x^2*y+2*x*y^2+y^3, x^3-3*x*y^2-2*y^3}, {1, 2*x^2-8*x*y+8*y^2, 4*x*y-4*y^2, 0, 0}, {1, 0, x^2, 0, 0}, {1, 0, 0, 0, 0}}) /// TEST /// V={{-5,0},{-3,0},{-1,-4},{-1,4},{-1,-2},{-1,2},{0,-1},{0,1},{1,-2},{1,2},{1,-4},{1,4},{3,0},{5,0}} F={{0, 1, 4, 2}, {0, 1, 5, 3}, {8, 10, 13, 12}, {9, 11, 13, 12}, {1, 4, 6, 7, 5}, {2, 4, 6, 8, 10}, {3, 5, 7, 9, 11}, {6, 7, 9, 12, 8}} E={{0, 1}, {0, 2}, {0, 3}, {1, 4}, {1, 5}, {2, 4}, {2, 10}, {3, 5}, {3, 11}, {4, 6}, {5, 7}, {6, 7}, {6, 8}, {7, 9}, {8, 10}, {8, 12}, {9, 11}, {9, 12}, {10, 13}, {11, 13}, {12, 13}} assert(splineMatrix(V,F,E,0) == matrix {{1, -1, 0, 0, 0, 0, 0, 0, t_1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, -1, 0, 0, 0, 0, t_0+t_1+3*t_2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, -1, 0, 0, 0, 0, 0, t_0-t_1+3*t_2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, t_0+t_2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, t_0+t_2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, t_0-t_1-t_2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, t_0+t_1-t_2, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, t_0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, t_0+t_1+t_2, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_0-t_1+t_2, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_0-t_2, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_0-t_1-3*t_2, 0, 0, 0}, {0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_0-t_2, 0, 0}, {0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_0+t_1-3*t_2, 0}, {0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_1}}) assert(splineMatrix(V,F,E,0,Homogenize=>false) == matrix {{1, -1, 0, 0, 0, 0, 0, 0, t_2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, -1, 0, 0, 0, 0, t_1+t_2+3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, -1, 0, 0, 0, 0, 0, t_1-t_2+3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, t_1+1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, t_1+1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, t_1-t_2-1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, t_1+t_2-1, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, t_1, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, t_1+t_2+1, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_1-t_2+1, 0, 0, 0, 0, 0}, {0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_1-1, 0, 0, 0, 0}, {0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_1-t_2-3, 0, 0, 0}, {0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_1-1, 0, 0}, {0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_1+t_2-3, 0}, {0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, t_2}}) /// TEST /// V={{0,0,0},{1,1,1},{-1,1,1},{-1,1,-1},{1,1,-1},{1,-1,1},{-1,-1,1},{-1,-1,-1},{1,-1,-1}}; F={{0,1,2,3,4},{0,1,4,5,8},{0,5,6,7,8},{0,2,3,6,7},{0,1,2,5,6}}; C=cellularComplex(V,F); sC=splineComplex(V,F,0); iC=idealsComplex(V,F,0); assert((prune HH_0 C)==prune image matrix{{0_(C.ring)}}) assert((prune HH_1 C)==prune image matrix{{0_(C.ring)}}) assert((prune HH_2 C)==prune image matrix{{0_(C.ring)}}) assert((prune HH_3 C)==prune image matrix{{1_(C.ring)}}) assert((prune HH_0 sC)==prune image matrix{{0_(sC.ring)}}) assert((prune HH_1 sC)==prune image matrix{{0_(sC.ring)}}) assert((prune HH_2 sC)==coker map((sC.ring)^{1:-1},(sC.ring)^2,sub(matrix{{t_1,t_0}},(sC.ring)))) assert((prune HH_3 sC)==(sC.ring)^{1:0,1:-1,2:-2,1:-3}) assert((prune HH_0 iC)==prune image matrix{{0_(iC.ring)}}) assert((prune HH_1 iC)==coker map((iC.ring)^{1:-1},(iC.ring)^2,sub(matrix{{t_1,t_0}},(iC.ring)))) assert((prune HH_2 iC)==(iC.ring)^{1:-1,2:-2,1:-3}) assert((prune HH_3 iC)==prune image matrix{{0_(iC.ring)}}) /// TEST /// V = {{-1,-1},{1,-1},{0,1},{10,10},{-10,10},{0,-10}}; V'= {{-1,-1},{1,-1},{0,1},{10,10},{-10,10},{1,-10}}; F = {{0,1,2},{2,3,4},{0,4,5},{1,3,5},{1,2,3},{0,2,4},{0,1,5}}; S1 = splineModule(V,F,1); S1' = splineModule(V',F,1); assert(splineDimensionTable(0,5,S1)==netList{{Degree,0,1,2,3,4,5},{"Dimension",1,3,7,16,33,57}}) assert(splineDimensionTable(0,5,S1')==netList{{Degree,0,1,2,3,4,5},{"Dimension",1,3,6,16,33,57}}) assert(hilbertComparisonTable(0,5,S1')==netList{{Degree,0,1,2,3,4,5},{"Dimension",1,3,6,16,33,57},{"HilbertPoly",7,3,6,16,33,57}}) assert(hilbertComparisonTable(0,5,S1)==netList{{Degree,0,1,2,3,4,5},{"Dimension",1,3,7,16,33,57},{"HilbertPoly",7,3,6,16,33,57}}) assert(postulationNumber(S1)==2) assert(postulationNumber(S1')==0) /// TEST /// V = {{0,0},{1,0},{1,1},{0,1}}; E = {{0,1},{0,2},{0,3},{1,2},{2,3}}; S=QQ[x,y]; assert(formsList(V,E,0)=={t_1, t_0-t_1, t_0, t_0-t_2, t_1-t_2}) assert(formsList(V,E,0,BaseRing=>S,Homogenize=>false)=={y, x-y, x, x-1, y-1}) /// TEST /// S = QQ[x,y]; E = {{0,1},{1,2},{2,3},{3,4},{0,4}}; L = {ideal(y^2),ideal((x-y)^2),ideal((x+y)^2),ideal((x-2*y)^2),ideal(x^2)} assert(generalizedSplines(E,L)==image matrix {{1, 2*x^2, -3*x^2, x^2*y, x^3}, {1, 2*x^2+2*y^2, -3*x^2, x^2*y-2*x*y^2+y^3, x^3-3*x*y^2+2*y^3}, {1, x^2+2*x*y+y^2, -6*x*y+3*y^2, 0, 0}, {1, 0, x^2-4*x*y+4*y^2, 0, 0}, {1, 0, 0, 0, 0}}) /// TEST /// V={{0,0},{0,1},{-1,-1},{1,0}}; F={{0,1,2},{0,2,3},{0,1,3}}; R=QQ[x,y]; M=splineModule(V,F,0,BaseRing=>R,Homogenize=>false); phi = ringStructure(M); assert((ker phi)==ideal(Y_1*Y_3-Y_2*Y_3,Y_0*Y_2-Y_2^2-Y_3)); phi' = ringStructure(M,Trim=>true); assert((ker phi')==ideal(Y_0*Y_1*Y_2-Y_0*Y_2^2-Y_1*Y_2^2+Y_2^3)); /// TEST /// V={{-1,0},{1,0},{2,1},{2,-1},{0,-1},{-2,-1},{-2,1},{0,1}}; F={{0,1,7},{0,1,4},{0,4,5},{0,5,6},{0,6,7},{1,2,7},{1,2,3},{1,3,4}}; S=QQ[x,y,z]; assert(courantFunctions(V,F,BaseRing=>S)==matrix {{-(1/2)*x-(1/2)*y+(1/2)*z, (1/2)*x-(1/2)*y+(1/2)*z, 0, 0, 0, 0, 0, y}, {-(1/2)*x+(1/2)*y+(1/2)*z, (1/2)*x+(1/2)*y+(1/2)*z, 0, 0, -y, 0, 0, 0}, {y+z, 0, 0, 0, (1/2)*x-(1/2)*y+(1/2)*z, -(1/2)*x-(1/2)*y-(1/2)*z, 0, 0}, {x+2*z, 0, 0, 0, 0, -(1/2)*x-(1/2)*y-(1/2)*z, -(1/2)*x+(1/2)*y-(1/2)*z, 0}, {-y+z, 0, 0, 0, 0, 0, -(1/2)*x+(1/2)*y-(1/2)*z, (1/2)*x+(1/2)*y+(1/2)*z}, {0, -y+z, (1/2)*x+(1/2)*y-(1/2)*z, 0, 0, 0, 0, -(1/2)*x+(1/2)*y+(1/2)*z}, {0, -x+2*z, (1/2)*x+(1/2)*y-(1/2)*z, (1/2)*x-(1/2)*y-(1/2)*z, 0, 0, 0, 0}, {0, y+z, 0, (1/2)*x-(1/2)*y-(1/2)*z, -(1/2)*x-(1/2)*y+(1/2)*z, 0, 0, 0}}) V={{0,0},{0,1},{-1,-1},{1,0}}; F={{0,1,2},{0,2,3},{0,1,3}}; R=QQ[x,y]; assert(courantFunctions(V,F,BaseRing=>R,Homogenize=>false)==matrix {{-x+y, -x, 0}, {0, -y, x-y}, {y, 0, x}}) /// TEST /// V={{0,0},{0,1},{-1,-1},{1,0}}; F={{0,1,2},{0,2,3},{0,1,3}}; R=QQ[x,y]; phi=stanleyReisner(V,F); assert((ker phi)==ideal(X_1*X_2*X_3)) phi1=stanleyReisner(V,F,BaseRing=>R,Homogenize=>false); assert((ker phi1)==ideal(X_0*X_1*X_2)) V={{-1,0},{1,0},{2,1},{2,-1},{0,-1},{-2,-1},{-2,1},{0,1}}; F={{0,1,7},{0,1,4},{0,4,5},{0,5,6},{0,6,7},{1,2,7},{1,2,3},{1,3,4}}; phi=stanleyReisner(V,F); H = source phi; G = apply(gens H,v->phi(v)); phi1=ringStructure(image courantFunctions(V,F),VariableGens=>false); H1 = source phi1; T1 = target phi1; G0 = apply(G,i->sub(i,T1)); G1 = apply(gens H1,v->phi1(v)); assert(G0==G1) /// TEST /// V={{0,0},{0,1},{-1,-1},{1,0}}; F={{0,1,2},{0,2,3},{0,1,3}}; R=QQ[x,y]; phi=stanleyReisnerPresentation(V,F,1,BaseRing=>R,Homogenize=>false); H=source phi; SR=target phi; assert(phi(H_0)==(-SR_1+SR_2)) assert(phi(H_1)==(SR_0-SR_1)) assert(phi(H_2)==(-SR_1^3+3*SR_1^2*SR_2)) assert(phi(H_3)==(SR_0*SR_1^2-SR_1^3+2*SR_1^2*SR_2)) M=splineModule(V,F,1,Homogenize=>false,BaseRing=>R); phi1=ringStructure(M); H1=source phi1; psi=map(H,H1,gens H); assert((ker phi)==psi(ker phi1)) V={{0,0,0},{1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1}}; F={{0,1,2,3},{0,1,2,6},{0,2,3,4},{0,2,4,6},{0,1,3,5},{0,3,4,5},{0,4,5,6},{0,1,5,6}}; S=QQ[x,y,z]; phi=stanleyReisnerPresentation(V,F,1,BaseRing=>S,Homogenize=>false,Trim=>true); H=source phi; SR=target phi; use SR; assert(apply(gens H,g->phi(g))=={X_0-X_3, X_1-X_4, X_2-X_5, X_2^2, X_1^2, X_3^2}) /// end --may restore to documentation in future iterations --doc /// -- Key -- Splines -- VertexCoordinates -- Regions -- SplineModule -- Headline -- a class for splines (piecewise polynomial functions on subdivisions) -- Description -- Text -- This class is a type of @TO "HashTable"@ that stores information on -- a subdivision $\Delta$ of ${\mathbb R}^n$, given by a set of vertex -- coordinates and a list of facets (and possibly edges), along with a -- module of all splines on $\Delta$ of continuity $r$. -- Example -- V = {{0,0},{1,0},{1,1},{-1,1},{-2,-1},{0,-1}}; -- F = {{0,2,1},{0,2,3},{0,3,4},{0,4,5},{0,1,5}}; -- E = {{0,1},{0,2},{0,3},{0,4},{0,5}}; -- S = splines(V,F,E,1) -- splines in R^2 with smoothness 1 -- SeeAlso -- splines --///