github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/product/product.go (about) 1 // Copyright ©2019 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package product 6 7 import ( 8 "sort" 9 10 "github.com/jingcheng-WU/gonum/graph" 11 "github.com/jingcheng-WU/gonum/graph/internal/ordered" 12 "github.com/jingcheng-WU/gonum/stat/combin" 13 ) 14 15 // Node is a product of two graph nodes. 16 // All graph products return this type directly via relevant graph.Graph method 17 // call, or indirectly via calls to graph.Edge methods from returned edges. 18 type Node struct { 19 UID int64 20 21 // A and B hold the nodes from graph a and b in a 22 // graph product constructed by a product function. 23 A, B graph.Node 24 } 25 26 // ID implements the graph.Node interface. 27 func (n Node) ID() int64 { return n.UID } 28 29 // Cartesian constructs the Cartesian product of a and b in dst. 30 // 31 // The Cartesian product of G₁ and G₂, G₁□G₂ has edges (u₁, u₂)~(v₁, v₂) when 32 // (u₁=v₁ and u₂~v₂) or (u₁~v₁ and u₂=v₂). The Cartesian product has size m₂n₁+m₁n₂ 33 // where m is the size of the input graphs and n is their order. 34 func Cartesian(dst graph.Builder, a, b graph.Graph) { 35 aNodes, bNodes, product := cartesianNodes(a, b) 36 if len(product) == 0 { 37 return 38 } 39 40 indexOfA := indexOf(aNodes) 41 indexOfB := indexOf(bNodes) 42 43 for _, p := range product { 44 dst.AddNode(p) 45 } 46 47 dims := []int{len(aNodes), len(bNodes)} 48 for i, uA := range aNodes { 49 for j, uB := range bNodes { 50 toB := b.From(uB.ID()) 51 for toB.Next() { 52 dst.SetEdge(dst.NewEdge( 53 product[combin.IdxFor([]int{i, j}, dims)], 54 product[combin.IdxFor([]int{i, indexOfB[toB.Node().ID()]}, dims)], 55 )) 56 } 57 58 toA := a.From(uA.ID()) 59 for toA.Next() { 60 dst.SetEdge(dst.NewEdge( 61 product[combin.IdxFor([]int{i, j}, dims)], 62 product[combin.IdxFor([]int{indexOfA[toA.Node().ID()], j}, dims)], 63 )) 64 } 65 } 66 } 67 } 68 69 // Tensor constructs the Tensor product of a and b in dst. 70 // 71 // The Tensor product of G₁ and G₂, G₁⨯G₂ has edges (u₁, u₂)~(v₁, v₂) when 72 // u₁~v₁ and u₂~v₂. The Tensor product has size 2m₁m₂ where m is the size 73 // of the input graphs. 74 func Tensor(dst graph.Builder, a, b graph.Graph) { 75 aNodes, bNodes, product := cartesianNodes(a, b) 76 if len(product) == 0 { 77 return 78 } 79 80 indexOfA := indexOf(aNodes) 81 indexOfB := indexOf(bNodes) 82 83 for _, p := range product { 84 dst.AddNode(p) 85 } 86 87 dims := []int{len(aNodes), len(bNodes)} 88 for i, uA := range aNodes { 89 toA := a.From(uA.ID()) 90 for toA.Next() { 91 j := indexOfA[toA.Node().ID()] 92 for k, uB := range bNodes { 93 toB := b.From(uB.ID()) 94 for toB.Next() { 95 dst.SetEdge(dst.NewEdge( 96 product[combin.IdxFor([]int{i, k}, dims)], 97 product[combin.IdxFor([]int{j, indexOfB[toB.Node().ID()]}, dims)], 98 )) 99 } 100 } 101 } 102 } 103 } 104 105 // Lexicographical constructs the Lexicographical product of a and b in dst. 106 // 107 // The Lexicographical product of G₁ and G₂, G₁·G₂ has edges (u₁, u₂)~(v₁, v₂) when 108 // u₁~v₁ or (u₁=v₁ and u₂~v₂). The Lexicographical product has size m₂n₁+m₁n₂² 109 // where m is the size of the input graphs and n is their order. 110 func Lexicographical(dst graph.Builder, a, b graph.Graph) { 111 aNodes, bNodes, product := cartesianNodes(a, b) 112 if len(product) == 0 { 113 return 114 } 115 116 indexOfA := indexOf(aNodes) 117 indexOfB := indexOf(bNodes) 118 119 for _, p := range product { 120 dst.AddNode(p) 121 } 122 123 dims := []int{len(aNodes), len(bNodes)} 124 p := make([]int, 2) 125 for i, uA := range aNodes { 126 toA := a.From(uA.ID()) 127 for toA.Next() { 128 j := indexOfA[toA.Node().ID()] 129 gen := combin.NewCartesianGenerator([]int{len(bNodes), len(bNodes)}) 130 for gen.Next() { 131 p = gen.Product(p) 132 dst.SetEdge(dst.NewEdge( 133 product[combin.IdxFor([]int{i, p[0]}, dims)], 134 product[combin.IdxFor([]int{j, p[1]}, dims)], 135 )) 136 } 137 } 138 139 for j, uB := range bNodes { 140 toB := b.From(uB.ID()) 141 for toB.Next() { 142 dst.SetEdge(dst.NewEdge( 143 product[combin.IdxFor([]int{i, j}, dims)], 144 product[combin.IdxFor([]int{i, indexOfB[toB.Node().ID()]}, dims)], 145 )) 146 } 147 } 148 } 149 } 150 151 // Strong constructs the Strong product of a and b in dst. 152 // 153 // The Strong product of G₁ and G₂, G₁⊠G₂ has edges (u₁, u₂)~(v₁, v₂) when 154 // (u₁=v₁ and u₂~v₂) or (u₁~v₁ and u₂=v₂) or (u₁~v₁ and u₂~v₂). The Strong 155 // product has size n₁m₂+n₂m₁+2m₁m₂ where m is the size of the input graphs 156 // and n is their order. 157 func Strong(dst graph.Builder, a, b graph.Graph) { 158 aNodes, bNodes, product := cartesianNodes(a, b) 159 if len(product) == 0 { 160 return 161 } 162 163 indexOfA := indexOf(aNodes) 164 indexOfB := indexOf(bNodes) 165 166 for _, p := range product { 167 dst.AddNode(p) 168 } 169 170 dims := []int{len(aNodes), len(bNodes)} 171 for i, uA := range aNodes { 172 for j, uB := range bNodes { 173 toB := b.From(uB.ID()) 174 for toB.Next() { 175 dst.SetEdge(dst.NewEdge( 176 product[combin.IdxFor([]int{i, j}, dims)], 177 product[combin.IdxFor([]int{i, indexOfB[toB.Node().ID()]}, dims)], 178 )) 179 } 180 181 toA := a.From(uA.ID()) 182 for toA.Next() { 183 dst.SetEdge(dst.NewEdge( 184 product[combin.IdxFor([]int{i, j}, dims)], 185 product[combin.IdxFor([]int{indexOfA[toA.Node().ID()], j}, dims)], 186 )) 187 } 188 } 189 190 toA := a.From(uA.ID()) 191 for toA.Next() { 192 for j, uB := range bNodes { 193 toB := b.From(uB.ID()) 194 for toB.Next() { 195 dst.SetEdge(dst.NewEdge( 196 product[combin.IdxFor([]int{i, j}, dims)], 197 product[combin.IdxFor([]int{indexOfA[toA.Node().ID()], indexOfB[toB.Node().ID()]}, dims)], 198 )) 199 } 200 } 201 } 202 } 203 } 204 205 // CoNormal constructs the Co-normal product of a and b in dst. 206 // 207 // The Co-normal product of G₁ and G₂, G₁*G₂ (or G₁[G₂]) has edges (u₁, u₂)~(v₁, v₂) 208 // when u₁~v₁ or u₂~v₂. The Co-normal product is non-commutative. 209 func CoNormal(dst graph.Builder, a, b graph.Graph) { 210 aNodes, bNodes, product := cartesianNodes(a, b) 211 if len(product) == 0 { 212 return 213 } 214 215 indexOfA := indexOf(aNodes) 216 indexOfB := indexOf(bNodes) 217 218 for _, p := range product { 219 dst.AddNode(p) 220 } 221 222 dims := []int{len(aNodes), len(bNodes)} 223 p := make([]int, 2) 224 for i, u := range aNodes { 225 to := a.From(u.ID()) 226 for to.Next() { 227 j := indexOfA[to.Node().ID()] 228 gen := combin.NewCartesianGenerator([]int{len(bNodes), len(bNodes)}) 229 for gen.Next() { 230 p = gen.Product(p) 231 dst.SetEdge(dst.NewEdge( 232 product[combin.IdxFor([]int{i, p[0]}, dims)], 233 product[combin.IdxFor([]int{j, p[1]}, dims)], 234 )) 235 } 236 } 237 } 238 for i, u := range bNodes { 239 to := b.From(u.ID()) 240 for to.Next() { 241 j := indexOfB[to.Node().ID()] 242 gen := combin.NewCartesianGenerator([]int{len(aNodes), len(aNodes)}) 243 for gen.Next() { 244 p = gen.Product(p) 245 dst.SetEdge(dst.NewEdge( 246 product[combin.IdxFor([]int{p[0], i}, dims)], 247 product[combin.IdxFor([]int{p[1], j}, dims)], 248 )) 249 } 250 } 251 } 252 } 253 254 // Modular constructs the Modular product of a and b in dst. 255 // 256 // The Modular product of G₁ and G₂, G₁◊G₂ has edges (u₁, u₂)~(v₁, v₂) 257 // when (u₁~v₁ and u₂~v₂) or (u₁≁v₁ and u₂≁v₂), and (u₁≠v₁ and u₂≠v₂). 258 // 259 // Modular is O(n^2) time where n is the order of the Cartesian product 260 // of a and b. 261 func Modular(dst graph.Builder, a, b graph.Graph) { 262 _, _, product := cartesianNodes(a, b) 263 if len(product) == 0 { 264 return 265 } 266 267 for _, p := range product { 268 dst.AddNode(p) 269 } 270 271 _, aUndirected := a.(graph.Undirected) 272 _, bUndirected := b.(graph.Undirected) 273 _, dstUndirected := dst.(graph.Undirected) 274 undirected := aUndirected && bUndirected && dstUndirected 275 276 n := len(product) 277 if undirected { 278 n-- 279 } 280 for i, u := range product[:n] { 281 var m int 282 if undirected { 283 m = i + 1 284 } 285 for _, v := range product[m:] { 286 if u.A.ID() == v.A.ID() || u.B.ID() == v.B.ID() { 287 // No self-loops. 288 continue 289 } 290 inA := a.Edge(u.A.ID(), v.A.ID()) != nil 291 inB := b.Edge(u.B.ID(), v.B.ID()) != nil 292 if inA == inB { 293 dst.SetEdge(dst.NewEdge(u, v)) 294 } 295 } 296 } 297 } 298 299 // ModularExt constructs the Modular product of a and b in dst with 300 // additional control over assessing edge agreement. 301 // 302 // In addition to the modular product conditions, agree(u₁v₁, u₂v₂) must 303 // return true when (u₁~v₁ and u₂~v₂) for an edge to be added between 304 // (u₁, u₂) and (v₁, v₂) in dst. If agree is nil, Modular is called. 305 // 306 // ModularExt is O(n^2) time where n is the order of the Cartesian product 307 // of a and b. 308 func ModularExt(dst graph.Builder, a, b graph.Graph, agree func(eA, eB graph.Edge) bool) { 309 if agree == nil { 310 Modular(dst, a, b) 311 return 312 } 313 314 _, _, product := cartesianNodes(a, b) 315 if len(product) == 0 { 316 return 317 } 318 319 for _, p := range product { 320 dst.AddNode(p) 321 } 322 323 _, aUndirected := a.(graph.Undirected) 324 _, bUndirected := b.(graph.Undirected) 325 _, dstUndirected := dst.(graph.Undirected) 326 undirected := aUndirected && bUndirected && dstUndirected 327 328 n := len(product) 329 if undirected { 330 n-- 331 } 332 for i, u := range product[:n] { 333 var m int 334 if undirected { 335 m = i + 1 336 } 337 for _, v := range product[m:] { 338 if u.A.ID() == v.A.ID() || u.B.ID() == v.B.ID() { 339 // No self-loops. 340 continue 341 } 342 eA := a.Edge(u.A.ID(), v.A.ID()) 343 eB := b.Edge(u.B.ID(), v.B.ID()) 344 inA := eA != nil 345 inB := eB != nil 346 if (inA && inB && agree(eA, eB)) || (!inA && !inB) { 347 dst.SetEdge(dst.NewEdge(u, v)) 348 } 349 } 350 } 351 } 352 353 // cartesianNodes returns the Cartesian product of the nodes in a and b. 354 func cartesianNodes(a, b graph.Graph) (aNodes, bNodes []graph.Node, product []Node) { 355 aNodes = lexicalNodes(a) 356 bNodes = lexicalNodes(b) 357 358 lens := []int{len(aNodes), len(bNodes)} 359 product = make([]Node, combin.Card(lens)) 360 gen := combin.NewCartesianGenerator(lens) 361 p := make([]int, 2) 362 for id := int64(0); gen.Next(); id++ { 363 p = gen.Product(p) 364 product[id] = Node{UID: id, A: aNodes[p[0]], B: bNodes[p[1]]} 365 } 366 return aNodes, bNodes, product 367 } 368 369 // lexicalNodes returns the nodes in g sorted lexically by node ID. 370 func lexicalNodes(g graph.Graph) []graph.Node { 371 nodes := graph.NodesOf(g.Nodes()) 372 sort.Sort(ordered.ByID(nodes)) 373 return nodes 374 } 375 376 func indexOf(nodes []graph.Node) map[int64]int { 377 idx := make(map[int64]int, len(nodes)) 378 for i, n := range nodes { 379 idx[n.ID()] = i 380 } 381 return idx 382 }