topologicpy 0.8.20__py3-none-any.whl → 0.8.22__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
topologicpy/Dictionary.py CHANGED
@@ -773,7 +773,7 @@ class Dictionary():
773
773
  return None
774
774
 
775
775
  @staticmethod
776
- def ValueAtKey(dictionary, key, silent=False):
776
+ def ValueAtKey(dictionary, key, defaultValue=None, silent=False):
777
777
  """
778
778
  Returns the value of the input key in the input dictionary.
779
779
 
@@ -783,6 +783,8 @@ class Dictionary():
783
783
  The input dictionary.
784
784
  key : string
785
785
  The input key.
786
+ defaultValue : any , optional
787
+ The default value to return if the key or value are not found. The default is None.
786
788
  silent : bool , optional
787
789
  If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
788
790
 
@@ -804,10 +806,10 @@ class Dictionary():
804
806
  return None
805
807
  if Topology.IsInstance(dictionary, "Dictionary"):
806
808
  dic = Dictionary.PythonDictionary(dictionary)
807
- return dic.get(key, None)
809
+ return dic.get(key, defaultValue)
808
810
  elif isinstance(dictionary, dict):
809
- return dictionary.get(key, None)
810
- return None
811
+ return dictionary.get(key, defaultValue)
812
+ return defaultValue
811
813
 
812
814
  # if isinstance(dictionary, dict):
813
815
  # attr = dictionary[key]
topologicpy/Graph.py CHANGED
@@ -4379,17 +4379,26 @@ class Graph:
4379
4379
 
4380
4380
  @staticmethod
4381
4381
  def Compare(graphA, graphB,
4382
- weightAttributes: float = 1.0,
4383
- weightGeometry: float = 1.0,
4384
- weightMetrics: float = 1.0,
4385
- weightStructure: float = 1.0,
4386
- weightWL: float = 1.0,
4382
+ weightAttributes: float = 0.0,
4383
+ weightGeometry: float = 0.0,
4384
+ weightBetwennessCentrality: float = 0.0,
4385
+ weightClosenessCentrality: float = 0.0,
4386
+ weightDegreeCentrality: float = 0.0,
4387
+ weightDiameter: float = 0.0,
4388
+ weightGlobalClusteringCoefficient: float = 0.0,
4389
+ weightPageRank: float = 0.0,
4390
+ weightStructure: float = 0.0,
4391
+ weightWeisfeilerLehman: float = 0.0,
4392
+ weightJaccard: float = 0.0,
4393
+ vertexIDKey: str = "id",
4394
+ edgeWeightKey: str = None,
4387
4395
  iterations: int = 3,
4388
4396
  mantissa: int = 6,
4389
4397
  silent: bool = False):
4390
4398
  """
4391
- Compares two graphs and returns a similarity score based on attributres, geometry, metrics, structure, and
4399
+ Compares two graphs and returns a similarity score based on attributres, geometry, metrics, structure,
4392
4400
  the Weisfeiler-Lehman graph kernel. See https://en.wikipedia.org/wiki/Weisfeiler_Leman_graph_isomorphism_test
4401
+ , and the weight Jaccard Similarity. See https://www.statology.org/jaccard-similarity/
4393
4402
 
4394
4403
  Parameters
4395
4404
  ----------
@@ -4398,16 +4407,34 @@ class Graph:
4398
4407
  graphB : topologic Graph
4399
4408
  The second input graph.
4400
4409
  weightAttributes : float , optional
4401
- The desired weight for attribute similarity (dictionary key overlap at vertices). Default is 1.0.
4410
+ The desired weight for attribute similarity (dictionary key overlap at vertices). Default is 0.0.
4411
+ weightBetwennessCentrality : float , optional
4412
+ The desired weight for betweenness centrality similarity (graph-level and node-level). Default is 0.0.
4413
+ weightClosenessCentrality : float , optional
4414
+ The desired weight for closeness centrality similarity (graph-level and node-level). Default is 0.0.
4415
+ weightDegreeCentrality : float , optional
4416
+ The desired weight for degree centrality similarity (graph-level and node-level). Default is 0.0.
4417
+ weightDiameter : float , optional
4418
+ The desired weight for diameter similarity (graph-level and node-level). Default is 0.0.
4402
4419
  weightGeometry : float , optional
