2017-10-21 18:39:23 +00:00
|
|
|
// Package gg implements ginger graph creation, traversal, and (de)serialization
|
|
|
|
package gg
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
// Value represents a value being stored in a Graph. Exactly one field must be
|
|
|
|
// non-nil.
|
2018-01-21 15:39:25 +00:00
|
|
|
type Value struct {
|
2021-12-27 17:11:07 +00:00
|
|
|
Name *string
|
|
|
|
Number *int64
|
|
|
|
Graph *Graph
|
|
|
|
|
|
|
|
// TODO coming soon!
|
|
|
|
// String *string
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
// Equal returns true if the passed in Value is equivalent.
|
|
|
|
func (v Value) Equal(v2 Value) bool {
|
|
|
|
switch {
|
|
|
|
|
|
|
|
case v.Name != nil && v2.Name != nil && *v.Name == *v2.Name:
|
|
|
|
return true
|
|
|
|
|
|
|
|
case v.Number != nil && v2.Number != nil && *v.Number == *v2.Number:
|
|
|
|
return true
|
|
|
|
|
|
|
|
case v.Graph != nil && v2.Graph != nil && Equal(v.Graph, v2.Graph):
|
|
|
|
return true
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false
|
2018-01-21 15:39:25 +00:00
|
|
|
}
|
2017-11-24 18:05:58 +00:00
|
|
|
}
|
|
|
|
|
2021-12-26 21:49:22 +00:00
|
|
|
// VertexType enumerates the different possible vertex types.
|
2017-10-21 18:39:23 +00:00
|
|
|
type VertexType string
|
|
|
|
|
|
|
|
const (
|
2018-01-21 15:39:25 +00:00
|
|
|
// ValueVertex is a Vertex which contains exactly one value and has at least
|
2021-12-26 21:49:22 +00:00
|
|
|
// one edge (either input or output).
|
2018-01-21 15:39:25 +00:00
|
|
|
ValueVertex VertexType = "value"
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-08-27 03:26:24 +00:00
|
|
|
// TupleVertex is a Vertex which contains two or more in edges and
|
2018-01-21 15:39:25 +00:00
|
|
|
// exactly one out edge
|
2021-08-27 03:26:24 +00:00
|
|
|
//
|
|
|
|
// TODO ^ what about 0 or 1 in edges?
|
|
|
|
TupleVertex VertexType = "tuple"
|
2017-10-21 18:39:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2017-11-05 16:11:05 +00:00
|
|
|
// OpenEdge is an un-realized Edge which can't be used for anything except
|
2017-10-21 18:39:23 +00:00
|
|
|
// constructing graphs. It has no meaning on its own.
|
2017-11-05 16:11:05 +00:00
|
|
|
type OpenEdge struct {
|
2017-10-21 18:39:23 +00:00
|
|
|
fromV vertex
|
2018-01-21 15:39:25 +00:00
|
|
|
val Value
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2017-11-05 16:11:05 +00:00
|
|
|
// ValueOut creates a OpenEdge which, when used to construct a Graph, represents
|
2018-01-21 15:39:25 +00:00
|
|
|
// an edge (with edgeVal attached to it) coming from the ValueVertex containing
|
2017-10-21 18:39:23 +00:00
|
|
|
// val.
|
|
|
|
//
|
2018-01-21 15:39:25 +00:00
|
|
|
// When constructing Graphs, Value vertices are de-duplicated on their Value. So
|
2017-11-05 16:11:05 +00:00
|
|
|
// multiple ValueOut OpenEdges constructed with the same val will be leaving the
|
2017-10-21 18:39:23 +00:00
|
|
|
// same Vertex instance in the constructed Graph.
|
2018-01-21 15:39:25 +00:00
|
|
|
func ValueOut(val, edgeVal Value) OpenEdge {
|
2018-06-07 02:21:44 +00:00
|
|
|
return OpenEdge{fromV: mkVertex(ValueVertex, val), val: edgeVal}
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2021-08-27 03:26:24 +00:00
|
|
|
// TupleOut creates an OpenEdge which, when used to construct a Graph,
|
2018-01-21 15:39:25 +00:00
|
|
|
// represents an edge (with edgeVal attached to it) coming from the
|
2021-08-27 03:26:24 +00:00
|
|
|
// TupleVertex comprised of the given ordered-set of input edges.
|
2017-10-21 18:39:23 +00:00
|
|
|
//
|
2021-08-27 03:26:24 +00:00
|
|
|
// When constructing Graphs Tuple vertices are de-duplicated on their input
|
|
|
|
// edges. So multiple Tuple OpenEdges constructed with the same set of input
|
|
|
|
// edges will be leaving the same Tuple instance in the constructed Graph.
|
|
|
|
func TupleOut(ins []OpenEdge, edgeVal Value) OpenEdge {
|
2017-11-05 16:11:05 +00:00
|
|
|
return OpenEdge{
|
2021-08-27 03:26:24 +00:00
|
|
|
fromV: mkVertex(TupleVertex, Value{}, ins...),
|
2018-01-23 13:32:11 +00:00
|
|
|
val: edgeVal,
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
func (oe OpenEdge) equal(oe2 OpenEdge) bool {
|
|
|
|
return oe.val.Equal(oe2.val) && oe.fromV.equal(oe2.fromV)
|
|
|
|
}
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
type vertex struct {
|
|
|
|
VertexType
|
|
|
|
val Value
|
|
|
|
tup []OpenEdge
|
|
|
|
}
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
func mkVertex(typ VertexType, val Value, tupIns ...OpenEdge) vertex {
|
|
|
|
return vertex{
|
|
|
|
VertexType: typ,
|
|
|
|
val: val,
|
|
|
|
tup: tupIns,
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
2021-12-27 17:11:07 +00:00
|
|
|
}
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
func (v vertex) equal(v2 vertex) bool {
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
if v.VertexType != v2.VertexType {
|
|
|
|
return false
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
if v.VertexType == ValueVertex {
|
|
|
|
return v.val.Equal(v2.val)
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
if len(v.tup) != len(v2.tup) {
|
2017-10-22 17:39:32 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
for i := range v.tup {
|
|
|
|
if !v.tup[i].equal(v2.tup[i]) {
|
2017-10-22 17:39:32 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
return true
|
|
|
|
}
|
2017-10-22 17:39:32 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
type graphValueIn struct {
|
|
|
|
val Value
|
|
|
|
edges []OpenEdge
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
func (valIn graphValueIn) cp() graphValueIn {
|
|
|
|
cp := valIn
|
|
|
|
cp.edges = make([]OpenEdge, len(valIn.edges))
|
|
|
|
copy(cp.edges, valIn.edges)
|
|
|
|
return valIn
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
func (valIn graphValueIn) equal(valIn2 graphValueIn) bool {
|
|
|
|
if !valIn.val.Equal(valIn2.val) {
|
|
|
|
return false
|
2018-06-07 02:21:44 +00:00
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
if len(valIn.edges) != len(valIn2.edges) {
|
|
|
|
return false
|
2018-06-07 02:21:44 +00:00
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
outer:
|
|
|
|
for _, edge := range valIn.edges {
|
|
|
|
|
|
|
|
for _, edge2 := range valIn2.edges {
|
|
|
|
|
|
|
|
if edge.equal(edge2) {
|
|
|
|
continue outer
|
2018-06-07 02:21:44 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-27 17:11:07 +00:00
|
|
|
|
|
|
|
return false
|
2018-06-07 02:21:44 +00:00
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
return true
|
|
|
|
}
|
2018-06-07 02:21:44 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
// Graph is an immutable container of a set of vertices. The Graph keeps track
|
|
|
|
// of all Values which terminate an OpenEdge (which may be a tree of Value/Tuple
|
|
|
|
// vertices).
|
|
|
|
//
|
|
|
|
// NOTE The current implementation of Graph is incredibly inefficient, there's
|
|
|
|
// lots of O(N) operations, unnecessary copying on changes, and duplicate data
|
|
|
|
// in memory.
|
|
|
|
type Graph struct {
|
|
|
|
valIns []graphValueIn
|
|
|
|
}
|
2018-06-07 02:21:44 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
// ZeroGraph is the root empty graph, and is the base off which all graphs are
|
|
|
|
// built.
|
|
|
|
var ZeroGraph = &Graph{}
|
2018-06-07 02:21:44 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
func (g *Graph) cp() *Graph {
|
|
|
|
cp := &Graph{
|
|
|
|
valIns: make([]graphValueIn, len(g.valIns)),
|
2018-06-07 02:21:44 +00:00
|
|
|
}
|
2021-12-27 17:11:07 +00:00
|
|
|
copy(cp.valIns, g.valIns)
|
|
|
|
return cp
|
2018-06-07 02:21:44 +00:00
|
|
|
}
|
|
|
|
|
2017-10-21 18:39:23 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2021-12-27 17:11:07 +00:00
|
|
|
// Graph creation
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
func (g *Graph) valIn(val Value) graphValueIn {
|
|
|
|
for _, valIn := range g.valIns {
|
|
|
|
if valIn.val.Equal(val) {
|
|
|
|
return valIn
|
|
|
|
}
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
return graphValueIn{val: val}
|
|
|
|
}
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
// AddValueIn takes a OpenEdge and connects it to the Value Vertex containing
|
|
|
|
// val, returning the new Graph which reflects that connection. Any Vertices
|
|
|
|
// referenced within toe OpenEdge which do not yet exist in the Graph will also
|
|
|
|
// be created in this step.
|
|
|
|
func (g *Graph) AddValueIn(oe OpenEdge, val Value) *Graph {
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
valIn := g.valIn(val)
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
for _, existingOE := range valIn.edges {
|
|
|
|
if existingOE.equal(oe) {
|
|
|
|
return g
|
2017-10-21 18:39:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
valIn = valIn.cp()
|
|
|
|
valIn.edges = append(valIn.edges, oe)
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
g = g.cp()
|
2017-10-21 18:39:23 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
for i, existingValIn := range g.valIns {
|
|
|
|
if existingValIn.val.Equal(val) {
|
|
|
|
g.valIns[i] = valIn
|
|
|
|
return g
|
|
|
|
}
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
2021-12-27 17:11:07 +00:00
|
|
|
|
|
|
|
g.valIns = append(g.valIns, valIn)
|
|
|
|
return g
|
2017-10-22 17:39:32 +00:00
|
|
|
}
|
|
|
|
|
2021-12-26 21:49:22 +00:00
|
|
|
// Equal returns whether or not the two Graphs are equivalent in value.
|
2017-10-21 18:39:23 +00:00
|
|
|
func Equal(g1, g2 *Graph) bool {
|
2021-12-27 17:11:07 +00:00
|
|
|
|
|
|
|
if len(g1.valIns) != len(g2.valIns) {
|
2017-10-21 18:39:23 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
outer:
|
|
|
|
for _, valIn1 := range g1.valIns {
|
2017-11-05 16:57:57 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
for _, valIn2 := range g2.valIns {
|
2018-03-03 17:32:40 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
if valIn1.equal(valIn2) {
|
|
|
|
continue outer
|
2017-11-05 16:57:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
return false
|
2017-11-05 16:57:57 +00:00
|
|
|
}
|
2017-12-03 19:38:53 +00:00
|
|
|
|
2021-12-27 17:11:07 +00:00
|
|
|
return true
|
2017-12-03 19:38:53 +00:00
|
|
|
}
|