This is an introduction to the implementation of two-complexes, including issues with scala, ending with constructing a torus. To start with we load the compiled code.
import $cp.bin.`superficial-c3516ca6f4.jar`
import superficial._
The code for vertices is rather simple.
class Vertex
Let us first create a vertex. As it has no abstract methods, we can just ask for a new one.
val v0 = new Vertex
Alternatively, we can declare a new object.
object v1 extends Vertex
3: Int
v1 : v1.type
Edges come in pairs, an edge and the same with the opposite orientation (i.e., flipped). Further, each edge has an initial and terminal vertex. We can also describe the boundary as a formal sum. This is trait, i.e., an abstract class. This means some of its fields are undefined, and have to be defined in a subclass/object with this trait.
trait Edge {
/**
* the same edge with the opposite orientation.
*/
def flip: Edge
def terminal: Vertex
def initial: Vertex
def del : FormalSum[Vertex] = FormalSum.reduced(Vector(terminal -> 1, initial -> -1))
}
We construct a loop at v0
, i.e., an edge beginning and ending at v0
. But note that we cannot construct just one, as we need to flip it. Instead we will construct a pair of edges, each a flip of the other.
object E1 extends Edge{
lazy val flip = E2
val terminal = v0
val initial = v0
}
object E2 extends Edge{
lazy val flip = E1
val terminal = v0
val initial = v0
}
Note a key feature above - we have defined the flip of each of the edges as lazy val
. This means this is not computed until it is needed. Otherwise defining each of E1
and E2
leads to an infinite loop.
We can see some computations on demand.
E1.flip
E1.flip == E2
E1.flip.flip == E1
E1 == E2
We now turn to constructing a torus. Recall that this has a single vertex, two edges that become loops and a single face. We will follow the same pattern as above but give things nicer names. We will also make objects case object
definitions. This means the names are cleaner (as is equality).
case object V extends Vertex
case object VV extends Vertex
V == VV
case class VC() extends Vertex
case class VVC() extends Vertex
VC() == VVC()
VC() == VC()
case object A extends Edge{
lazy val flip = Abar
val terminal = V
val initial = V
}
case object Abar extends Edge{
lazy val flip = A
val terminal = V
val initial = V
}
case object B extends Edge{
lazy val flip = Bbar
val terminal = V
val initial = V
}
case object Bbar extends Edge{
lazy val flip = B
val terminal = V
val initial = V
}
A.flip
Abar.flip
Now we construct the face of the torus. Here is an extract from the code for defining a polygon. We have omitted concrete methods, i.e., methods in the trait that are defined, so need not be implemented in subclasses/objects.
trait Polygon extends TwoComplex {
val sides: Int
val boundary: Vector[Edge]
val vertices: Set[Vertex]
}
Note that this is a two-complex, so we are constructing a torus.
case object Torus extends Polygon{
val sides = 4
val boundary = Vector(A, B, Abar, Bbar)
val vertices = Set(V)
}
Torus.faces
Torus.edges
Torus.boundary
Note that there are subclasses that let us construct more directly, but for now (i.e. as of Jan 13, 2020) they are not sufficient. We took a more direct approach to illustrate the structures.