4403
- The desired weight for geometric similarity (vertex positions). Default is 1.0.
4404
- weightMetrics : float , optional
4405
- The desired weight for metric similarity (graph-level and node-level). Default is 1.0.
4406
- The compared metrics are: betweenness centrality, closeness centrality, clustering coefficient, degree, diameter, and pagerank.
4420
+ The desired weight for geometric similarity (vertex positions). Default is 0.0.
4421
+ weightGlobalClusteringCoefficient : float , optional
4422
+ The desired weight for global clustering coefficient similarity (graph-level and node-level). Default is 0.0.
4423
+ weightJaccard: float , optional
4424
+ The desired weight for the Weighted Jaccard similarity. Default is 0.0.
4425
+ weightPageRank : float , optional
4426
+ The desired weight for PageRank similarity (graph-level and node-level). Default is 0.0.
4407
4427
  weightStructure : float , optional
4408
- The desired weight for structural similarity (number of vertices and edges). Default is 1.0.
4409
- weightWL : float , optional
4410
- The desired weight for Weisfeiler-Lehman kernel similarity (iterative label propagation). Default is 1.0.
4428
+ The desired weight for structural similarity (number of vertices and edges). Default is 0.0.
4429
+ weightWeisfeilerLehman : float , optional
4430
+ The desired weight for Weisfeiler-Lehman kernel similarity (iterative label propagation). Default is 0.0.
4431
+
4432
+ vertexIDKey: str , optional
4433
+ The dictionary key under which to find the unique vertex ID. The default is "id".
4434
+ edgeWeightKey: str , optional
4435
+ The dictionary key under which to find the weight of the edge for weighted graphs.
4436
+ If this parameter is specified as "length" or "distance" then the length of the edge is used as its weight.
4437
+ The default is None which means all edges are treated as if they have a weight of 1.
4411
4438
  iterations : int , optional
4412
4439
  The desired number of Weisfeiler-Lehman iterations. Default is 3.
4413
4440
  mantissa : int , optional
@@ -4421,12 +4448,16 @@ class Graph:
4421
4448
  A dictionary of similarity scores between 0 (completely dissimilar) and 1 (identical), based on weighted components.
4422
4449
  The keys in the dictionary are:
4423
4450
  "attribute"
4451
+ "betwenness_centrality"
4452
+ "closeness_centrality"
4453
+ "degree_centrality"
4424
4454
  "geometry"
4425
- "metrics"
4455
+ "global_clustering_coefficient"
4456
+ "jaccard"
4457
+ "pagerank"
4426
4458
  "structure"
4427
- "wl"
4459
+ "weisfeiler_lehman"
4428
4460
  "overall"
