refacctor gg to use Value instead of Identifier, which will make serializing more straightforward, and reduces some complexity of the code besides
This commit is contained in:
parent
754b75407a
commit
e52befb7ed
181
gg/gg.go
181
gg/gg.go
@ -2,63 +2,62 @@
|
|||||||
package gg
|
package gg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/md5"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO instead of Identifier being public, make it encoding.TextMarshaler
|
// Value wraps a go value in a way such that it will be uniquely identified
|
||||||
|
// within any Graph and between Graphs. Use NewValue to create a Value instance.
|
||||||
// Identifier is implemented by any value which can return a unique string for
|
// You can create an instance manually as long as ID is globally unique.
|
||||||
// itself via an Identify method
|
type Value struct {
|
||||||
type Identifier interface {
|
ID string
|
||||||
Identify(hash.Hash)
|
V interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func identify(i Identifier) string {
|
// NewValue returns a Value instance wrapping any go value. The Value returned
|
||||||
h := md5.New()
|
// will be independent of the passed in go value. So if the same go value is
|
||||||
i.Identify(h)
|
// passed in twice then the two returned Value instances will be treated as
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
// being different values by Graph.
|
||||||
|
func NewValue(V interface{}) Value {
|
||||||
|
b := make([]byte, 8)
|
||||||
|
if _, err := rand.Read(b); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return Value{
|
||||||
|
ID: hex.EncodeToString(b),
|
||||||
|
V: V,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Str is an Identifier identified by its string value
|
|
||||||
type Str string
|
|
||||||
|
|
||||||
// Identify implements the Identifier interface
|
|
||||||
func (s Str) Identify(h hash.Hash) {
|
|
||||||
fmt.Fprintf(h, "%q", s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// VertexType enumerates the different possible vertex types
|
// VertexType enumerates the different possible vertex types
|
||||||
type VertexType string
|
type VertexType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Value is a Vertex which contains exactly one value and has at least one
|
// ValueVertex is a Vertex which contains exactly one value and has at least
|
||||||
// edge (either input or output)
|
// one edge (either input or output)
|
||||||
Value VertexType = "value"
|
ValueVertex VertexType = "value"
|
||||||
|
|
||||||
// Junction is a Vertex which contains two or more in edges and exactly one
|
// JunctionVertex is a Vertex which contains two or more in edges and
|
||||||
// out edge
|
// exactly one out edge
|
||||||
Junction VertexType = "junction"
|
JunctionVertex VertexType = "junction"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Edge is a uni-directional connection between two vertices with an attribute
|
// Edge is a uni-directional connection between two vertices with an attribute
|
||||||
// value
|
// value
|
||||||
type Edge struct {
|
type Edge struct {
|
||||||
From *Vertex
|
From *Vertex
|
||||||
Value Identifier
|
Value Value
|
||||||
To *Vertex
|
To *Vertex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertex is a vertex in a Graph. No fields should be modified directly, only
|
// Vertex is a vertex in a Graph. No fields should be modified directly, only
|
||||||
// through method calls
|
// through method calls
|
||||||
type Vertex struct {
|
type Vertex struct {
|
||||||
|
ID string
|
||||||
VertexType
|
VertexType
|
||||||
ID string // identifier of the vertex, unique within the graph
|
Value Value // Value is valid if-and-only-if VertexType is ValueVertex
|
||||||
Value Identifier // Value is valid if-and-only-if VertexType is Value
|
|
||||||
In, Out []Edge
|
In, Out []Edge
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,14 +71,11 @@ type OpenEdge struct {
|
|||||||
// already that will need to be taken into account when persisting into the
|
// already that will need to be taken into account when persisting into the
|
||||||
// graph
|
// graph
|
||||||
fromV vertex
|
fromV vertex
|
||||||
val Identifier
|
val Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identify implements the Identifier interface
|
func (oe OpenEdge) id() string {
|
||||||
func (oe OpenEdge) Identify(h hash.Hash) {
|
return fmt.Sprintf("(%s,%s)", oe.fromV.id, oe.val.ID)
|
||||||
fmt.Fprintln(h, "openEdge")
|
|
||||||
oe.fromV.Identify(h)
|
|
||||||
oe.val.Identify(h)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vertex is a representation of a vertex in the graph. Each Graph contains a
|
// vertex is a representation of a vertex in the graph. Each Graph contains a
|
||||||
@ -95,28 +91,12 @@ func (oe OpenEdge) Identify(h hash.Hash) {
|
|||||||
// When a view is constructed in makeView these Value instances are deduplicated
|
// When a view is constructed in makeView these Value instances are deduplicated
|
||||||
// and the top-level one's in value is used to properly connect it.
|
// and the top-level one's in value is used to properly connect it.
|
||||||
type vertex struct {
|
type vertex struct {
|
||||||
|
id string
|
||||||
VertexType
|
VertexType
|
||||||
val Identifier
|
val Value
|
||||||
in []OpenEdge
|
in []OpenEdge
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Value vertex is unique by the value it contains
|
|
||||||
// A Junction vertex is unique by its input edges
|
|
||||||
func (v vertex) Identify(h hash.Hash) {
|
|
||||||
switch v.VertexType {
|
|
||||||
case Value:
|
|
||||||
fmt.Fprintln(h, "value")
|
|
||||||
v.val.Identify(h)
|
|
||||||
case Junction:
|
|
||||||
fmt.Fprintf(h, "junction:%d\n", len(v.in))
|
|
||||||
for _, in := range v.in {
|
|
||||||
in.Identify(h)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("invalid VertexType:%#v", v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v vertex) cp() vertex {
|
func (v vertex) cp() vertex {
|
||||||
cp := v
|
cp := v
|
||||||
cp.in = make([]OpenEdge, len(v.in))
|
cp.in = make([]OpenEdge, len(v.in))
|
||||||
@ -125,9 +105,9 @@ func (v vertex) cp() vertex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v vertex) hasOpenEdge(oe OpenEdge) bool {
|
func (v vertex) hasOpenEdge(oe OpenEdge) bool {
|
||||||
oeID := identify(oe)
|
oeID := oe.id()
|
||||||
for _, in := range v.in {
|
for _, in := range v.in {
|
||||||
if identify(in) == oeID {
|
if in.id() == oeID {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,9 +115,9 @@ func (v vertex) hasOpenEdge(oe OpenEdge) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v vertex) cpAndDelOpenEdge(oe OpenEdge) (vertex, bool) {
|
func (v vertex) cpAndDelOpenEdge(oe OpenEdge) (vertex, bool) {
|
||||||
oeID := identify(oe)
|
oeID := oe.id()
|
||||||
for i, in := range v.in {
|
for i, in := range v.in {
|
||||||
if identify(in) == oeID {
|
if in.id() == oeID {
|
||||||
v = v.cp()
|
v = v.cp()
|
||||||
v.in = append(v.in[:i], v.in[i+1:]...)
|
v.in = append(v.in[:i], v.in[i+1:]...)
|
||||||
return v, true
|
return v, true
|
||||||
@ -168,8 +148,8 @@ func (g *Graph) cp() *Graph {
|
|||||||
cp := &Graph{
|
cp := &Graph{
|
||||||
vM: make(map[string]vertex, len(g.vM)),
|
vM: make(map[string]vertex, len(g.vM)),
|
||||||
}
|
}
|
||||||
for id, v := range g.vM {
|
for vID, v := range g.vM {
|
||||||
cp.vM[id] = v
|
cp.vM[vID] = v
|
||||||
}
|
}
|
||||||
return cp
|
return cp
|
||||||
}
|
}
|
||||||
@ -178,16 +158,17 @@ func (g *Graph) cp() *Graph {
|
|||||||
// Graph creation
|
// Graph creation
|
||||||
|
|
||||||
// ValueOut creates a OpenEdge which, when used to construct a Graph, represents
|
// ValueOut creates a OpenEdge which, when used to construct a Graph, represents
|
||||||
// an edge (with edgeVal attached to it) leaving the Value Vertex containing
|
// an edge (with edgeVal attached to it) coming from the ValueVertex containing
|
||||||
// val.
|
// val.
|
||||||
//
|
//
|
||||||
// When constructing Graphs Value vertices are de-duplicated on their value. So
|
// When constructing Graphs, Value vertices are de-duplicated on their Value. So
|
||||||
// multiple ValueOut OpenEdges constructed with the same val will be leaving the
|
// multiple ValueOut OpenEdges constructed with the same val will be leaving the
|
||||||
// same Vertex instance in the constructed Graph.
|
// same Vertex instance in the constructed Graph.
|
||||||
func ValueOut(val, edgeVal Identifier) OpenEdge {
|
func ValueOut(val, edgeVal Value) OpenEdge {
|
||||||
return OpenEdge{
|
return OpenEdge{
|
||||||
fromV: vertex{
|
fromV: vertex{
|
||||||
VertexType: Value,
|
id: val.ID,
|
||||||
|
VertexType: ValueVertex,
|
||||||
val: val,
|
val: val,
|
||||||
},
|
},
|
||||||
val: edgeVal,
|
val: edgeVal,
|
||||||
@ -195,16 +176,21 @@ func ValueOut(val, edgeVal Identifier) OpenEdge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// JunctionOut creates a OpenEdge which, when used to construct a Graph,
|
// JunctionOut creates a OpenEdge which, when used to construct a Graph,
|
||||||
// represents an edge (with edgeVal attached to it) leaving the Junction Vertex
|
// represents an edge (with edgeVal attached to it) coming from the
|
||||||
// comprised of the given ordered-set of input edges.
|
// JunctionVertex comprised of the given ordered-set of input edges.
|
||||||
//
|
//
|
||||||
// When constructing Graphs Junction vertices are de-duplicated on their input
|
// When constructing Graphs Junction vertices are de-duplicated on their input
|
||||||
// edges. So multiple Junction OpenEdges constructed with the same set of input
|
// edges. So multiple Junction OpenEdges constructed with the same set of input
|
||||||
// edges will be leaving the same Junction instance in the constructed Graph.
|
// edges will be leaving the same Junction instance in the constructed Graph.
|
||||||
func JunctionOut(in []OpenEdge, edgeVal Identifier) OpenEdge {
|
func JunctionOut(in []OpenEdge, edgeVal Value) OpenEdge {
|
||||||
|
inIDs := make([]string, len(in))
|
||||||
|
for i := range in {
|
||||||
|
inIDs[i] = in[i].id()
|
||||||
|
}
|
||||||
return OpenEdge{
|
return OpenEdge{
|
||||||
fromV: vertex{
|
fromV: vertex{
|
||||||
VertexType: Junction,
|
id: "[" + strings.Join(inIDs, ",") + "]",
|
||||||
|
VertexType: JunctionVertex,
|
||||||
in: in,
|
in: in,
|
||||||
},
|
},
|
||||||
val: edgeVal,
|
val: edgeVal,
|
||||||
@ -215,12 +201,13 @@ func JunctionOut(in []OpenEdge, edgeVal Identifier) OpenEdge {
|
|||||||
// val, returning the new Graph which reflects that connection. Any Vertices
|
// 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
|
// referenced within toe OpenEdge which do not yet exist in the Graph will also
|
||||||
// be created in this step.
|
// be created in this step.
|
||||||
func (g *Graph) AddValueIn(oe OpenEdge, val Identifier) *Graph {
|
func (g *Graph) AddValueIn(oe OpenEdge, val Value) *Graph {
|
||||||
to := vertex{
|
to := vertex{
|
||||||
VertexType: Value,
|
id: val.ID,
|
||||||
|
VertexType: ValueVertex,
|
||||||
val: val,
|
val: val,
|
||||||
}
|
}
|
||||||
toID := identify(to)
|
toID := to.id
|
||||||
|
|
||||||
// if to is already in the graph, pull it out, as it might have existing in
|
// if to is already in the graph, pull it out, as it might have existing in
|
||||||
// edges we want to keep
|
// edges we want to keep
|
||||||
@ -241,8 +228,8 @@ func (g *Graph) AddValueIn(oe OpenEdge, val Identifier) *Graph {
|
|||||||
// recursively add in any vertices which aren't already there
|
// recursively add in any vertices which aren't already there
|
||||||
var persist func(vertex)
|
var persist func(vertex)
|
||||||
persist = func(v vertex) {
|
persist = func(v vertex) {
|
||||||
vID := identify(v)
|
if v.VertexType == ValueVertex {
|
||||||
if v.VertexType == Value {
|
vID := v.id
|
||||||
if _, ok := g.vM[vID]; !ok {
|
if _, ok := g.vM[vID]; !ok {
|
||||||
g.vM[vID] = v
|
g.vM[vID] = v
|
||||||
}
|
}
|
||||||
@ -266,12 +253,13 @@ func (g *Graph) AddValueIn(oe OpenEdge, val Identifier) *Graph {
|
|||||||
// the Value Vertex doesn't exist within the graph, or it doesn't have the given
|
// the Value Vertex doesn't exist within the graph, or it doesn't have the given
|
||||||
// OpenEdge, no changes are made. Any vertices referenced by toe OpenEdge for
|
// OpenEdge, no changes are made. Any vertices referenced by toe OpenEdge for
|
||||||
// which that edge is their only outgoing edge will be removed from the Graph.
|
// which that edge is their only outgoing edge will be removed from the Graph.
|
||||||
func (g *Graph) DelValueIn(oe OpenEdge, val Identifier) *Graph {
|
func (g *Graph) DelValueIn(oe OpenEdge, val Value) *Graph {
|
||||||
to := vertex{
|
to := vertex{
|
||||||
VertexType: Value,
|
id: val.ID,
|
||||||
|
VertexType: ValueVertex,
|
||||||
val: val,
|
val: val,
|
||||||
}
|
}
|
||||||
toID := identify(to)
|
toID := to.id
|
||||||
|
|
||||||
// pull to out of the graph. if it's not there then bail
|
// pull to out of the graph. if it's not there then bail
|
||||||
var ok bool
|
var ok bool
|
||||||
@ -293,9 +281,9 @@ func (g *Graph) DelValueIn(oe OpenEdge, val Identifier) *Graph {
|
|||||||
var connectedTo func(string, vertex) bool
|
var connectedTo func(string, vertex) bool
|
||||||
connectedTo = func(vID string, curr vertex) bool {
|
connectedTo = func(vID string, curr vertex) bool {
|
||||||
for _, in := range curr.in {
|
for _, in := range curr.in {
|
||||||
if in.fromV.VertexType == Value && identify(in.fromV) == vID {
|
if in.fromV.VertexType == ValueVertex && in.fromV.id == vID {
|
||||||
return true
|
return true
|
||||||
} else if in.fromV.VertexType == Junction && connectedTo(vID, in.fromV) {
|
} else if in.fromV.VertexType == JunctionVertex && connectedTo(vID, in.fromV) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,7 +293,7 @@ func (g *Graph) DelValueIn(oe OpenEdge, val Identifier) *Graph {
|
|||||||
// isOrphaned returns whether the given vertex has any connections to other
|
// isOrphaned returns whether the given vertex has any connections to other
|
||||||
// nodes in the graph
|
// nodes in the graph
|
||||||
isOrphaned := func(v vertex) bool {
|
isOrphaned := func(v vertex) bool {
|
||||||
vID := identify(v)
|
vID := v.id
|
||||||
if v, ok := g.vM[vID]; ok && len(v.in) > 0 {
|
if v, ok := g.vM[vID]; ok && len(v.in) > 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -328,11 +316,11 @@ func (g *Graph) DelValueIn(oe OpenEdge, val Identifier) *Graph {
|
|||||||
// Vertices referenced in it which are now orphaned
|
// Vertices referenced in it which are now orphaned
|
||||||
var rmOrphaned func(OpenEdge)
|
var rmOrphaned func(OpenEdge)
|
||||||
rmOrphaned = func(oe OpenEdge) {
|
rmOrphaned = func(oe OpenEdge) {
|
||||||
if oe.fromV.VertexType == Value && isOrphaned(oe.fromV) {
|
if oe.fromV.VertexType == ValueVertex && isOrphaned(oe.fromV) {
|
||||||
delete(g.vM, identify(oe.fromV))
|
delete(g.vM, oe.fromV.id)
|
||||||
} else if oe.fromV.VertexType == Junction {
|
} else if oe.fromV.VertexType == JunctionVertex {
|
||||||
for _, juncHe := range oe.fromV.in {
|
for _, juncOe := range oe.fromV.in {
|
||||||
rmOrphaned(juncHe)
|
rmOrphaned(juncOe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,18 +365,17 @@ func (g *Graph) makeView() {
|
|||||||
|
|
||||||
var getV func(vertex, bool) *Vertex
|
var getV func(vertex, bool) *Vertex
|
||||||
getV = func(v vertex, top bool) *Vertex {
|
getV = func(v vertex, top bool) *Vertex {
|
||||||
vID := identify(v)
|
V, ok := g.all[v.id]
|
||||||
V, ok := g.all[vID]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
V = &Vertex{VertexType: v.VertexType, ID: vID, Value: v.val}
|
V = &Vertex{ID: v.id, VertexType: v.VertexType, Value: v.val}
|
||||||
g.all[vID] = V
|
g.all[v.id] = V
|
||||||
}
|
}
|
||||||
|
|
||||||
// we can be sure all Value vertices will be called with top==true at
|
// we can be sure all Value vertices will be called with top==true at
|
||||||
// some point, so we only need to descend into the input edges if:
|
// some point, so we only need to descend into the input edges if:
|
||||||
// * top is true
|
// * top is true
|
||||||
// * this is a junction's first time being gotten
|
// * this is a junction's first time being gotten
|
||||||
if !top && (ok || v.VertexType != Junction) {
|
if !top && (ok || v.VertexType != JunctionVertex) {
|
||||||
return V
|
return V
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,8 +387,8 @@ func (g *Graph) makeView() {
|
|||||||
V.In = append(V.In, e)
|
V.In = append(V.In, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.VertexType == Value {
|
if v.VertexType == ValueVertex {
|
||||||
g.byVal[identify(v.val)] = V
|
g.byVal[v.val.ID] = V
|
||||||
}
|
}
|
||||||
|
|
||||||
return V
|
return V
|
||||||
@ -412,15 +399,15 @@ func (g *Graph) makeView() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value returns the Value Vertex for the given value. If the Graph doesn't
|
// ValueVertex returns the Value Vertex for the given value. If the Graph
|
||||||
// contain a vertex for the value then nil is returned
|
// doesn't contain a vertex for the value then nil is returned
|
||||||
func (g *Graph) Value(val Identifier) *Vertex {
|
func (g *Graph) ValueVertex(val Value) *Vertex {
|
||||||
g.makeView()
|
g.makeView()
|
||||||
return g.byVal[identify(val)]
|
return g.byVal[val.ID]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values returns all Value Vertices in the Graph
|
// ValueVertices returns all Value Vertices in the Graph
|
||||||
func (g *Graph) Values() []*Vertex {
|
func (g *Graph) ValueVertices() []*Vertex {
|
||||||
g.makeView()
|
g.makeView()
|
||||||
vv := make([]*Vertex, 0, len(g.byVal))
|
vv := make([]*Vertex, 0, len(g.byVal))
|
||||||
for _, v := range g.byVal {
|
for _, v := range g.byVal {
|
||||||
|
513
gg/gg_test.go
513
gg/gg_test.go
@ -1,44 +1,30 @@
|
|||||||
package gg
|
package gg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"hash"
|
|
||||||
. "testing"
|
. "testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type idAny struct {
|
func edge(val Value, from *Vertex) Edge {
|
||||||
i interface{}
|
return Edge{Value: val, From: from}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i idAny) Identify(h hash.Hash) {
|
func value(val Value, in ...Edge) *Vertex {
|
||||||
fmt.Fprintln(h, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
func id(i interface{}) Identifier {
|
|
||||||
return idAny{i: i}
|
|
||||||
}
|
|
||||||
|
|
||||||
func edge(val string, from *Vertex) Edge {
|
|
||||||
return Edge{Value: id(val), From: from}
|
|
||||||
}
|
|
||||||
|
|
||||||
func value(val string, in ...Edge) *Vertex {
|
|
||||||
return &Vertex{
|
return &Vertex{
|
||||||
VertexType: Value,
|
VertexType: ValueVertex,
|
||||||
Value: id(val),
|
Value: val,
|
||||||
In: in,
|
In: in,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func junction(val string, in ...Edge) Edge {
|
func junction(val Value, in ...Edge) Edge {
|
||||||
return Edge{
|
return Edge{
|
||||||
From: &Vertex{
|
From: &Vertex{
|
||||||
VertexType: Junction,
|
VertexType: JunctionVertex,
|
||||||
In: in,
|
In: in,
|
||||||
},
|
},
|
||||||
Value: id(val),
|
Value: val,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +60,7 @@ func assertWalk(t *T, expVals, expJuncs int, g *Graph, msgAndArgs ...interface{}
|
|||||||
g.Walk(nil, func(v *Vertex) bool {
|
g.Walk(nil, func(v *Vertex) bool {
|
||||||
assert.NotContains(t, seen, v, msgAndArgs...)
|
assert.NotContains(t, seen, v, msgAndArgs...)
|
||||||
seen[v] = true
|
seen[v] = true
|
||||||
if v.VertexType == Value {
|
if v.VertexType == ValueVertex {
|
||||||
gotVals++
|
gotVals++
|
||||||
} else {
|
} else {
|
||||||
gotJuncs++
|
gotJuncs++
|
||||||
@ -102,122 +88,140 @@ func mkTest(name string, out func() *Graph, numVals, numJuncs int, exp ...*Verte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGraph(t *T) {
|
func TestGraph(t *T) {
|
||||||
|
var (
|
||||||
|
v0 = NewValue("v0")
|
||||||
|
v1 = NewValue("v1")
|
||||||
|
v2 = NewValue("v2")
|
||||||
|
v3 = NewValue("v3")
|
||||||
|
e0 = NewValue("e0")
|
||||||
|
e00 = NewValue("e00")
|
||||||
|
e01 = NewValue("e01")
|
||||||
|
e1 = NewValue("e1")
|
||||||
|
e10 = NewValue("e10")
|
||||||
|
e11 = NewValue("e11")
|
||||||
|
e2 = NewValue("e2")
|
||||||
|
e20 = NewValue("e20")
|
||||||
|
e21 = NewValue("e21")
|
||||||
|
ej0 = NewValue("ej0")
|
||||||
|
ej1 = NewValue("ej1")
|
||||||
|
ej2 = NewValue("ej2")
|
||||||
|
)
|
||||||
tests := []graphTest{
|
tests := []graphTest{
|
||||||
mkTest(
|
mkTest(
|
||||||
"values-basic",
|
"values-basic",
|
||||||
func() *Graph {
|
func() *Graph {
|
||||||
return Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
return Null.AddValueIn(ValueOut(v0, e0), v1)
|
||||||
},
|
},
|
||||||
2, 0,
|
2, 0,
|
||||||
value("v0"),
|
value(v0),
|
||||||
value("v1", edge("e0", value("v0"))),
|
value(v1, edge(e0, value(v0))),
|
||||||
),
|
),
|
||||||
|
|
||||||
mkTest(
|
mkTest(
|
||||||
"values-2edges",
|
"values-2edges",
|
||||||
func() *Graph {
|
func() *Graph {
|
||||||
g0 := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v2"))
|
g0 := Null.AddValueIn(ValueOut(v0, e0), v2)
|
||||||
return g0.AddValueIn(ValueOut(id("v1"), id("e1")), id("v2"))
|
return g0.AddValueIn(ValueOut(v1, e1), v2)
|
||||||
},
|
},
|
||||||
3, 0,
|
3, 0,
|
||||||
value("v0"),
|
value(v0),
|
||||||
value("v1"),
|
value(v1),
|
||||||
value("v2",
|
value(v2,
|
||||||
edge("e0", value("v0")),
|
edge(e0, value(v0)),
|
||||||
edge("e1", value("v1")),
|
edge(e1, value(v1)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
mkTest(
|
mkTest(
|
||||||
"values-separate",
|
"values-separate",
|
||||||
func() *Graph {
|
func() *Graph {
|
||||||
g0 := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
g0 := Null.AddValueIn(ValueOut(v0, e0), v1)
|
||||||
return g0.AddValueIn(ValueOut(id("v2"), id("e2")), id("v3"))
|
return g0.AddValueIn(ValueOut(v2, e2), v3)
|
||||||
},
|
},
|
||||||
4, 0,
|
4, 0,
|
||||||
value("v0"),
|
value(v0),
|
||||||
value("v1", edge("e0", value("v0"))),
|
value(v1, edge(e0, value(v0))),
|
||||||
value("v2"),
|
value(v2),
|
||||||
value("v3", edge("e2", value("v2"))),
|
value(v3, edge(e2, value(v2))),
|
||||||
),
|
),
|
||||||
|
|
||||||
mkTest(
|
mkTest(
|
||||||
"values-circular",
|
"values-circular",
|
||||||
func() *Graph {
|
func() *Graph {
|
||||||
return Null.AddValueIn(ValueOut(id("v0"), id("e")), id("v0"))
|
return Null.AddValueIn(ValueOut(v0, e0), v0)
|
||||||
},
|
},
|
||||||
1, 0,
|
1, 0,
|
||||||
value("v0", edge("e", value("v0"))),
|
value(v0, edge(e0, value(v0))),
|
||||||
),
|
),
|
||||||
|
|
||||||
mkTest(
|
mkTest(
|
||||||
"values-circular2",
|
"values-circular2",
|
||||||
func() *Graph {
|
func() *Graph {
|
||||||
g0 := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
g0 := Null.AddValueIn(ValueOut(v0, e0), v1)
|
||||||
return g0.AddValueIn(ValueOut(id("v1"), id("e1")), id("v0"))
|
return g0.AddValueIn(ValueOut(v1, e1), v0)
|
||||||
},
|
},
|
||||||
2, 0,
|
2, 0,
|
||||||
value("v0", edge("e1", value("v1", edge("e0", value("v0"))))),
|
value(v0, edge(e1, value(v1, edge(e0, value(v0))))),
|
||||||
value("v1", edge("e0", value("v0", edge("e1", value("v1"))))),
|
value(v1, edge(e0, value(v0, edge(e1, value(v1))))),
|
||||||
),
|
),
|
||||||
|
|
||||||
mkTest(
|
mkTest(
|
||||||
"values-circular3",
|
"values-circular3",
|
||||||
func() *Graph {
|
func() *Graph {
|
||||||
g0 := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
g0 := Null.AddValueIn(ValueOut(v0, e0), v1)
|
||||||
g1 := g0.AddValueIn(ValueOut(id("v1"), id("e1")), id("v2"))
|
g1 := g0.AddValueIn(ValueOut(v1, e1), v2)
|
||||||
return g1.AddValueIn(ValueOut(id("v2"), id("e2")), id("v1"))
|
return g1.AddValueIn(ValueOut(v2, e2), v1)
|
||||||
},
|
},
|
||||||
3, 0,
|
3, 0,
|
||||||
value("v0"),
|
value(v0),
|
||||||
value("v1",
|
value(v1,
|
||||||
edge("e0", value("v0")),
|
edge(e0, value(v0)),
|
||||||
edge("e2", value("v2", edge("e1", value("v1")))),
|
edge(e2, value(v2, edge(e1, value(v1)))),
|
||||||
),
|
),
|
||||||
value("v2", edge("e1", value("v1",
|
value(v2, edge(e1, value(v1,
|
||||||
edge("e0", value("v0")),
|
edge(e0, value(v0)),
|
||||||
edge("e2", value("v2")),
|
edge(e2, value(v2)),
|
||||||
))),
|
))),
|
||||||
),
|
),
|
||||||
|
|
||||||
mkTest(
|
mkTest(
|
||||||
"junction-basic",
|
"junction-basic",
|
||||||
func() *Graph {
|
func() *Graph {
|
||||||
e0 := ValueOut(id("v0"), id("e0"))
|
e0 := ValueOut(v0, e0)
|
||||||
e1 := ValueOut(id("v1"), id("e1"))
|
e1 := ValueOut(v1, e1)
|
||||||
ej0 := JunctionOut([]OpenEdge{e0, e1}, id("ej0"))
|
ej0 := JunctionOut([]OpenEdge{e0, e1}, ej0)
|
||||||
return Null.AddValueIn(ej0, id("v2"))
|
return Null.AddValueIn(ej0, v2)
|
||||||
},
|
},
|
||||||
3, 1,
|
3, 1,
|
||||||
value("v0"), value("v1"),
|
value(v0), value(v1),
|
||||||
value("v2", junction("ej0",
|
value(v2, junction(ej0,
|
||||||
edge("e0", value("v0")),
|
edge(e0, value(v0)),
|
||||||
edge("e1", value("v1")),
|
edge(e1, value(v1)),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
|
|
||||||
mkTest(
|
mkTest(
|
||||||
"junction-basic2",
|
"junction-basic2",
|
||||||
func() *Graph {
|
func() *Graph {
|
||||||
e00 := ValueOut(id("v0"), id("e00"))
|
e00 := ValueOut(v0, e00)
|
||||||
e10 := ValueOut(id("v1"), id("e10"))
|
e10 := ValueOut(v1, e10)
|
||||||
ej0 := JunctionOut([]OpenEdge{e00, e10}, id("ej0"))
|
ej0 := JunctionOut([]OpenEdge{e00, e10}, ej0)
|
||||||
e01 := ValueOut(id("v0"), id("e01"))
|
e01 := ValueOut(v0, e01)
|
||||||
e11 := ValueOut(id("v1"), id("e11"))
|
e11 := ValueOut(v1, e11)
|
||||||
ej1 := JunctionOut([]OpenEdge{e01, e11}, id("ej1"))
|
ej1 := JunctionOut([]OpenEdge{e01, e11}, ej1)
|
||||||
ej2 := JunctionOut([]OpenEdge{ej0, ej1}, id("ej2"))
|
ej2 := JunctionOut([]OpenEdge{ej0, ej1}, ej2)
|
||||||
return Null.AddValueIn(ej2, id("v2"))
|
return Null.AddValueIn(ej2, v2)
|
||||||
},
|
},
|
||||||
3, 3,
|
3, 3,
|
||||||
value("v0"), value("v1"),
|
value(v0), value(v1),
|
||||||
value("v2", junction("ej2",
|
value(v2, junction(ej2,
|
||||||
junction("ej0",
|
junction(ej0,
|
||||||
edge("e00", value("v0")),
|
edge(e00, value(v0)),
|
||||||
edge("e10", value("v1")),
|
edge(e10, value(v1)),
|
||||||
),
|
),
|
||||||
junction("ej1",
|
junction(ej1,
|
||||||
edge("e01", value("v0")),
|
edge(e01, value(v0)),
|
||||||
edge("e11", value("v1")),
|
edge(e11, value(v1)),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
@ -225,27 +229,27 @@ func TestGraph(t *T) {
|
|||||||
mkTest(
|
mkTest(
|
||||||
"junction-circular",
|
"junction-circular",
|
||||||
func() *Graph {
|
func() *Graph {
|
||||||
e0 := ValueOut(id("v0"), id("e0"))
|
e0 := ValueOut(v0, e0)
|
||||||
e1 := ValueOut(id("v1"), id("e1"))
|
e1 := ValueOut(v1, e1)
|
||||||
ej0 := JunctionOut([]OpenEdge{e0, e1}, id("ej0"))
|
ej0 := JunctionOut([]OpenEdge{e0, e1}, ej0)
|
||||||
g0 := Null.AddValueIn(ej0, id("v2"))
|
g0 := Null.AddValueIn(ej0, v2)
|
||||||
e20 := ValueOut(id("v2"), id("e20"))
|
e20 := ValueOut(v2, e20)
|
||||||
g1 := g0.AddValueIn(e20, id("v0"))
|
g1 := g0.AddValueIn(e20, v0)
|
||||||
e21 := ValueOut(id("v2"), id("e21"))
|
e21 := ValueOut(v2, e21)
|
||||||
return g1.AddValueIn(e21, id("v1"))
|
return g1.AddValueIn(e21, v1)
|
||||||
},
|
},
|
||||||
3, 1,
|
3, 1,
|
||||||
value("v0", edge("e20", value("v2", junction("ej0",
|
value(v0, edge(e20, value(v2, junction(ej0,
|
||||||
edge("e0", value("v0")),
|
edge(e0, value(v0)),
|
||||||
edge("e1", value("v1", edge("e21", value("v2")))),
|
edge(e1, value(v1, edge(e21, value(v2)))),
|
||||||
)))),
|
)))),
|
||||||
value("v1", edge("e21", value("v2", junction("ej0",
|
value(v1, edge(e21, value(v2, junction(ej0,
|
||||||
edge("e0", value("v0", edge("e20", value("v2")))),
|
edge(e0, value(v0, edge(e20, value(v2)))),
|
||||||
edge("e1", value("v1")),
|
edge(e1, value(v1)),
|
||||||
)))),
|
)))),
|
||||||
value("v2", junction("ej0",
|
value(v2, junction(ej0,
|
||||||
edge("e0", value("v0", edge("e20", value("v2")))),
|
edge(e0, value(v0, edge(e20, value(v2)))),
|
||||||
edge("e1", value("v1", edge("e21", value("v2")))),
|
edge(e1, value(v1, edge(e21, value(v2)))),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@ -256,9 +260,9 @@ func TestGraph(t *T) {
|
|||||||
for j, exp := range tests[i].exp {
|
for j, exp := range tests[i].exp {
|
||||||
msgAndArgs := []interface{}{
|
msgAndArgs := []interface{}{
|
||||||
"tests[%d].name:%q exp[%d].val:%q",
|
"tests[%d].name:%q exp[%d].val:%q",
|
||||||
i, tests[i].name, j, exp.Value.(idAny).i,
|
i, tests[i].name, j, exp.Value.V.(string),
|
||||||
}
|
}
|
||||||
v := out.Value(exp.Value)
|
v := out.ValueVertex(exp.Value)
|
||||||
if !assert.NotNil(t, v, msgAndArgs...) {
|
if !assert.NotNil(t, v, msgAndArgs...) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -279,109 +283,127 @@ func TestGraph(t *T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGraphImmutability(t *T) {
|
func TestGraphImmutability(t *T) {
|
||||||
e0 := ValueOut(id("v0"), id("e0"))
|
v0 := NewValue("v0")
|
||||||
g0 := Null.AddValueIn(e0, id("v1"))
|
v1 := NewValue("v1")
|
||||||
assert.Nil(t, Null.Value(id("v0")))
|
e0 := NewValue("e0")
|
||||||
assert.Nil(t, Null.Value(id("v1")))
|
oe0 := ValueOut(v0, e0)
|
||||||
assert.NotNil(t, g0.Value(id("v0")))
|
g0 := Null.AddValueIn(oe0, v1)
|
||||||
assert.NotNil(t, g0.Value(id("v1")))
|
assert.Nil(t, Null.ValueVertex(v0))
|
||||||
|
assert.Nil(t, Null.ValueVertex(v1))
|
||||||
|
assert.NotNil(t, g0.ValueVertex(v0))
|
||||||
|
assert.NotNil(t, g0.ValueVertex(v1))
|
||||||
|
|
||||||
// half-edges should be re-usable
|
// half-edges should be re-usable
|
||||||
e1 := ValueOut(id("v2"), id("e1"))
|
v2 := NewValue("v2")
|
||||||
g1a := g0.AddValueIn(e1, id("v3a"))
|
v3a, v3b := NewValue("v3a"), NewValue("v3b")
|
||||||
g1b := g0.AddValueIn(e1, id("v3b"))
|
e1 := NewValue("e1")
|
||||||
assertVertexEqual(t, value("v3a", edge("e1", value("v2"))), g1a.Value(id("v3a")))
|
oe1 := ValueOut(v2, e1)
|
||||||
assert.Nil(t, g1a.Value(id("v3b")))
|
g1a := g0.AddValueIn(oe1, v3a)
|
||||||
assertVertexEqual(t, value("v3b", edge("e1", value("v2"))), g1b.Value(id("v3b")))
|
g1b := g0.AddValueIn(oe1, v3b)
|
||||||
assert.Nil(t, g1b.Value(id("v3a")))
|
assertVertexEqual(t, value(v3a, edge(e1, value(v2))), g1a.ValueVertex(v3a))
|
||||||
|
assert.Nil(t, g1a.ValueVertex(v3b))
|
||||||
|
assertVertexEqual(t, value(v3b, edge(e1, value(v2))), g1b.ValueVertex(v3b))
|
||||||
|
assert.Nil(t, g1b.ValueVertex(v3a))
|
||||||
|
|
||||||
// ... even re-usable twice in succession
|
// ... even re-usable twice in succession
|
||||||
g2 := g0.AddValueIn(e1, id("v3")).AddValueIn(e1, id("v4"))
|
v3 := NewValue("v3")
|
||||||
assert.Nil(t, g2.Value(id("v3b")))
|
v4 := NewValue("v4")
|
||||||
assert.Nil(t, g2.Value(id("v3a")))
|
g2 := g0.AddValueIn(oe1, v3).AddValueIn(oe1, v4)
|
||||||
assertVertexEqual(t, value("v3", edge("e1", value("v2"))), g2.Value(id("v3")))
|
assert.Nil(t, g2.ValueVertex(v3b))
|
||||||
assertVertexEqual(t, value("v4", edge("e1", value("v2"))), g2.Value(id("v4")))
|
assert.Nil(t, g2.ValueVertex(v3a))
|
||||||
|
assertVertexEqual(t, value(v3, edge(e1, value(v2))), g2.ValueVertex(v3))
|
||||||
|
assertVertexEqual(t, value(v4, edge(e1, value(v2))), g2.ValueVertex(v4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGraphDelValueIn(t *T) {
|
func TestGraphDelValueIn(t *T) {
|
||||||
|
v0 := NewValue("v0")
|
||||||
|
v1 := NewValue("v1")
|
||||||
|
e0 := NewValue("e0")
|
||||||
{ // removing from null
|
{ // removing from null
|
||||||
g := Null.DelValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
g := Null.DelValueIn(ValueOut(v0, e0), v1)
|
||||||
assert.True(t, Equal(Null, g))
|
assert.True(t, Equal(Null, g))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e1 := NewValue("e1")
|
||||||
{ // removing edge from vertex which doesn't have that edge
|
{ // removing edge from vertex which doesn't have that edge
|
||||||
g0 := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
g0 := Null.AddValueIn(ValueOut(v0, e0), v1)
|
||||||
g1 := g0.DelValueIn(ValueOut(id("v0"), id("e1")), id("v1"))
|
g1 := g0.DelValueIn(ValueOut(v0, e1), v1)
|
||||||
assert.True(t, Equal(g0, g1))
|
assert.True(t, Equal(g0, g1))
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // removing only edge
|
{ // removing only edge
|
||||||
oe := ValueOut(id("v0"), id("e0"))
|
oe := ValueOut(v0, e0)
|
||||||
g0 := Null.AddValueIn(oe, id("v1"))
|
g0 := Null.AddValueIn(oe, v1)
|
||||||
g1 := g0.DelValueIn(oe, id("v1"))
|
g1 := g0.DelValueIn(oe, v1)
|
||||||
assert.True(t, Equal(Null, g1))
|
assert.True(t, Equal(Null, g1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ej0 := NewValue("ej0")
|
||||||
|
v2 := NewValue("v2")
|
||||||
{ // removing only edge (junction)
|
{ // removing only edge (junction)
|
||||||
oe := JunctionOut([]OpenEdge{
|
oe := JunctionOut([]OpenEdge{
|
||||||
ValueOut(id("v0"), id("e0")),
|
ValueOut(v0, e0),
|
||||||
ValueOut(id("v1"), id("e1")),
|
ValueOut(v1, e1),
|
||||||
}, id("ej0"))
|
}, ej0)
|
||||||
g0 := Null.AddValueIn(oe, id("v2"))
|
g0 := Null.AddValueIn(oe, v2)
|
||||||
g1 := g0.DelValueIn(oe, id("v2"))
|
g1 := g0.DelValueIn(oe, v2)
|
||||||
assert.True(t, Equal(Null, g1))
|
assert.True(t, Equal(Null, g1))
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // removing one of two edges
|
{ // removing one of two edges
|
||||||
oe := ValueOut(id("v1"), id("e0"))
|
oe := ValueOut(v1, e0)
|
||||||
g0 := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v2"))
|
g0 := Null.AddValueIn(ValueOut(v0, e0), v2)
|
||||||
g1 := g0.AddValueIn(oe, id("v2"))
|
g1 := g0.AddValueIn(oe, v2)
|
||||||
g2 := g1.DelValueIn(oe, id("v2"))
|
g2 := g1.DelValueIn(oe, v2)
|
||||||
assert.True(t, Equal(g0, g2))
|
assert.True(t, Equal(g0, g2))
|
||||||
assert.NotNil(t, g2.Value(id("v0")))
|
assert.NotNil(t, g2.ValueVertex(v0))
|
||||||
assert.Nil(t, g2.Value(id("v1")))
|
assert.Nil(t, g2.ValueVertex(v1))
|
||||||
assert.NotNil(t, g2.Value(id("v2")))
|
assert.NotNil(t, g2.ValueVertex(v2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e2 := NewValue("e2")
|
||||||
|
eja, ejb := NewValue("eja"), NewValue("ejb")
|
||||||
|
v3 := NewValue("v3")
|
||||||
{ // removing one of two edges (junction)
|
{ // removing one of two edges (junction)
|
||||||
e0 := ValueOut(id("v0"), id("e0"))
|
e0 := ValueOut(v0, e0)
|
||||||
e1 := ValueOut(id("v1"), id("e1"))
|
e1 := ValueOut(v1, e1)
|
||||||
e2 := ValueOut(id("v2"), id("e2"))
|
e2 := ValueOut(v2, e2)
|
||||||
oeA := JunctionOut([]OpenEdge{e0, e1}, id("oeA"))
|
oeA := JunctionOut([]OpenEdge{e0, e1}, eja)
|
||||||
oeB := JunctionOut([]OpenEdge{e1, e2}, id("oeB"))
|
oeB := JunctionOut([]OpenEdge{e1, e2}, ejb)
|
||||||
g0a := Null.AddValueIn(oeA, id("v3"))
|
g0a := Null.AddValueIn(oeA, v3)
|
||||||
g0b := Null.AddValueIn(oeB, id("v3"))
|
g0b := Null.AddValueIn(oeB, v3)
|
||||||
g1 := g0a.Union(g0b).DelValueIn(oeA, id("v3"))
|
g1 := g0a.Union(g0b).DelValueIn(oeA, v3)
|
||||||
assert.True(t, Equal(g1, g0b))
|
assert.True(t, Equal(g1, g0b))
|
||||||
assert.Nil(t, g1.Value(id("v0")))
|
assert.Nil(t, g1.ValueVertex(v0))
|
||||||
assert.NotNil(t, g1.Value(id("v1")))
|
assert.NotNil(t, g1.ValueVertex(v1))
|
||||||
assert.NotNil(t, g1.Value(id("v2")))
|
assert.NotNil(t, g1.ValueVertex(v2))
|
||||||
assert.NotNil(t, g1.Value(id("v3")))
|
assert.NotNil(t, g1.ValueVertex(v3))
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // removing one of two edges in circular graph
|
{ // removing one of two edges in circular graph
|
||||||
e0 := ValueOut(id("v0"), id("e0"))
|
e0 := ValueOut(v0, e0)
|
||||||
e1 := ValueOut(id("v1"), id("e1"))
|
e1 := ValueOut(v1, e1)
|
||||||
g0 := Null.AddValueIn(e0, id("v1")).AddValueIn(e1, id("v0"))
|
g0 := Null.AddValueIn(e0, v1).AddValueIn(e1, v0)
|
||||||
g1 := g0.DelValueIn(e0, id("v1"))
|
g1 := g0.DelValueIn(e0, v1)
|
||||||
assert.True(t, Equal(Null.AddValueIn(e1, id("v0")), g1))
|
assert.True(t, Equal(Null.AddValueIn(e1, v0), g1))
|
||||||
assert.NotNil(t, g1.Value(id("v0")))
|
assert.NotNil(t, g1.ValueVertex(v0))
|
||||||
assert.NotNil(t, g1.Value(id("v1")))
|
assert.NotNil(t, g1.ValueVertex(v1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ej := NewValue("ej")
|
||||||
{ // removing to's only edge, sub-nodes have edge to each other
|
{ // removing to's only edge, sub-nodes have edge to each other
|
||||||
ej := JunctionOut([]OpenEdge{
|
oej := JunctionOut([]OpenEdge{
|
||||||
ValueOut(id("v0"), id("ej0")),
|
ValueOut(v0, ej0),
|
||||||
ValueOut(id("v1"), id("ej0")),
|
ValueOut(v1, ej0),
|
||||||
}, id("ej"))
|
}, ej)
|
||||||
g0 := Null.AddValueIn(ej, id("v2"))
|
g0 := Null.AddValueIn(oej, v2)
|
||||||
e0 := ValueOut(id("v0"), id("e0"))
|
e0 := ValueOut(v0, e0)
|
||||||
g1 := g0.AddValueIn(e0, id("v1"))
|
g1 := g0.AddValueIn(e0, v1)
|
||||||
g2 := g1.DelValueIn(ej, id("v2"))
|
g2 := g1.DelValueIn(oej, v2)
|
||||||
assert.True(t, Equal(Null.AddValueIn(e0, id("v1")), g2))
|
assert.True(t, Equal(Null.AddValueIn(e0, v1), g2))
|
||||||
assert.NotNil(t, g2.Value(id("v0")))
|
assert.NotNil(t, g2.ValueVertex(v0))
|
||||||
assert.NotNil(t, g2.Value(id("v1")))
|
assert.NotNil(t, g2.ValueVertex(v1))
|
||||||
assert.Nil(t, g2.Value(id("v2")))
|
assert.Nil(t, g2.ValueVertex(v2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,110 +415,124 @@ func TestGraphUnion(t *T) {
|
|||||||
return ga
|
return ga
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v0 := NewValue("v0")
|
||||||
|
v1 := NewValue("v1")
|
||||||
|
e0 := NewValue("e0")
|
||||||
{ // Union with Null
|
{ // Union with Null
|
||||||
assert.True(t, Equal(Null, Null.Union(Null)))
|
assert.True(t, Equal(Null, Null.Union(Null)))
|
||||||
|
|
||||||
g := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
g := Null.AddValueIn(ValueOut(v0, e0), v1)
|
||||||
assert.True(t, Equal(g, assertUnion(g, Null)))
|
assert.True(t, Equal(g, assertUnion(g, Null)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v2 := NewValue("v2")
|
||||||
|
v3 := NewValue("v3")
|
||||||
|
e1 := NewValue("e1")
|
||||||
{ // Two disparate graphs union'd
|
{ // Two disparate graphs union'd
|
||||||
g0 := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
g0 := Null.AddValueIn(ValueOut(v0, e0), v1)
|
||||||
g1 := Null.AddValueIn(ValueOut(id("v2"), id("e1")), id("v3"))
|
g1 := Null.AddValueIn(ValueOut(v2, e1), v3)
|
||||||
g := assertUnion(g0, g1)
|
g := assertUnion(g0, g1)
|
||||||
assertVertexEqual(t, value("v0"), g.Value(id("v0")))
|
assertVertexEqual(t, value(v0), g.ValueVertex(v0))
|
||||||
assertVertexEqual(t, value("v1", edge("e0", value("v0"))), g.Value(id("v1")))
|
assertVertexEqual(t, value(v1, edge(e0, value(v0))), g.ValueVertex(v1))
|
||||||
assertVertexEqual(t, value("v2"), g.Value(id("v2")))
|
assertVertexEqual(t, value(v2), g.ValueVertex(v2))
|
||||||
assertVertexEqual(t, value("v3", edge("e1", value("v2"))), g.Value(id("v3")))
|
assertVertexEqual(t, value(v3, edge(e1, value(v2))), g.ValueVertex(v3))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
va0, vb0 := NewValue("va0"), NewValue("vb0")
|
||||||
|
va1, vb1 := NewValue("va1"), NewValue("vb1")
|
||||||
|
va2, vb2 := NewValue("va2"), NewValue("vb2")
|
||||||
|
ea0, eb0 := NewValue("ea0"), NewValue("eb0")
|
||||||
|
ea1, eb1 := NewValue("ea1"), NewValue("eb1")
|
||||||
|
eaj, ebj := NewValue("eaj"), NewValue("ebj")
|
||||||
{ // Two disparate graphs with junctions
|
{ // Two disparate graphs with junctions
|
||||||
ga := Null.AddValueIn(JunctionOut([]OpenEdge{
|
ga := Null.AddValueIn(JunctionOut([]OpenEdge{
|
||||||
ValueOut(id("va0"), id("ea0")),
|
ValueOut(va0, ea0),
|
||||||
ValueOut(id("va1"), id("ea1")),
|
ValueOut(va1, ea1),
|
||||||
}, id("eaj")), id("va2"))
|
}, eaj), va2)
|
||||||
gb := Null.AddValueIn(JunctionOut([]OpenEdge{
|
gb := Null.AddValueIn(JunctionOut([]OpenEdge{
|
||||||
ValueOut(id("vb0"), id("eb0")),
|
ValueOut(vb0, eb0),
|
||||||
ValueOut(id("vb1"), id("eb1")),
|
ValueOut(vb1, eb1),
|
||||||
}, id("ebj")), id("vb2"))
|
}, ebj), vb2)
|
||||||
g := assertUnion(ga, gb)
|
g := assertUnion(ga, gb)
|
||||||
assertVertexEqual(t, value("va0"), g.Value(id("va0")))
|
assertVertexEqual(t, value(va0), g.ValueVertex(va0))
|
||||||
assertVertexEqual(t, value("va1"), g.Value(id("va1")))
|
assertVertexEqual(t, value(va1), g.ValueVertex(va1))
|
||||||
assertVertexEqual(t,
|
assertVertexEqual(t,
|
||||||
value("va2", junction("eaj",
|
value(va2, junction(eaj,
|
||||||
edge("ea0", value("va0")),
|
edge(ea0, value(va0)),
|
||||||
edge("ea1", value("va1")))),
|
edge(ea1, value(va1)))),
|
||||||
g.Value(id("va2")),
|
g.ValueVertex(va2),
|
||||||
)
|
)
|
||||||
assertVertexEqual(t, value("vb0"), g.Value(id("vb0")))
|
assertVertexEqual(t, value(vb0), g.ValueVertex(vb0))
|
||||||
assertVertexEqual(t, value("vb1"), g.Value(id("vb1")))
|
assertVertexEqual(t, value(vb1), g.ValueVertex(vb1))
|
||||||
assertVertexEqual(t,
|
assertVertexEqual(t,
|
||||||
value("vb2", junction("ebj",
|
value(vb2, junction(ebj,
|
||||||
edge("eb0", value("vb0")),
|
edge(eb0, value(vb0)),
|
||||||
edge("eb1", value("vb1")))),
|
edge(eb1, value(vb1)))),
|
||||||
g.Value(id("vb2")),
|
g.ValueVertex(vb2),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Two partially overlapping graphs
|
{ // Two partially overlapping graphs
|
||||||
g0 := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v2"))
|
g0 := Null.AddValueIn(ValueOut(v0, e0), v2)
|
||||||
g1 := Null.AddValueIn(ValueOut(id("v1"), id("e1")), id("v2"))
|
g1 := Null.AddValueIn(ValueOut(v1, e1), v2)
|
||||||
g := assertUnion(g0, g1)
|
g := assertUnion(g0, g1)
|
||||||
assertVertexEqual(t, value("v0"), g.Value(id("v0")))
|
assertVertexEqual(t, value(v0), g.ValueVertex(v0))
|
||||||
assertVertexEqual(t, value("v1"), g.Value(id("v1")))
|
assertVertexEqual(t, value(v1), g.ValueVertex(v1))
|
||||||
assertVertexEqual(t,
|
assertVertexEqual(t,
|
||||||
value("v2",
|
value(v2,
|
||||||
edge("e0", value("v0")),
|
edge(e0, value(v0)),
|
||||||
edge("e1", value("v1")),
|
edge(e1, value(v1)),
|
||||||
),
|
),
|
||||||
g.Value(id("v2")),
|
g.ValueVertex(v2),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ej0 := NewValue("ej0")
|
||||||
|
ej1 := NewValue("ej1")
|
||||||
{ // two partially overlapping graphs with junctions
|
{ // two partially overlapping graphs with junctions
|
||||||
g0 := Null.AddValueIn(JunctionOut([]OpenEdge{
|
g0 := Null.AddValueIn(JunctionOut([]OpenEdge{
|
||||||
ValueOut(id("v0"), id("e0")),
|
ValueOut(v0, e0),
|
||||||
ValueOut(id("v1"), id("e1")),
|
ValueOut(v1, e1),
|
||||||
}, id("ej0")), id("v2"))
|
}, ej0), v2)
|
||||||
g1 := Null.AddValueIn(JunctionOut([]OpenEdge{
|
g1 := Null.AddValueIn(JunctionOut([]OpenEdge{
|
||||||
ValueOut(id("v0"), id("e0")),
|
ValueOut(v0, e0),
|
||||||
ValueOut(id("v1"), id("e1")),
|
ValueOut(v1, e1),
|
||||||
}, id("ej1")), id("v2"))
|
}, ej1), v2)
|
||||||
g := assertUnion(g0, g1)
|
g := assertUnion(g0, g1)
|
||||||
assertVertexEqual(t, value("v0"), g.Value(id("v0")))
|
assertVertexEqual(t, value(v0), g.ValueVertex(v0))
|
||||||
assertVertexEqual(t, value("v1"), g.Value(id("v1")))
|
assertVertexEqual(t, value(v1), g.ValueVertex(v1))
|
||||||
assertVertexEqual(t,
|
assertVertexEqual(t,
|
||||||
value("v2",
|
value(v2,
|
||||||
junction("ej0", edge("e0", value("v0")), edge("e1", value("v1"))),
|
junction(ej0, edge(e0, value(v0)), edge(e1, value(v1))),
|
||||||
junction("ej1", edge("e0", value("v0")), edge("e1", value("v1"))),
|
junction(ej1, edge(e0, value(v0)), edge(e1, value(v1))),
|
||||||
),
|
),
|
||||||
g.Value(id("v2")),
|
g.ValueVertex(v2),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Two equal graphs
|
{ // Two equal graphs
|
||||||
g0 := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
g0 := Null.AddValueIn(ValueOut(v0, e0), v1)
|
||||||
g := assertUnion(g0, g0)
|
g := assertUnion(g0, g0)
|
||||||
assertVertexEqual(t, value("v0"), g.Value(id("v0")))
|
assertVertexEqual(t, value(v0), g.ValueVertex(v0))
|
||||||
assertVertexEqual(t,
|
assertVertexEqual(t,
|
||||||
value("v1", edge("e0", value("v0"))),
|
value(v1, edge(e0, value(v0))),
|
||||||
g.Value(id("v1")),
|
g.ValueVertex(v1),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Two equal graphs with junctions
|
{ // Two equal graphs with junctions
|
||||||
g0 := Null.AddValueIn(JunctionOut([]OpenEdge{
|
g0 := Null.AddValueIn(JunctionOut([]OpenEdge{
|
||||||
ValueOut(id("v0"), id("e0")),
|
ValueOut(v0, e0),
|
||||||
ValueOut(id("v1"), id("e1")),
|
ValueOut(v1, e1),
|
||||||
}, id("ej0")), id("v2"))
|
}, ej0), v2)
|
||||||
g := assertUnion(g0, g0)
|
g := assertUnion(g0, g0)
|
||||||
assertVertexEqual(t, value("v0"), g.Value(id("v0")))
|
assertVertexEqual(t, value(v0), g.ValueVertex(v0))
|
||||||
assertVertexEqual(t, value("v1"), g.Value(id("v1")))
|
assertVertexEqual(t, value(v1), g.ValueVertex(v1))
|
||||||
assertVertexEqual(t,
|
assertVertexEqual(t,
|
||||||
value("v2",
|
value(v2,
|
||||||
junction("ej0", edge("e0", value("v0")), edge("e1", value("v1"))),
|
junction(ej0, edge(e0, value(v0)), edge(e1, value(v1))),
|
||||||
),
|
),
|
||||||
g.Value(id("v2")),
|
g.ValueVertex(v2),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -514,35 +550,42 @@ func TestGraphEqual(t *T) {
|
|||||||
|
|
||||||
assertEqual(Null, Null) // duh
|
assertEqual(Null, Null) // duh
|
||||||
|
|
||||||
|
v0 := NewValue("v0")
|
||||||
|
v1 := NewValue("v1")
|
||||||
|
v2 := NewValue("v2")
|
||||||
|
e0 := NewValue("e0")
|
||||||
|
e1 := NewValue("e1")
|
||||||
|
e1a, e1b := NewValue("e1a"), NewValue("e1b")
|
||||||
{
|
{
|
||||||
// graph is equal to itself, not to null
|
// graph is equal to itself, not to null
|
||||||
e0 := ValueOut(id("v0"), id("e0"))
|
e0 := ValueOut(v0, e0)
|
||||||
g0 := Null.AddValueIn(e0, id("v1"))
|
g0 := Null.AddValueIn(e0, v1)
|
||||||
assertNotEqual(g0, Null)
|
assertNotEqual(g0, Null)
|
||||||
assertEqual(g0, g0)
|
assertEqual(g0, g0)
|
||||||
|
|
||||||
// adding the an existing edge again shouldn't do anything
|
// adding the an existing edge again shouldn't do anything
|
||||||
assertEqual(g0, g0.AddValueIn(e0, id("v1")))
|
assertEqual(g0, g0.AddValueIn(e0, v1))
|
||||||
|
|
||||||
// g1a and g1b have the same vertices, but the edges are different
|
// g1a and g1b have the same vertices, but the edges are different
|
||||||
g1a := g0.AddValueIn(ValueOut(id("v0"), id("e1a")), id("v2"))
|
g1a := g0.AddValueIn(ValueOut(v0, e1a), v2)
|
||||||
g1b := g0.AddValueIn(ValueOut(id("v0"), id("e1b")), id("v2"))
|
g1b := g0.AddValueIn(ValueOut(v0, e1b), v2)
|
||||||
assertNotEqual(g1a, g1b)
|
assertNotEqual(g1a, g1b)
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // equal construction should yield equality, even if out of order
|
{ // equal construction should yield equality, even if out of order
|
||||||
ga := Null.AddValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
ga := Null.AddValueIn(ValueOut(v0, e0), v1)
|
||||||
ga = ga.AddValueIn(ValueOut(id("v1"), id("e1")), id("v2"))
|
ga = ga.AddValueIn(ValueOut(v1, e1), v2)
|
||||||
gb := Null.AddValueIn(ValueOut(id("v1"), id("e1")), id("v2"))
|
gb := Null.AddValueIn(ValueOut(v1, e1), v2)
|
||||||
gb = gb.AddValueIn(ValueOut(id("v0"), id("e0")), id("v1"))
|
gb = gb.AddValueIn(ValueOut(v0, e0), v1)
|
||||||
assertEqual(ga, gb)
|
assertEqual(ga, gb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ej := NewValue("ej")
|
||||||
{ // junction basic test
|
{ // junction basic test
|
||||||
e0 := ValueOut(id("v0"), id("e0"))
|
e0 := ValueOut(v0, e0)
|
||||||
e1 := ValueOut(id("v1"), id("e1"))
|
e1 := ValueOut(v1, e1)
|
||||||
ga := Null.AddValueIn(JunctionOut([]OpenEdge{e0, e1}, id("ej")), id("v2"))
|
ga := Null.AddValueIn(JunctionOut([]OpenEdge{e0, e1}, ej), v2)
|
||||||
gb := Null.AddValueIn(JunctionOut([]OpenEdge{e1, e0}, id("ej")), id("v2"))
|
gb := Null.AddValueIn(JunctionOut([]OpenEdge{e1, e0}, ej), v2)
|
||||||
assertEqual(ga, ga)
|
assertEqual(ga, ga)
|
||||||
assertNotEqual(ga, gb)
|
assertNotEqual(ga, gb)
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,8 @@ func boxFromVertex(v *gg.Vertex, flowDir geo.XY) box {
|
|||||||
numIn: len(v.In),
|
numIn: len(v.In),
|
||||||
numOut: len(v.Out),
|
numOut: len(v.Out),
|
||||||
}
|
}
|
||||||
if v.VertexType == gg.Value {
|
if v.VertexType == gg.ValueVertex {
|
||||||
b.body = string(v.Value.(gg.Str))
|
b.body = v.Value.V.(string)
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
@ -17,28 +17,38 @@ type Constraint struct {
|
|||||||
LT string
|
LT string
|
||||||
}
|
}
|
||||||
|
|
||||||
const ltEdge = gg.Str("lt")
|
var ltEdge = gg.NewValue("lt")
|
||||||
|
|
||||||
// Engine processes sets of constraints to generate an output
|
// Engine processes sets of constraints to generate an output
|
||||||
type Engine struct {
|
type Engine struct {
|
||||||
g *gg.Graph
|
g *gg.Graph
|
||||||
|
vals map[string]gg.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEngine initializes and returns an empty Engine
|
// NewEngine initializes and returns an empty Engine
|
||||||
func NewEngine() *Engine {
|
func NewEngine() *Engine {
|
||||||
return &Engine{g: gg.Null}
|
return &Engine{g: gg.Null, vals: map[string]gg.Value{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Engine) getVal(elem string) gg.Value {
|
||||||
|
if val, ok := e.vals[elem]; ok {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
val := gg.NewValue(elem)
|
||||||
|
e.vals[elem] = val
|
||||||
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddConstraint adds the given constraint to the engine's set, returns false if
|
// AddConstraint adds the given constraint to the engine's set, returns false if
|
||||||
// the constraint couldn't be added due to a conflict with a previous constraint
|
// the constraint couldn't be added due to a conflict with a previous constraint
|
||||||
func (e *Engine) AddConstraint(c Constraint) bool {
|
func (e *Engine) AddConstraint(c Constraint) bool {
|
||||||
elem := gg.Str(c.Elem)
|
elem := e.getVal(c.Elem)
|
||||||
g := e.g.AddValueIn(gg.ValueOut(elem, ltEdge), gg.Str(c.LT))
|
g := e.g.AddValueIn(gg.ValueOut(elem, ltEdge), e.getVal(c.LT))
|
||||||
|
|
||||||
// Check for loops in g starting at c.Elem, bail if there are any
|
// Check for loops in g starting at c.Elem, bail if there are any
|
||||||
{
|
{
|
||||||
seen := map[*gg.Vertex]bool{}
|
seen := map[*gg.Vertex]bool{}
|
||||||
start := g.Value(elem)
|
start := g.ValueVertex(elem)
|
||||||
var hasLoop func(v *gg.Vertex) bool
|
var hasLoop func(v *gg.Vertex) bool
|
||||||
hasLoop = func(v *gg.Vertex) bool {
|
hasLoop = func(v *gg.Vertex) bool {
|
||||||
if seen[v] {
|
if seen[v] {
|
||||||
@ -66,12 +76,12 @@ func (e *Engine) AddConstraint(c Constraint) bool {
|
|||||||
// engine and whose value is known to be zero.
|
// engine and whose value is known to be zero.
|
||||||
func (e *Engine) Solve() map[string]int {
|
func (e *Engine) Solve() map[string]int {
|
||||||
m := map[string]int{}
|
m := map[string]int{}
|
||||||
if len(e.g.Values()) == 0 {
|
if len(e.g.ValueVertices()) == 0 {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
vElem := func(v *gg.Vertex) string {
|
vElem := func(v *gg.Vertex) string {
|
||||||
return string(v.Value.(gg.Str))
|
return v.Value.V.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// first the roots are determined to be the elements with no In edges, which
|
// first the roots are determined to be the elements with no In edges, which
|
||||||
|
48
gim/main.go
48
gim/main.go
@ -35,25 +35,36 @@ func debugf(str string, args ...interface{}) {
|
|||||||
fmt.Fprintf(os.Stderr, str, args...)
|
fmt.Fprintf(os.Stderr, str, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkGraph() *gg.Graph {
|
func mkGraph() (*gg.Graph, gg.Value) {
|
||||||
aE0 := gg.ValueOut(gg.Str("a"), gg.Str("aE0"))
|
a := gg.NewValue("a")
|
||||||
aE1 := gg.ValueOut(gg.Str("a"), gg.Str("aE1"))
|
aE0 := gg.NewValue("aE0")
|
||||||
aE2 := gg.ValueOut(gg.Str("a"), gg.Str("aE2"))
|
aE1 := gg.NewValue("aE1")
|
||||||
aE3 := gg.ValueOut(gg.Str("a"), gg.Str("aE3"))
|
aE2 := gg.NewValue("aE2")
|
||||||
|
aE3 := gg.NewValue("aE3")
|
||||||
|
b0 := gg.NewValue("b0")
|
||||||
|
b1 := gg.NewValue("b1")
|
||||||
|
b2 := gg.NewValue("b2")
|
||||||
|
b3 := gg.NewValue("b3")
|
||||||
|
oaE0 := gg.ValueOut(a, aE0)
|
||||||
|
oaE1 := gg.ValueOut(a, aE1)
|
||||||
|
oaE2 := gg.ValueOut(a, aE2)
|
||||||
|
oaE3 := gg.ValueOut(a, aE3)
|
||||||
g := gg.Null
|
g := gg.Null
|
||||||
g = g.AddValueIn(aE0, gg.Str("b0"))
|
g = g.AddValueIn(oaE0, b0)
|
||||||
g = g.AddValueIn(aE1, gg.Str("b1"))
|
g = g.AddValueIn(oaE1, b1)
|
||||||
g = g.AddValueIn(aE2, gg.Str("b2"))
|
g = g.AddValueIn(oaE2, b2)
|
||||||
g = g.AddValueIn(aE3, gg.Str("b3"))
|
g = g.AddValueIn(oaE3, b3)
|
||||||
|
|
||||||
|
c := gg.NewValue("c")
|
||||||
|
empty := gg.NewValue("")
|
||||||
jE := gg.JunctionOut([]gg.OpenEdge{
|
jE := gg.JunctionOut([]gg.OpenEdge{
|
||||||
gg.ValueOut(gg.Str("b0"), gg.Str("")),
|
gg.ValueOut(b0, empty),
|
||||||
gg.ValueOut(gg.Str("b1"), gg.Str("")),
|
gg.ValueOut(b1, empty),
|
||||||
gg.ValueOut(gg.Str("b2"), gg.Str("")),
|
gg.ValueOut(b2, empty),
|
||||||
gg.ValueOut(gg.Str("b3"), gg.Str("")),
|
gg.ValueOut(b3, empty),
|
||||||
}, gg.Str("jE"))
|
}, gg.NewValue("jE"))
|
||||||
g = g.AddValueIn(jE, gg.Str("c"))
|
g = g.AddValueIn(jE, c)
|
||||||
return g
|
return g, c
|
||||||
}
|
}
|
||||||
|
|
||||||
//func mkGraph() *gg.Graph {
|
//func mkGraph() *gg.Graph {
|
||||||
@ -68,11 +79,12 @@ func main() {
|
|||||||
term.Reset()
|
term.Reset()
|
||||||
term.HideCursor()
|
term.HideCursor()
|
||||||
|
|
||||||
|
g, start := mkGraph()
|
||||||
v := view{
|
v := view{
|
||||||
g: mkGraph(),
|
g: g,
|
||||||
primFlowDir: geo.Right,
|
primFlowDir: geo.Right,
|
||||||
secFlowDir: geo.Down,
|
secFlowDir: geo.Down,
|
||||||
start: gg.Str("c"),
|
start: start,
|
||||||
center: geo.Zero.Midpoint(term.WindowSize(), rounder),
|
center: geo.Zero.Midpoint(term.WindowSize(), rounder),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,12 +24,12 @@ func posSolve(g *gg.Graph) [][]*gg.Vertex {
|
|||||||
secEng := constraint.NewEngine()
|
secEng := constraint.NewEngine()
|
||||||
|
|
||||||
strM := g.ByID()
|
strM := g.ByID()
|
||||||
for vID, v := range strM {
|
for _, v := range strM {
|
||||||
var prevIn *gg.Vertex
|
var prevIn *gg.Vertex
|
||||||
for _, e := range v.In {
|
for _, e := range v.In {
|
||||||
primEng.AddConstraint(constraint.Constraint{
|
primEng.AddConstraint(constraint.Constraint{
|
||||||
Elem: e.From.ID,
|
Elem: e.From.ID,
|
||||||
LT: vID,
|
LT: v.ID,
|
||||||
})
|
})
|
||||||
if prevIn != nil {
|
if prevIn != nil {
|
||||||
secEng.AddConstraint(constraint.Constraint{
|
secEng.AddConstraint(constraint.Constraint{
|
||||||
@ -103,7 +103,7 @@ func centerBoxes(boxes []*box, around geo.XY) {
|
|||||||
type view struct {
|
type view struct {
|
||||||
g *gg.Graph
|
g *gg.Graph
|
||||||
primFlowDir, secFlowDir geo.XY
|
primFlowDir, secFlowDir geo.XY
|
||||||
start gg.Str
|
start gg.Value
|
||||||
center geo.XY
|
center geo.XY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user