The attached file contains my first tentative experiments with what I thought of as Finite Topology. Could you take a quick glance at it to see if that's what you would describe as Finite Topology, if not could you suggest an alternative name?
Anyway its the subject that interests me at the moment and I think it should keep me busy for a few years. Despite what you say about the usefulness of 'geometric realization' I would still like to attempt to implement it, just for completeness and my own education. I realise that n points will produce 2*n+1 dimensions but FriCAS can handle high dimensional matrix algebra, right? That's one of the advantages of doing this on a CAS. My reason for looking at databases for the representation was not performance but because the database structure seems to match the mathematical structure better. For instance a minimal complex might be a graph which is two tables (nodes and edges) and you could use common keys or indexes for the source and target relations between the tables. But more importantly I am looking for a way to abstract out topological constructs such as sheaf and fibration. It will take me some time to work though the other issues you mention. As Ralf suggests I will email him off this list about the 'style guide' issues in case my questions here are getting annoying. Martin -- You received this message because you are subscribed to the Google Groups "FriCAS - computer algebra system" group. To unsubscribe from this group and stop receiving emails from it, send an email to fricas-devel+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/fricas-devel/23e80480-daa0-43b8-97bc-d0ce01c19e2e%40martinb.com.
-- to compile -- )co fricas/topology.spad -- -- To test out: -- test OpenSet -- a := openSet [1,2,3] -- b := openSet [1,2] -- c := openSet [2,4] -- product(shift(a,4),b) -- intersection(a,c) -- union(a,c) -- -- test TopologyFinite -- x := topologyFiniteLeftOrder(3) -- y := topologyFiniteDiscrete(3) -- product(x,y) -- -- test TopoSpaceFinite -- topoSpaceFiniteTrivial(["a","b"]) -- topoSpaceFiniteDiscrete(["a","b","c"]) -- y := topologyFiniteLeftOrder(3) -- y := topologyFiniteDiscrete(3) -- full2basis y -- basis2full y -- x := topoSpaceFiniteLeftOrder(["a","b","c"]) -- y := topoSpaceFiniteLeftOrder(["d","e"]) -- product(x,y) -- nerveConstruction(x) )abbrev domain OPENSET OpenSet ++ Author: Martin Baker ++ Description: ++ An open set. ++ Modeled using natural numbers (NNI), this is so that ++ they can be used to index other sets, it does not ++ imply a total order of the sets containing them. ++ for more documentation see: ++ References: ++ http://www.euclideanspace.com/maths/topology/algtop/ OpenSet() : Exports == Impl where NNI==> NonNegativeInteger x<<y ==> hconcat(x::OutputForm, y::OutputForm) Exports ==> Join(SetCategory,PartialOrder) with openSet : (List NNI) -> % ++ constructor from list getOpenSetAsList : (t:%) -> List(NNI) intersection : (a:%, b:%) -> % ++ intersection with degenerates removed union : (a:%, b:%) -> % ++ union with degenerates removed product : (a : %, b : %) -> % shift : (a : %, distance : NNI) -> % getDimension : (a : %) -> NNI addIfNew : (a : List %, b : %) -> List % isEmpty? : (a:%) -> Boolean Impl ==> add -- A set and a topology on it. Rep := List NNI -- constructor openSet(a : List NNI) : % == [sort a] getOpenSetAsList(t:%) : List(NNI) == t::Rep -- display as set coerce(x : %) : OutputForm == x1:List NNI := x::Rep brace [a::OutputForm for a in x1] -- true if a contained in b -- generates logic of inclusions _<_=(a:%,b:%) : Boolean == for x in a::Rep repeat if not member?(x, b::Rep) then return false true -- true if they contain the same elements -- ignore degenerate (multiple copies) elements _=(a:%,b:%) : Boolean == for x in a::Rep repeat if not member?(x, b::Rep) then return false for x in b::Rep repeat if not member?(x, a::Rep) then return false true -- intersection with degenerates removed intersection(a:%, b:%) : % == res:List NNI := empty for x in a::Rep repeat for y in b::Rep repeat if x=y and not member?(x, res) then res:=concat(res,x) res -- union with degenerates removed union(a:%, b:%) : % == res:List NNI := empty for x in a::Rep repeat if not member?(x, res) then res:=concat(res,x) for x in b::Rep repeat if not member?(x, res) then res:=concat(res,x) sort res product(a : %, b : %) : % == -- should check that a and b are disjoint concat(a,b) shift(a : %, distance : NNI) : % == [x+distance for x in a] getDimension(a : %) : NNI == top1:List NNI := a::Rep #top1 addIfNew(a : List %, b : %) : List % == if empty?(b) then return a sorted : List(NNI) := sort(b::Rep) if member?(sorted, a) then return a concat(a, sorted) isEmpty?(a:%) : Boolean == isEmpty?(a::Rep) )abbrev domain TOPFIN TopologyFinite ++ Author: Martin Baker ++ Description: ++ A set of open sets. ++ Can also be thought of as a subset of the power set. ++ It may be sufficient to use only a basis where the full ++ topology can be reconstructed from it. ++ for more documentation see: ++ References: ++ http://www.euclideanspace.com/maths/topology/algtop/ TopologyFinite() : Exports == Impl where NNI==> NonNegativeInteger x<<y ==> hconcat(x::OutputForm, y::OutputForm) Exports ==> SetCategory() with topologyFinite : (List List NNI) -> % ++ constructor topologyFiniteTrivial : () -> % ++ Constructor for trivial topology ++ Only empty(doesn't need to be explicitly included) and full open sets topologyFiniteDiscrete : (dim:NNI) -> % ++ Constructor for discrete topology ++ includes all open sets ++ Don't need to explicitly include empty topologyFiniteLeftOrder : (dim:NNI) -> % ++ Constructor for order topology ++ The order topology may be considered on partially ordered sets as ++ well as linearly ordered sets ++ The open sets are {x | x<b} where b is 1..max ++ On a linearly ordered set it coincides with the interval topology getTopology : (a:%) -> List List NNI full2basis : (a:%) -> % ++ Remove non-basis open sets ++ That is, for each element, only the smallest open set that includes it. basis2full : (a:%) -> % ++ Add all unions of open sets not already included coerce : (x : %) -> OutputForm ++ display as symbols intersection : (a:%, b:%) -> % union : (a:%, b:%) -> % ++ union with degenerates removed getDimension : (a : %) -> NNI product : (a : %, b : %) -> % nerveConstruction : (a : %) -> FiniteSimplicialComplex(Integer) ++ A nerve construction creates a simplicial complex with the ++ topological properties of a given set family. ++ The nerve construction is based on a cover of the set family ++ The resulting complex is a discrete representation of that cover. Impl ==> add -- A set and a topology on it. Rep := Record(basis:Boolean,topology:List OpenSet) getTopologyAsList(t:List OpenSet) : List(List(NNI)) == [getOpenSetAsList(a) for a in t] setTopologyFromList(t:List(List(NNI))) : List OpenSet == [openSet(a) for a in t] -- constructor topologyFinite(a : List List NNI) : % == [false,setTopologyFromList(a)] topologyFiniteTrivial() : % == [false,empty] -- local function to add if new addIfNew(lst : List(List(NNI)), unsorted : List(NNI)) : List(List(NNI)) == if empty?(unsorted) then return lst sorted : List(NNI) := sort(unsorted) if member?(sorted, lst) then return lst concat(lst, sorted) -- generate discrete topology genDiscreteTopology(lst : List(List(NNI)),level : NNI, thisOpenSet : List(NNI), dim : NNI) : List(List(NNI)) == -- print(message "genDiscreteTopology(" << lst << message "," -- << level << message "," << thisOpenSet << message "," << dim << message ")") top1:List List NNI := lst for i in 1..dim repeat openset1 : List NNI := [i] if not member?(i,thisOpenSet) then -- print(message "genDiscreteTopology not member(" << thisOpenSet << message "," -- << i << message ")") openset2 : List(NNI) := concat(thisOpenSet,openset1) if (level+1)<dim then top1 := genDiscreteTopology(top1,level+1,openset2,dim) top1 := addIfNew(top1,openset2) top1 topologyFiniteDiscrete(dim:NNI) : % == top1:List List NNI := empty top1 := genDiscreteTopology(top1,1,empty,dim) [false,setTopologyFromList(top1)] -- generate order topology genOrderTopology(lst : List(List(NNI)),level : NNI, thisOpenSet : List(NNI), dim : NNI) : List(List(NNI)) == -- print(message "genOrderTopology(" << lst << message "," -- << level << message "," << thisOpenSet << message "," << dim << message ")") top1:List List NNI := lst openset1:List NNI := [] for i in 1..dim repeat -- print(message "genOrderTopology loop(" << top1 << message "," << i << message ")") openset1 := concat(openset1,[i]) top1 := concat(top1,openset1) top1 -- generate order topology topologyFiniteLeftOrder(dim:NNI) : % == top1:List List NNI := empty top1 := genOrderTopology(top1,1,empty,dim) [false,setTopologyFromList(top1)] getTopology(a:%) : List List NNI == getTopologyAsList(a.topology) -- To find a basis: for every element of the set find the smallest -- open set that contains it. -- Remove non-basis open sets -- That is, for each element, only the smallest open set that includes it. full2basis(a:%) : % == -- assume number of elements is maximum index numEle:NNI := 0 top1:List List NNI := getTopologyAsList(a.topology) for x in top1 repeat for y in x repeat if y>numEle then numEle:=y basisSets:List List NNI := empty for currEle in 1..numEle repeat basisCandidate:List NNI := empty minSize:NNI := 0 for currOpenSet in top1 repeat currSize:NNI := #currOpenSet if member?(currEle,currOpenSet) and not empty?(currOpenSet) and (minSize=0 or currSize < minSize) then --print(message "adding" << currOpenSet << message " minSize=" -- << minSize << message " currEle=" << currEle) basisCandidate := currOpenSet minSize := #currOpenSet basisSets := addIfNew(basisSets,basisCandidate) [true,setTopologyFromList(basisSets)] unionLocal(a:List NNI, b:List NNI) : List NNI == res:List NNI := a for x in b repeat if not member?(x, res) then res:=concat(res, x) res -- Add all unions of open sets not already included basis2full(a:%) : % == top1:List List NNI := getTopologyAsList(a.topology) top2:List List NNI := copy(top1) -- so we dont alter top1 inside loop for x in top1 repeat for y in top1 repeat z : List NNI := sort (unionLocal(x,y)) top2 := addIfNew(top2,z) -- print(message "x=" << x << message " y=" -- << y << message " union=" << z) [false,setTopologyFromList(top2)] -- no access to symbols here -- --symboliseList(topol1 : List NNI) : OutputForm == -- res:List OutputForm := empty -- for a in topol1 repeat -- val:OutputForm := (a::OutputForm) -- res := concat(res,val) -- bracket res -- display coerce(x : %) : OutputForm == x1:List OpenSet := x.topology msg:OutputForm := if x.basis then message "basis=" else message "topology=" msg << bracket[(a::OutputForm) for a in x1] "="(a:%,b:%) : Boolean == a=b -- intersection intersection(a:%, b:%) : % == -- sort(setIntersection(a,b)) a -- union with degenerates removed union(a:%, b:%) : % == -- removeDuplicates!(merge("<",a,b)) a getDimension(a : %) : NNI == numEle:NNI := 0 top1:List OpenSet := a.topology for x in top1 repeat if getDimension(x) > numEle then numEle := getDimension(x) numEle product(a : %, b : %) : % == top1:List OpenSet := (full2basis a).topology top2:List OpenSet := (full2basis b).topology -- following only works for full not basis sizea:NNI := getDimension(a) sizeb:NNI := getDimension(a) top2s:List OpenSet := [shift(x,sizea) for x in top2] res:List OpenSet := empty for x in top1 repeat for y in top2s repeat res := concat(res,product(x,y)) [true,res] -- https://sauln.github.io/blog/towers-nerves/ -- A nerve construction creates a simplicial complex with the -- topological properties of a given set family. -- The nerve construction is based on a cover of the set family -- The resulting complex is a discrete representation of that cover. nerveConstruction(a : %) : FiniteSimplicialComplex(Integer) == -- For each nonempty intersection of n elements in the cover, -- add an (n-1)-dimensional simplex. top1:List OpenSet := (a::Rep).topology intersections:List OpenSet := empty for x in top1 repeat for y in top1 repeat intersec:OpenSet := intersection(x,y) intersections := addIfNew(intersections,intersec) -- print(message "x=" << x << message " y=" -- << y << message " intersec=" << intersec) -- print(message "intersections=" << intersections ) -- Add a vertex for each element in the cover. -- Add an edge between two vertices if the corresponding sets overlap. leng:NNI := #intersections eles:List Integer := [x for x in 1..leng] top1:List List NNI := getTopologyAsList(intersections) simplicialComplex(eles,top1) )abbrev domain TOPOSP TopoSpaceFinite ++ Author: Martin Baker ++ Description: ++ TopoSpaceFinite topological space as set + opensets. ++ for more documentation see: ++ References: ++ http://www.euclideanspace.com/maths/topology/algtop/ TopoSpaceFinite() : Exports == Impl where NNI==> NonNegativeInteger x<<y ==> hconcat(x::OutputForm, y::OutputForm) Exports ==> SetCategory() with topologyFinite : (List Symbol) -> % ++ constructor topoSpaceFiniteTrivial : (List String) -> % ++ Constructor for trivial topology ++ Only empty and full open sets (don't need to be explicitly included) topoSpaceFiniteDiscrete : (List String) -> % ++ Constructor for discrete topology ++ includes all open sets ++ Don't need to explicitly include empty and full set topoSpaceFiniteLeftOrder : (List String) -> % ++ Constructor for order topology ++ The order topology may be considered on partially ordered sets as ++ well as linearly ordered sets ++ The open sets are {x | x<b} where b is 1..max ++ On a linearly ordered set it coincides with the interval topology coerce : (x : %) -> OutputForm ++ display as symbols -- equivalenceRelation : (a : %,va : NNI,vb : NNI) -> OutputForm intersection : (a:%, b:%) -> % union : (a:%, b:%) -> % ++ union with degenerates removed product : (a : %, b : %) -> % ++ The product topology is the coarsest topology (the topology ++ with the fewest open sets) which still has continuous projections ++ to the input topologies. nerveConstruction : (a : %) -> FiniteSimplicialComplex(Integer) ++ A nerve construction creates a simplicial complex with the ++ topological properties of a given set family. ++ The nerve construction is based on a cover of the set family ++ The resulting complex is a discrete representation of that cover. Impl ==> add -- A set and a topology on it. Rep := Record(topSet : List Symbol, topol : TopologyFinite) -- constructor topoSpaceFinite(a : List Symbol) : % == [a,topologyFiniteTrivial()] topoSpaceFiniteTrivial(x1 : List String) : % == [[a::Symbol for a in x1],topologyFiniteTrivial()] -- local function to add if new addIfNew(lst : List(List(NNI)), unsorted : List(NNI)) : List(List(NNI)) == if empty?(unsorted) then return lst sorted : List(NNI) := sort(unsorted) if member?(sorted, lst) then return lst concat(lst, sorted) -- generate discrete topology genDiscreteTopology(lst : List(List(NNI)),level : NNI, thisOpenSet : List(NNI), dim : NNI) : List(List(NNI)) == -- print(message "genDiscreteTopology(" << lst << message "," -- << level << message "," << thisOpenSet << message "," << dim << message ")") top1:List List NNI := lst for i in 1..dim repeat openset1 : List NNI := [i] if not member?(i,thisOpenSet) then -- print(message "genDiscreteTopology not member(" << thisOpenSet << message "," -- << i << message ")") openset2 : List(NNI) := concat(thisOpenSet,openset1) if (level+1)<dim then top1 := genDiscreteTopology(top1,level+1,openset2,dim) top1 := addIfNew(top1,openset2) top1 topoSpaceFiniteDiscrete(x1 : List String) : % == dim1:NNI := #x1 -- top1:List List NNI := empty -- top1 := genDiscreteTopology(top1,1,empty,dim1) [[a::Symbol for a in x1],topologyFiniteDiscrete(dim1)] -- generate order topology genOrderTopology(lst : List(List(NNI)),level : NNI, thisOpenSet : List(NNI), dim : NNI) : List(List(NNI)) == -- print(message "genOrderTopology(" << lst << message "," -- << level << message "," << thisOpenSet << message "," << dim << message ")") top1:List List NNI := lst openset1:List NNI := [] for i in 1..dim repeat -- print(message "genOrderTopology loop(" << top1 << message "," << i << message ")") openset1 := concat(openset1,[i]) top1 := concat(top1,openset1) top1 -- generate order topology topoSpaceFiniteLeftOrder(x1 : List String) : % == dim1:NNI := #x1 -- top1:List List NNI := empty -- top1 := genOrderTopology(top1,1,empty,dim1) [[a::Symbol for a in x1],topologyFiniteLeftOrder(dim1)] symboliseList(topSet1 : List Symbol, topol1 : List NNI) : OutputForm == res:List OutputForm := empty for a in topol1 repeat val:OutputForm := ((topSet1.a)::OutputForm) res := concat(res,val) bracket res -- display as symbols coerce(x : %) : OutputForm == x1:List Symbol := x.topSet topSet1:OutputForm := bracket[a::OutputForm for a in x1] -- x2:List List NNI := (x.topol)::Rep -- topol2:OutputForm := bracket[symboliseList(x1,a) for a in x2] -- bracket[topSet1,topol2] bracket[topSet1,(x.topol)::OutputForm] "="(a:%,b:%) : Boolean == a=b -- intersection intersection(a:%, b:%) : % == -- sort(setIntersection(a,b)) a -- union with degenerates removed union(a:%, b:%) : % == -- removeDuplicates!(merge("<",a,b)) a -- The product topology is the coarsest topology (the topology -- with the fewest open sets) which still has continuous projections -- to the input topologies. product(a : %, b : %) : % == a1:List Symbol := a.topSet b1:List Symbol := b.topSet -- convert inputs to basis a2:TopologyFinite := full2basis(a.topol) b2:TopologyFinite := full2basis(b.topol) -- Cartesian product of sets pairs:List(Record(left : Symbol, right : Symbol)) := empty for sa in a1 repeat for sb in b1 repeat pair:Record(left : Symbol, right : Symbol) := [sa,sb] pairs := concat(pairs,pair) print(message "points=" << pairs) topols:List(Record(tl : List(NNI), tr : List(NNI))) := empty for ta in getTopology(a2) repeat for tb in getTopology(b2) repeat topol:Record(tl : List(NNI), tr : List(NNI)) := [ta,tb] topols := concat(topols,topol) print(message "topols=" << topols) [a1,a2] -- https://sauln.github.io/blog/towers-nerves/ -- A nerve construction creates a simplicial complex with the -- topological properties of a given set family. -- The nerve construction is based on a cover of the set family -- The resulting complex is a discrete representation of that cover. nerveConstruction(a : %) : FiniteSimplicialComplex(Integer) == -- For each nonempty intersection of n elements in the cover, -- add an (n-1)-dimensional simplex. a1:TopologyFinite := a.topol nerveConstruction(a1) )abbrev domain CONTMAP ContinuousMap ++ Author: Martin Baker ++ Description: ++ A continuous map between two topological spaces ++ for more documentation see: ++ References: ++ http://www.euclideanspace.com/maths/topology/algtop/ ContinuousMap(DOMAIN:TopoSpaceFinite,CODOMAIN:TopoSpaceFinite) : Exports == Impl where NNI==> NonNegativeInteger x<<y ==> hconcat(x::OutputForm, y::OutputForm) Exports ==> SetCategory() with continuousMap : (im:Table(NNI,NNI),preIm:Table(NNI,NNI)) -> % Impl ==> add -- The image holds a map of the points in the forward direction. -- The pre-image holds a map of the open sets in the reverse direction. Rep := Record(image:Table(NNI,NNI),preImage:Table(NNI,NNI)) -- constructor continuousMap(im:Table(NNI,NNI),preIm:Table(NNI,NNI)) : % == [im,preIm]