4429
-
4430
4461
  """
4431
4462
 
4432
4463
  import hashlib
@@ -4473,40 +4504,122 @@ class Graph:
4473
4504
  avg_dist = total_dist / len(v1)
4474
4505
  return round(1 / (1 + avg_dist), mantissa) # Inverse average distance
4475
4506
 
4476
- def metrics_similarity(graphA, graphB, mantissa=6):
4477
- # Example using global metrics + mean of node metrics
4478
- def safe_mean(lst):
4479
- return sum(lst)/len(lst) if lst else 0
4507
+ def weighted_jaccard_similarity(graph1, graph2, vertexIDKey="id", edgeWeightKey=None, mantissa=6):
4508
+ """
4509
+ Computes weighted Jaccard similarity between two graphs by comparing their edge weights.
4510
+
4511
+ Parameters
4512
+ ----------
4513
+ graph1 : topologic Graph
4514
+ First graph.
4515
+ graph2 : topologic Graph
4516
+ Second graph.
4517
+ vertexIDKey: str , optional
4518
+ The dictionary key under which to find the unique vertex ID. The default is "id".
4519
+ edgeWeightKey: str , optional
4520
+ The dictionary key under which to find the weight of the edge for weighted graphs.
4521
+ If this parameter is specified as "length" or "distance" then the length of the edge is used as its weight.
4522
+ The default is None which means all edges are treated as if they have a weight of 1.
4523
+ iterations : int , optional
4524
+ The desired number of Weisfeiler-Lehman iterations. Default is 3.
4525
+ mantissa : int , optional
4526
+ The desired length of the mantissa. The default is 6.
4527
+
4528
+ Returns
4529
+ -------
4530
+ float
4531
+ Similarity score between 0 and 1.
4532
+ """
4533
+ from topologicpy.Vertex import Vertex
4534
+ from topologicpy.Graph import Graph
4535
+ from topologicpy.Topology import Topology
4536
+ from topologicpy.Dictionary import Dictionary
4537
+ from topologicpy.Edge import Edge
4480
4538
 
4481
- metrics1 = {
4482
- "closeness": safe_mean(Graph.ClosenessCentrality(graphA)),
4483
- "betweenness": safe_mean(Graph.BetweennessCentrality(graphA)),
4484
- "degree": safe_mean(Graph.DegreeCentrality(graphA)),
4485
- "pagerank": safe_mean(Graph.PageRank(graphA)),
4486
- "clustering": Graph.GlobalClusteringCoefficient(graphA),
4487
- "diameter": Graph.Diameter(graphA)
4488
- }
4489
-
4490
- metrics2 = {
4491
- "closeness": safe_mean(Graph.ClosenessCentrality(graphB)),
4492
- "betweenness": safe_mean(Graph.BetweennessCentrality(graphB)),
4493
- "degree": safe_mean(Graph.DegreeCentrality(graphB)),
4494
- "pagerank": safe_mean(Graph.PageRank(graphB)),
4495
- "clustering": Graph.GlobalClusteringCoefficient(graphB),
4496
- "diameter": Graph.Diameter(graphB)
4497
- }
4498
-
4499
- # Compute similarity as 1 - normalized absolute difference
4500
- similarities = []
4501
- for key in metrics1:
4502
- v1, v2 = metrics1[key], metrics2[key]
4503
- if v1 == 0 and v2 == 0:
4504
- similarities.append(1)
4505
- else:
4506
- diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
4507
- similarities.append(1 - diff)
4508
4539
 
4509
- return round(sum(similarities) / len(similarities), mantissa)
4540
+ def edge_id(edge, vertexIDKey="id", mantissa=6):
4541
+ v1 = Edge.StartVertex(edge)
4542
+ v2 = Edge.EndVertex(edge)
4543
+ d1 = Topology.Dictionary(v1)
4544
+ d2 = Topology.Dictionary(v2)
4545
+ v1_id = Dictionary.ValueAtKey(d1, vertexIDKey) if d1 and Dictionary.ValueAtKey(d1, vertexIDKey) is not None else str(sorted(Vertex.Coordinates(v1, mantissa=mantissa)))
4546
+ v2_id = Dictionary.ValueAtKey(d2, vertexIDKey) if d2 and Dictionary.ValueAtKey(d2, vertexIDKey) is not None else str(sorted(Vertex.Coordinates(v2, mantissa=mantissa)))
4547
+
4548
+ return tuple(sorted(tuple([v1_id, v2_id])))
4549
+
4550
+ def edge_weights(graph, edgeWeightKey=None, mantissa=6):
4551
+ weights = {}
4552
+ for edge in Graph.Edges(graph):
4553
+ if edgeWeightKey == None:
4554
+ weight = 1
4555
+ elif edgeWeightKey.lower() == "length" or edgeWeightKey.lower() == "distance":
4556
+ weight = Edge.Length(edge)
4557
+ else:
4558
+ d = Topology.Dictionary(edge)
4559
+ weight = Dictionary.ValueAtKey(d, edgeWeightKey) if d and Dictionary.ValueAtKey(d, edgeWeightKey) is not None else 1.0
4560
+ eid = edge_id(edge, vertexIDKey=vertexIDKey, mantissa=mantissa)
4561
+ weights[eid] = weight
4562
+ return weights
4563
+
4564
+ w1 = edge_weights(graph1, edgeWeightKey=edgeWeightKey)
4565
+ w2 = edge_weights(graph2, edgeWeightKey=edgeWeightKey)
4566
+ keys = set(w1.keys()) | set(w2.keys())
4567
+
4568
+ numerator = sum(min(w1.get(k, 0), w2.get(k, 0)) for k in keys)
4569
+ denominator = sum(max(w1.get(k, 0), w2.get(k, 0)) for k in keys)
4570
+
4571
+ return numerator / denominator if denominator > 0 else 0.0
4572
+
4573
+ def safe_mean(lst):
4574
+ return sum(lst)/len(lst) if lst else 0
4575
+
4576
+ def betweenness_centrality_similarity(graphA, graphB, mantissa=6):
4577
+ v1 = safe_mean(Graph.BetweennessCentrality(graphA))
4578
+ v2 = safe_mean(Graph.BetweennessCentrality(graphB))
4579
+ if v1 == 0 and v2 == 0:
4580
+ return 1
4581
+ diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
4582
+ return round((1 - diff), mantissa)
4583
+
4584
+ def closeness_centrality_similarity(graphA, graphB, mantissa=6):
4585
+ v1 = safe_mean(Graph.ClosenessCentrality(graphA))
4586
+ v2 = safe_mean(Graph.ClosenessCentrality(graphB))
4587
+ if v1 == 0 and v2 == 0:
4588
+ return 1
4589
+ diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
4590
+ return round((1 - diff), mantissa)
4591
+
4592
+ def degree_centrality_similarity(graphA, graphB, mantissa=6):
4593
+ v1 = safe_mean(Graph.DegreeCentrality(graphA))
4594
+ v2 = safe_mean(Graph.DegreeCentrality(graphB))
4595
+ if v1 == 0 and v2 == 0:
4596
+ return 1
4597
+ diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
4598
+ return round((1 - diff), mantissa)
4599
+
4600
+ def diameter_similarity(graphA, graphB, mantissa=6):
4601
+ v1 = Graph.Diameter(graphA)
4602
+ v2 = Graph.Diameter(graphB)
4603
+ if v1 == 0 and v2 == 0:
4604
+ return 1
4605
+ diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
4606
+ return round((1 - diff), mantissa)
4607
+
4608
+ def global_clustering_coefficient_similarity(graphA, graphB, mantissa=6):
4609
+ v1 = Graph.GlobalClusteringCoefficient(graphA)
4610
+ v2 = Graph.GlobalClusteringCoefficient(graphB)
4611
+ if v1 == 0 and v2 == 0:
4612
+ return 1
4613
+ diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
4614
+ return round((1 - diff), mantissa)
4615
+
4616
+ def pagerank_similarity(graphA, graphB, mantissa=6):
4617
+ v1 = safe_mean(Graph.PageRank(graphA))
4618
+ v2 = safe_mean(Graph.PageRank(graphB))
4619
+ if v1 == 0 and v2 == 0:
4620
+ return 1
4621
+ diff = abs(v1 - v2) / max(abs(v1), abs(v2), 1e-6)
4622
+ return round((1 - diff), mantissa)
4510
4623
 
4511
4624
  def structure_similarity(graphA, graphB, mantissa=6):
4512
4625
  v1 = Graph.Vertices(graphA)
@@ -4562,20 +4675,42 @@ class Graph:
4562
4675
  print("Graph.Compare - Error: The graphB input parameter is not a valid topologic graph. Returning None.")
4563
4676
  return
4564
4677
 
4565
- total_weight = weightAttributes + weightGeometry + weightMetrics + weightStructure + weightWL
4678
+ total_weight = sum([weightAttributes,
4679
+ weightGeometry,
4680
+ weightBetwennessCentrality,
4681
+ weightClosenessCentrality,
4682
+ weightDegreeCentrality,
4683
+ weightDiameter,
4684
+ weightGlobalClusteringCoefficient,
4685
+ weightPageRank,
4686
+ weightStructure,
4687
+ weightWeisfeilerLehman,
4688
+ weightJaccard])
4566
4689
 
4567
4690
  attribute_score = attribute_similarity(graphA, graphB, mantissa=mantissa) if weightAttributes else 0
4691
+ betweenness_centrality_score = betweenness_centrality_similarity(graphA, graphB, mantissa=mantissa) if weightBetwennessCentrality else 0
4692
+ closeness_centrality_score = closeness_centrality_similarity(graphA, graphB, mantissa=mantissa) if weightClosenessCentrality else 0
4693
+ degree_centrality_score = degree_centrality_similarity(graphA, graphB, mantissa=mantissa) if weightDegreeCentrality else 0
4694
+ diameter_score = diameter_similarity(graphA, graphB, mantissa=mantissa) if weightDiameter else 0
4695
+ global_clustering_coefficient_score = global_clustering_coefficient_similarity(graphA, graphB, mantissa=mantissa) if weightGlobalClusteringCoefficient else 0
4568
4696
  geometry_score = geometry_similarity(graphA, graphB, mantissa=mantissa) if weightGeometry else 0
4569
- metrics_score = metrics_similarity(graphA, graphB, mantissa=mantissa) if weightMetrics else 0
4697
+ jaccard_score = weighted_jaccard_similarity(graphA, graphB, vertexIDKey=vertexIDKey, edgeWeightKey=edgeWeightKey, mantissa=mantissa) if weightJaccard else 0
4698
+ pagerank_score = pagerank_similarity(graphA, graphB, mantissa=mantissa) if weightPageRank else 0
4570
4699
  structure_score = structure_similarity(graphA, graphB, mantissa=mantissa) if weightStructure else 0
4571
- wl_score = weisfeiler_lehman_similarity(graphA, graphB, iterations, mantissa=mantissa) if weightWL else 0
4700
+ weisfeiler_lehman_score = weisfeiler_lehman_similarity(graphA, graphB, iterations, mantissa=mantissa) if weightWeisfeilerLehman else 0
4572
4701
 
4573
4702
  weighted_sum = (
4574
4703
  attribute_score * weightAttributes +
4704
+ betweenness_centrality_score * weightBetwennessCentrality +
4705
+ closeness_centrality_score * weightClosenessCentrality +
4706
+ degree_centrality_score * weightDegreeCentrality +
4707
+ diameter_score * weightDiameter +
4575
4708
  geometry_score * weightGeometry +
4576
- metrics_score * weightMetrics +
4709
+ global_clustering_coefficient_score * weightGlobalClusteringCoefficient +
4710
+ jaccard_score * weightJaccard +
4711
+ pagerank_score * weightPageRank +
4577
4712
  structure_score * weightStructure +
4578
- wl_score * weightWL
4713
+ weisfeiler_lehman_score * weightWeisfeilerLehman
4579
4714
  )
4580
4715
 
4581
4716
  if total_weight <= 0:
@@ -4583,12 +4718,18 @@ class Graph:
4583
4718
  else:
4584
4719
  overall_score = weighted_sum / total_weight
4585
4720
 
4586
- return { "attribute": round(attribute_score, mantissa),
4587
- "geometry": round(geometry_score, mantissa),
4588
- "metrics": round(metrics_score, mantissa),
4589
- "structure": round(structure_score, mantissa),
4590
- "wl": round(wl_score, mantissa),
4591
- "overall": round(overall_score, mantissa)
4721
+ return {
4722
+ "attribute": round(attribute_score, mantissa),
4723
+ "betwenness_centrality": round(betweenness_centrality_score, mantissa),
4724
+ "closeness_centrality": round(closeness_centrality_score, mantissa),
4725
+ "degree_centrality": round(degree_centrality_score, mantissa),
4726
+ "geometry": round(geometry_score, mantissa),
4727
+ "global_clustering_coefficient": round(global_clustering_coefficient_score, mantissa),
4728
+ "jaccard": round(jaccard_score, mantissa),
4729
+ "pagerank": round(pagerank_score, mantissa),
4730
+ "structure": round(structure_score, mantissa),
4731
+ "weisfeiler_lehman": round(weisfeiler_lehman_score, mantissa),
4732
+ "overall": round(overall_score, mantissa)
4592
4733
  }
4593
4734
 
4594
4735
  @staticmethod
@@ -11018,3 +11159,85 @@ class Graph:
11018
11159
  g = Graph.ByVerticesEdges(final_vertices, final_edges)
11019
11160
  return g
11020
11161
  return None
11162
+
11163
+ @staticmethod
11164
+ def WeightedJaccardSimilarity(graphA, graphB, vertexA, vertexB, vertexIDKey="id", edgeWeightKey=None, mantissa=6, silent=False):
11165
+ """
11166
+ Computes the weighted Jaccard similarity between two vertices based on their neighbors and
11167
+ edge weights. Accepts either one graph (both vertices are in the same graph) or two graphs
11168
+ (each vertex is in a separate graph).
11169
+
11170
+ Parameters
11171
+ ----------
11172
+ graphA : topologic_core.Graph
11173
+ The first graph
11174
+ graphB : topologic_core.Graph
11175
+ The second graph (this can be the same as the first graph)
11176
+ vertexA : topologic_core.Vertex
11177
+ The first vertex.
11178
+ vertexB : topologic_core.Vertex
11179
+ The second vertex.
11180
+ vertexIDKey : str , optional
11181
+ The dictionary key under which to find the unique vertex ID. The default is "id".
11182
+ edgeWeightKey : str , optional
11183
+ The dictionary key under which to find the weight of the edge for weighted graphs.
11184
+ If this parameter is specified as "length" or "distance" then the length of the edge is used as its weight.
11185
+ The default is None which means all edges are treated as if they have a weight of 1.
11186
+ mantissa : int , optional
11187
+ The desired length of the mantissa. The default is 6.
11188
+ silent : bool , optional
11189
+ If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
11190
+
11191
+ Returns
11192
+ -------
11193
+ float
11194
+ Weighted Jaccard similarity score between 0 (no overlap) and 1 (perfect match).
11195
+
11196
+ """
11197
+ from topologicpy.Graph import Graph
11198
+ from topologicpy.Topology import Topology
11199
+ from topologicpy.Dictionary import Dictionary
11200
+ from topologicpy.Vertex import Vertex
11201
+ from topologicpy.Edge import Edge
11202
+
11203
+ if graphB == None:
11204
+ graphB = graphA
11205
+
11206
+ def edge_id(edge, vertexIDKey="id", mantissa=6):
11207
+ v1 = Edge.StartVertex(edge)
11208
+ v2 = Edge.EndVertex(edge)
11209
+ d1 = Topology.Dictionary(v1)
11210
+ d2 = Topology.Dictionary(v2)
11211
+ v1_id = Dictionary.ValueAtKey(d1, vertexIDKey) if d1 and Dictionary.ValueAtKey(d1, vertexIDKey) is not None else str(sorted(Vertex.Coordinates(v1, mantissa=mantissa)))
11212
+ v2_id = Dictionary.ValueAtKey(d2, vertexIDKey) if d2 and Dictionary.ValueAtKey(d2, vertexIDKey) is not None else str(sorted(Vertex.Coordinates(v2, mantissa=mantissa)))
11213
+ return tuple(sorted([v1_id, v2_id]))
11214
+
11215
+ def get_neighbors_with_weights(graph, vertex, vertexIDKey="id", edgeWeightKey=None, mantissa=6):
11216
+ weights = {}
11217
+ for edge in Graph.Edges(graph, [vertex]):
11218
+ eid = edge_id(edge, vertexIDKey=vertexIDKey, mantissa=mantissa)
11219
+ if edgeWeightKey == None:
11220
+ weight = 1.0
11221
+ elif edgeWeightKey.lower() == "length" or edgeWeightKey.lower() == "distance":
11222
+ weight = Edge.Length(edge, mantissa=mantissa)
11223
+ else:
11224
+ d = Topology.Dictionary(edge)
11225
+ d_weight = Dictionary.ValueAtKey(d, edgeWeightKey, silent=silent)
11226
+ if not d or d_weight is None:
11227
+ if not silent:
11228
+ print(f"Graph.WeightedJaccardSimilarity - Warning: The dictionary of edge {eid} is missing '{edgeWeightKey}' key. Defaulting the edge weight to 1.0.")
11229
+ weight = 1.0
11230
+ else:
11231
+ weight = d_weight
11232
+ weights[eid] = weight
11233
+ return weights
11234
+
11235
+ weights1 = get_neighbors_with_weights(graphA, vertexA, vertexIDKey=vertexIDKey, edgeWeightKey=edgeWeightKey, mantissa=mantissa)
11236
+ weights2 = get_neighbors_with_weights(graphB, vertexB, vertexIDKey=vertexIDKey, edgeWeightKey=edgeWeightKey, mantissa=mantissa)
11237
+
11238
+ keys = set(weights1.keys()) | set(weights2.keys())
11239
+
11240
+ numerator = sum(min(weights1.get(k, 0), weights2.get(k, 0)) for k in keys)
11241
+ denominator = sum(max(weights1.get(k, 0), weights2.get(k, 0)) for k in keys)
11242
+
11243
+ return round(numerator / denominator, mantissa) if denominator != 0 else 0.0
topologicpy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.8.20'
1
+ __version__ = '0.8.22'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: topologicpy
3
- Version: 0.8.20
3
+ Version: 0.8.22
4
4
  Summary: An AI-Powered Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
5
5
  Author-email: Wassim Jabi <wassim.jabi@gmail.com>
6
6
  License: AGPL v3 License
@@ -7,11 +7,11 @@ topologicpy/Cluster.py,sha256=o5jdMRpcGfSGGiXQdFg-e9XcnBF5AqTj3xb1nSpwJWE,58606
7
7
  topologicpy/Color.py,sha256=q9xsGmxFMz7sQKmygwSVS12GaTRB-OT0-_i6t3-cthE,20307
8
8
  topologicpy/Context.py,sha256=ppApYKngZZCQBFWaxIMi2z2dokY23c935IDCBosxDAE,3055
9
9
  topologicpy/DGL.py,sha256=M_znFtyPBJJz-iXLYZs2wwBj24fhevIo739dGha0chM,139041
10
- topologicpy/Dictionary.py,sha256=7h-Gszgnt2OEOvOSADJ4pa-mTNlhQ9cuIiB5WHEW6aY,33949
10
+ topologicpy/Dictionary.py,sha256=TO5Ar9j_xUSV325MYbUHdNrKfgo9VcehcZCeZWAn6b0,34126
11
11
  topologicpy/Edge.py,sha256=yxkCVDYBflJNEYxnjMmlyvbkpg8TNy7y5bSH3yQ4jzs,71418
12
12
  topologicpy/EnergyModel.py,sha256=UoQ9Jm-hYsN383CbcLKw-y6BKitRHj0uyh84yQ-8ACg,53856
13
13
  topologicpy/Face.py,sha256=SlhB8L7BpDjd4a9YZE4UJ3zoGuF1oq9MSpuesEWro_Q,184847
14
- topologicpy/Graph.py,sha256=fsWgbYp1di1HtDipsXY9d2i42Fn_3dXsVKTac9vl7bU,515137
14
+ topologicpy/Graph.py,sha256=c2VvEvEM3hGgFR6xP-A58HXcgEVnPyA_heFOoNZ4p_Y,527640
15
15
  topologicpy/Grid.py,sha256=2s9cSlWldivn1i9EUz4OOokJyANveqmRe_vR93CAndI,18245
16
16
  topologicpy/Helper.py,sha256=4H5KPiv_eiEs489UOOyGLe9RaeoZIfmMh3mk_YCHmXg,29100
17
17
  topologicpy/Honeybee.py,sha256=uDVtDbloydNoaBFcSNukKL_2PLyD6XKkCp1VHz1jtaU,21751
@@ -28,9 +28,9 @@ topologicpy/Vector.py,sha256=GkGt-aJ591IJ2IPffMAudvITLDPi2qZibZc4UAav6m8,42407
28
28
  topologicpy/Vertex.py,sha256=q99IrWwdNlvVfUXz6iP8icmP8NzP2nsiqtgnF9Jnpx8,80913
29
29
  topologicpy/Wire.py,sha256=IVPzBKsckuxC-rHvwxmvtVF7PpApz2lhPHomtQMo_kg,228499
30
30
  topologicpy/__init__.py,sha256=vlPCanUbxe5NifC4pHcnhSzkmmYcs_UrZrTlVMsxcFs,928
31
- topologicpy/version.py,sha256=uWqZIJblLUrle0kYZkrKO4aVSNXiyYenL0G_TSUJllE,23
32
- topologicpy-0.8.20.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
33
- topologicpy-0.8.20.dist-info/METADATA,sha256=0_3vo7ubfFiV0woZaJt8RCFHF9MZZ_Sc7VnqYZX4Mao,10535
34
- topologicpy-0.8.20.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
35
- topologicpy-0.8.20.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
36
- topologicpy-0.8.20.dist-info/RECORD,,
31
+ topologicpy/version.py,sha256=SuLneBfTbTDP--cc9ZcmXl_eRJruqxfxMHpHGiHHHZA,23
32
+ topologicpy-0.8.22.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
33
+ topologicpy-0.8.22.dist-info/METADATA,sha256=9_VzttjULYoYaVn35tAzKn6Q7cf2l4mfnGKYkOE_tFo,10535
34
+ topologicpy-0.8.22.dist-info/WHEEL,sha256=ooBFpIzZCPdw3uqIQsOo4qqbA4ZRPxHnOH7peeONza0,91
35
+ topologicpy-0.8.22.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
36
+ topologicpy-0.8.22.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5