mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-26 16:45:18 +00:00
add inmemory dev mock for hypergraph
This commit is contained in:
parent
26195cef5f
commit
310bd6fc11
242
node/hypergraph/inmem/hypergraph_crdt.go
Normal file
242
node/hypergraph/inmem/hypergraph_crdt.go
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
package inmem
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var ErrInvalidLocation error = errors.New("invalid location")
|
||||||
|
var ErrMissingExtrinsics error = errors.New("missing extrinsics")
|
||||||
|
var ErrIsExtrinsic error = errors.New("is extrinsic")
|
||||||
|
|
||||||
|
type HypergraphCRDT struct {
|
||||||
|
locations map[Location]struct{}
|
||||||
|
|
||||||
|
vertexAdds map[Location]*IdSet
|
||||||
|
vertexRemoves map[Location]*IdSet
|
||||||
|
hyperedgeAdds map[Location]*IdSet
|
||||||
|
hyperedgeRemoves map[Location]*IdSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHypergraphCRDT(locations []Location) *HypergraphCRDT {
|
||||||
|
hypergraph := &HypergraphCRDT{
|
||||||
|
locations: make(map[Location]struct{}),
|
||||||
|
vertexAdds: make(map[Location]*IdSet),
|
||||||
|
vertexRemoves: make(map[Location]*IdSet),
|
||||||
|
hyperedgeAdds: make(map[Location]*IdSet),
|
||||||
|
hyperedgeRemoves: make(map[Location]*IdSet),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, l := range locations {
|
||||||
|
hypergraph.locations[l] = struct{}{}
|
||||||
|
hypergraph.vertexAdds[l] = NewIdSet("vertex")
|
||||||
|
hypergraph.vertexRemoves[l] = NewIdSet("vertex")
|
||||||
|
hypergraph.hyperedgeAdds[l] = NewIdSet("hyperedge")
|
||||||
|
hypergraph.hyperedgeRemoves[l] = NewIdSet("hyperedge")
|
||||||
|
}
|
||||||
|
|
||||||
|
return hypergraph
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hg *HypergraphCRDT) AddAtom(a Atom) error {
|
||||||
|
switch v := a.(type) {
|
||||||
|
case *Vertex:
|
||||||
|
hg.AddVertex(v)
|
||||||
|
return nil
|
||||||
|
case *Hyperedge:
|
||||||
|
return hg.AddHyperedge(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hg *HypergraphCRDT) AddVertex(v *Vertex) {
|
||||||
|
shardMap := ShardVertex(v)
|
||||||
|
for location, vertices := range shardMap {
|
||||||
|
for _, vertex := range vertices.VertexSet.atoms {
|
||||||
|
if vert, ok := vertex.(*Vertex); ok {
|
||||||
|
hg.vertexAdds[location].Add(vert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hg *HypergraphCRDT) AddVertexSet(vertices *IdSet) error {
|
||||||
|
if vertices.atomType != "vertex" {
|
||||||
|
return ErrInvalidAtomType
|
||||||
|
}
|
||||||
|
|
||||||
|
shardMap := ShardAtomSet(vertices.atoms)
|
||||||
|
for location, vertices := range shardMap {
|
||||||
|
for _, vertex := range vertices.VertexSet.atoms {
|
||||||
|
if vert, ok := vertex.(*Vertex); ok {
|
||||||
|
hg.vertexAdds[location].Add(vert)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hg *HypergraphCRDT) AddHyperedge(h *Hyperedge) error {
|
||||||
|
if hg.LookupAtomSet(h.extrinsics) {
|
||||||
|
shardMap := ShardHyperedge(h)
|
||||||
|
|
||||||
|
for location, set := range shardMap {
|
||||||
|
for _, hyperedge := range set.HyperedgeSet.atoms {
|
||||||
|
if he, ok := hyperedge.(*Hyperedge); ok {
|
||||||
|
hg.hyperedgeAdds[location].Add(he)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, vertex := range set.VertexSet.atoms {
|
||||||
|
if v, ok := vertex.(*Vertex); ok {
|
||||||
|
hg.hyperedgeAdds[location].Add(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return ErrMissingExtrinsics
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hg *HypergraphCRDT) RemoveAtom(a Atom) error {
|
||||||
|
switch v := a.(type) {
|
||||||
|
case *Vertex:
|
||||||
|
return hg.RemoveVertex(v)
|
||||||
|
case *Hyperedge:
|
||||||
|
return hg.RemoveHyperedge(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hg *HypergraphCRDT) RemoveVertex(v *Vertex) error {
|
||||||
|
if hg.LookupVertex(v) {
|
||||||
|
for l, hyperedgeAdds := range hg.hyperedgeAdds {
|
||||||
|
for _, hyperedge := range hyperedgeAdds.atoms {
|
||||||
|
he, ok := hyperedge.(*Hyperedge)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !hg.hyperedgeRemoves[l].Has(he) {
|
||||||
|
if _, ok := he.extrinsics[v.GetID()]; ok {
|
||||||
|
return ErrIsExtrinsic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hg.vertexRemoves[v.location].Add(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hg *HypergraphCRDT) RemoveHyperedge(h *Hyperedge) error {
|
||||||
|
if hg.LookupAtom(h) {
|
||||||
|
for l, hyperedgeAdds := range hg.hyperedgeAdds {
|
||||||
|
for _, hyperedge := range hyperedgeAdds.atoms {
|
||||||
|
he, ok := hyperedge.(*Hyperedge)
|
||||||
|
if !ok || hg.hyperedgeRemoves[l].Has(he) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := he.extrinsics[h.GetID()]; ok {
|
||||||
|
return ErrIsExtrinsic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hg.hyperedgeRemoves[h.location].Add(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hg *HypergraphCRDT) LookupAtom(a Atom) bool {
|
||||||
|
if _, ok := hg.locations[a.GetLocation()]; !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := a.(type) {
|
||||||
|
case *Vertex:
|
||||||
|
return hg.LookupVertex(v)
|
||||||
|
case *Hyperedge:
|
||||||
|
return hg.LookupHyperedge(v)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupAtomSet checks all atoms in an IdSet to see if they all can be looked
|
||||||
|
// up successfully.
|
||||||
|
func (hg *HypergraphCRDT) LookupAtomSet(atomSet map[string]Atom) bool {
|
||||||
|
for _, atom := range atomSet {
|
||||||
|
if !hg.LookupAtom(atom) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupVertex checks if a vertex is added and not removed in the current
|
||||||
|
// location.
|
||||||
|
func (hg *HypergraphCRDT) LookupVertex(v *Vertex) bool {
|
||||||
|
location := v.GetLocation()
|
||||||
|
return hg.vertexAdds[location].Has(v) && !hg.vertexRemoves[location].Has(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupHyperedge checks if a hyperedge and its extrinsics can be looked up.
|
||||||
|
func (hg *HypergraphCRDT) LookupHyperedge(h *Hyperedge) bool {
|
||||||
|
return hg.LookupAtomSet(h.extrinsics) &&
|
||||||
|
hg.hyperedgeAdds[h.GetLocation()].Has(h) &&
|
||||||
|
!hg.hyperedgeRemoves[h.GetLocation()].Has(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Within checks if atom `a` is within hyperedge `h` directly or transitively.
|
||||||
|
func (hg *HypergraphCRDT) Within(a, h Atom) bool {
|
||||||
|
switch ha := h.(type) {
|
||||||
|
case *Hyperedge:
|
||||||
|
_, ok := ha.extrinsics[a.GetID()]
|
||||||
|
if ok || a.GetID() == h.GetID() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, extrinsic := range ha.extrinsics {
|
||||||
|
if he, ok := extrinsic.(*Hyperedge); ok {
|
||||||
|
for _, hyperExtrinsic := range he.extrinsics {
|
||||||
|
if hyperHe, ok := hyperExtrinsic.(*Hyperedge); ok {
|
||||||
|
if hg.LookupHyperedge(hyperHe) {
|
||||||
|
if _, ok := hyperHe.extrinsics[a.GetID()]; ok &&
|
||||||
|
hg.Within(hyperHe, h) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReconciledVertexSet computes the set of vertices that have been added but
|
||||||
|
// not removed for a location.
|
||||||
|
func (hg *HypergraphCRDT) GetReconciledVertexSet(l Location) *IdSet {
|
||||||
|
vertices := NewIdSet("vertex")
|
||||||
|
for _, v := range hg.vertexAdds[l].atoms {
|
||||||
|
if !hg.vertexRemoves[l].Has(v) {
|
||||||
|
vertices.Add(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vertices
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReconciledHyperedgeSet computes the set of hyperedges that have been added
|
||||||
|
// but not removed for a location.
|
||||||
|
func (hg *HypergraphCRDT) GetReconciledHyperedgeSet(l Location) *IdSet {
|
||||||
|
hyperedges := NewIdSet("hyperedge")
|
||||||
|
for _, h := range hg.hyperedgeAdds[l].atoms {
|
||||||
|
if !hg.hyperedgeRemoves[l].Has(h) {
|
||||||
|
hyperedges.Add(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hyperedges
|
||||||
|
}
|
75
node/hypergraph/inmem/hypergraph_test.go
Normal file
75
node/hypergraph/inmem/hypergraph_test.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package inmem_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
hypergraph "source.quilibrium.com/quilibrium/monorepo/node/hypergraph/inmem"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIdSet(t *testing.T) {
|
||||||
|
v := hypergraph.NewVertex("1", "here")
|
||||||
|
h := hypergraph.NewHyperedge("2", "here", make(map[string]hypergraph.Atom))
|
||||||
|
|
||||||
|
vset := hypergraph.NewIdSet("vertex")
|
||||||
|
hset := hypergraph.NewIdSet("hyperedge")
|
||||||
|
assert.NoError(t, vset.Add(v))
|
||||||
|
assert.NoError(t, hset.Add(h))
|
||||||
|
|
||||||
|
assert.True(t, vset.Has(v))
|
||||||
|
assert.True(t, hset.Has(h))
|
||||||
|
|
||||||
|
vset.Delete(v)
|
||||||
|
assert.False(t, hset.Has(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCRDT(t *testing.T) {
|
||||||
|
loc1 := hypergraph.Location("here1")
|
||||||
|
loc2 := hypergraph.Location("here2")
|
||||||
|
hg := hypergraph.NewHypergraphCRDT([]hypergraph.Location{loc1, loc2})
|
||||||
|
|
||||||
|
v1 := hypergraph.NewVertex("1", loc1)
|
||||||
|
v2 := hypergraph.NewVertex("2", loc2)
|
||||||
|
h1 := hypergraph.NewHyperedge("h1", loc1, make(map[string]hypergraph.Atom))
|
||||||
|
|
||||||
|
hg.AddVertex(v1)
|
||||||
|
hg.AddVertex(v2)
|
||||||
|
hg.AddHyperedge(h1)
|
||||||
|
h2vs := map[string]hypergraph.Atom{}
|
||||||
|
h2vs["1"] = v1
|
||||||
|
h2vs["2"] = v2
|
||||||
|
h2 := hypergraph.NewHyperedge("h2", loc2, h2vs)
|
||||||
|
hg.AddHyperedge(h2)
|
||||||
|
|
||||||
|
h3vs := map[string]hypergraph.Atom{}
|
||||||
|
h3vs["h2"] = h2
|
||||||
|
h3 := hypergraph.NewHyperedge("h3", loc1, h3vs)
|
||||||
|
hg.AddHyperedge(h3)
|
||||||
|
|
||||||
|
assert.NotNil(t, hg.LookupVertex(v1))
|
||||||
|
assert.NotNil(t, hg.LookupVertex(v2))
|
||||||
|
assert.NotNil(t, hg.LookupHyperedge(h1))
|
||||||
|
assert.NotNil(t, hg.LookupHyperedge(h2))
|
||||||
|
assert.NotNil(t, hg.LookupHyperedge(h3))
|
||||||
|
|
||||||
|
assert.True(t, hg.GetReconciledVertexSet(v1.GetLocation()).Has(v1))
|
||||||
|
assert.False(t, hg.GetReconciledVertexSet(v1.GetLocation()).Has(v2))
|
||||||
|
assert.True(t, hg.GetReconciledVertexSet(v2.GetLocation()).Has(v2))
|
||||||
|
assert.True(t, hg.GetReconciledHyperedgeSet(v1.GetLocation()).Has(h1))
|
||||||
|
assert.False(t, hg.GetReconciledHyperedgeSet(h1.GetLocation()).Has(h2))
|
||||||
|
assert.True(t, hg.GetReconciledHyperedgeSet(h2.GetLocation()).Has(h2))
|
||||||
|
assert.True(t, hg.GetReconciledHyperedgeSet(h3.GetLocation()).Has(h3))
|
||||||
|
|
||||||
|
assert.Error(t, hg.RemoveHyperedge(h2))
|
||||||
|
assert.True(t, hg.GetReconciledHyperedgeSet(h2.GetLocation()).Has(h2))
|
||||||
|
assert.NoError(t, hg.RemoveHyperedge(h3))
|
||||||
|
assert.False(t, hg.GetReconciledHyperedgeSet(h3.GetLocation()).Has(h3))
|
||||||
|
assert.Error(t, hg.RemoveVertex(v1))
|
||||||
|
assert.True(t, hg.GetReconciledVertexSet(v1.GetLocation()).Has(v1))
|
||||||
|
assert.NoError(t, hg.RemoveHyperedge(h2))
|
||||||
|
assert.False(t, hg.GetReconciledHyperedgeSet(h2.GetLocation()).Has(h2))
|
||||||
|
assert.NoError(t, hg.RemoveVertex(v1))
|
||||||
|
assert.False(t, hg.GetReconciledVertexSet(v1.GetLocation()).Has(v1))
|
||||||
|
assert.NoError(t, hg.RemoveVertex(v2))
|
||||||
|
assert.False(t, hg.GetReconciledVertexSet(v2.GetLocation()).Has(v2))
|
||||||
|
}
|
89
node/hypergraph/inmem/shard.go
Normal file
89
node/hypergraph/inmem/shard.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package inmem
|
||||||
|
|
||||||
|
func InShard(a Atom, l Location) bool {
|
||||||
|
return a.GetLocation() == l
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShardSet struct {
|
||||||
|
VertexSet *IdSet
|
||||||
|
HyperedgeSet *IdSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func ShardAtom(a Atom) map[Location]*ShardSet {
|
||||||
|
switch atom := a.(type) {
|
||||||
|
case *Vertex:
|
||||||
|
return ShardVertex(atom)
|
||||||
|
case *Hyperedge:
|
||||||
|
return ShardHyperedge(atom)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ShardAtomSet(atomSet map[string]Atom) map[Location]*ShardSet {
|
||||||
|
result := make(map[Location]*ShardSet)
|
||||||
|
for _, a := range atomSet {
|
||||||
|
result[a.GetLocation()] = &ShardSet{
|
||||||
|
VertexSet: NewIdSet("vertex"),
|
||||||
|
HyperedgeSet: NewIdSet("hyperedge"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, atom := range atomSet {
|
||||||
|
shard := ShardAtom(atom)
|
||||||
|
for location, locationShard := range shard {
|
||||||
|
for _, locationAtom := range locationShard.VertexSet.atoms {
|
||||||
|
if _, ok := result[location]; !ok {
|
||||||
|
result[location] = &ShardSet{
|
||||||
|
VertexSet: NewIdSet("vertex"),
|
||||||
|
HyperedgeSet: NewIdSet("hyperedge"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[location].VertexSet.Add(locationAtom)
|
||||||
|
}
|
||||||
|
for _, locationAtom := range locationShard.HyperedgeSet.atoms {
|
||||||
|
if _, ok := result[location]; !ok {
|
||||||
|
result[location] = &ShardSet{
|
||||||
|
VertexSet: NewIdSet("vertex"),
|
||||||
|
HyperedgeSet: NewIdSet("hyperedge"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[location].HyperedgeSet.Add(locationAtom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func ShardVertex(v *Vertex) map[Location]*ShardSet {
|
||||||
|
result := make(map[Location]*ShardSet)
|
||||||
|
if _, ok := result[v.location]; !ok {
|
||||||
|
result[v.location] = &ShardSet{
|
||||||
|
VertexSet: NewIdSet("vertex"),
|
||||||
|
HyperedgeSet: NewIdSet("hyperedge"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[v.location].VertexSet.Add(v)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShardHyperedge shards a hyperedge and its extrinsics across locations.
|
||||||
|
func ShardHyperedge(h *Hyperedge) map[Location]*ShardSet {
|
||||||
|
extrinsicShardSet := ShardAtomSet(h.extrinsics)
|
||||||
|
result := make(map[Location]*ShardSet)
|
||||||
|
|
||||||
|
for l, s := range extrinsicShardSet {
|
||||||
|
result[l] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := result[h.location]; !ok {
|
||||||
|
result[h.location] = &ShardSet{
|
||||||
|
VertexSet: NewIdSet("vertex"),
|
||||||
|
HyperedgeSet: NewIdSet("hyperedge"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result[h.location].HyperedgeSet.Add(h)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
133
node/hypergraph/inmem/types.go
Normal file
133
node/hypergraph/inmem/types.go
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package inmem
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
type AtomType string
|
||||||
|
type Location string
|
||||||
|
|
||||||
|
var ErrInvalidAtomType error = errors.New("invalid atom type for set")
|
||||||
|
|
||||||
|
type Vertex struct {
|
||||||
|
id string
|
||||||
|
location Location
|
||||||
|
}
|
||||||
|
|
||||||
|
type Hyperedge struct {
|
||||||
|
id string
|
||||||
|
location Location
|
||||||
|
extrinsics map[string]Atom
|
||||||
|
}
|
||||||
|
|
||||||
|
type Atom interface {
|
||||||
|
GetID() string
|
||||||
|
GetAtomType() AtomType
|
||||||
|
GetLocation() Location
|
||||||
|
}
|
||||||
|
|
||||||
|
var _v Atom = (*Vertex)(nil)
|
||||||
|
var _h Atom = (*Hyperedge)(nil)
|
||||||
|
|
||||||
|
func NewVertex(id string, location Location) *Vertex {
|
||||||
|
return &Vertex{
|
||||||
|
id,
|
||||||
|
location,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHyperedge(
|
||||||
|
id string,
|
||||||
|
location Location,
|
||||||
|
extrinsics map[string]Atom,
|
||||||
|
) *Hyperedge {
|
||||||
|
return &Hyperedge{
|
||||||
|
id,
|
||||||
|
location,
|
||||||
|
extrinsics,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Vertex) GetID() string {
|
||||||
|
return v.id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Hyperedge) GetID() string {
|
||||||
|
return h.id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Vertex) GetAtomType() AtomType {
|
||||||
|
return "vertex"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Hyperedge) GetAtomType() AtomType {
|
||||||
|
return "hyperedge"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Vertex) GetLocation() Location {
|
||||||
|
return v.location
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Hyperedge) GetLocation() Location {
|
||||||
|
return h.location
|
||||||
|
}
|
||||||
|
|
||||||
|
type IdSet struct {
|
||||||
|
atomType AtomType
|
||||||
|
atoms map[string]Atom
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIdSet(atomType AtomType) *IdSet {
|
||||||
|
return &IdSet{atomType: atomType, atoms: make(map[string]Atom)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds an atom to the IdSet if it's not already present.
|
||||||
|
func (set *IdSet) Add(atom Atom) error {
|
||||||
|
switch a := atom.(type) {
|
||||||
|
case *Vertex:
|
||||||
|
if set.atomType != "vertex" {
|
||||||
|
return ErrInvalidAtomType
|
||||||
|
}
|
||||||
|
if _, exists := set.atoms[a.GetID()]; !exists {
|
||||||
|
set.atoms[a.GetID()] = a
|
||||||
|
}
|
||||||
|
case *Hyperedge:
|
||||||
|
if set.atomType != "hyperedge" {
|
||||||
|
return ErrInvalidAtomType
|
||||||
|
}
|
||||||
|
if _, exists := set.atoms[a.GetID()]; !exists {
|
||||||
|
set.atoms[a.GetID()] = a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes an atom from the IdSet and returns true if the atom was
|
||||||
|
// present.
|
||||||
|
func (set *IdSet) Delete(atom Atom) bool {
|
||||||
|
switch a := atom.(type) {
|
||||||
|
case *Vertex:
|
||||||
|
if _, exists := set.atoms[a.GetID()]; exists {
|
||||||
|
delete(set.atoms, a.GetID())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case *Hyperedge:
|
||||||
|
if _, exists := set.atoms[a.GetID()]; exists {
|
||||||
|
delete(set.atoms, a.GetID())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has checks if an atom is in the IdSet.
|
||||||
|
func (set *IdSet) Has(atom Atom) bool {
|
||||||
|
switch a := atom.(type) {
|
||||||
|
case *Vertex:
|
||||||
|
_, exists := set.atoms[a.GetID()]
|
||||||
|
return exists
|
||||||
|
case *Hyperedge:
|
||||||
|
_, exists := set.atoms[a.GetID()]
|
||||||
|
return exists
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user