topologicpy 0.8.57__py3-none-any.whl → 0.8.58__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/Graph.py +348 -33
- topologicpy/Kuzu.py +495 -134
- topologicpy/version.py +1 -1
- {topologicpy-0.8.57.dist-info → topologicpy-0.8.58.dist-info}/METADATA +1 -1
- {topologicpy-0.8.57.dist-info → topologicpy-0.8.58.dist-info}/RECORD +8 -8
- {topologicpy-0.8.57.dist-info → topologicpy-0.8.58.dist-info}/WHEEL +0 -0
- {topologicpy-0.8.57.dist-info → topologicpy-0.8.58.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.57.dist-info → topologicpy-0.8.58.dist-info}/top_level.txt +0 -0
topologicpy/Graph.py
CHANGED
@@ -6929,44 +6929,146 @@ class Graph:
|
|
6929
6929
|
return graph.Edge(vertexA, vertexB, tolerance) # Hook to Core
|
6930
6930
|
|
6931
6931
|
@staticmethod
|
6932
|
-
def Edges(
|
6932
|
+
def Edges(
|
6933
|
+
graph,
|
6934
|
+
vertices: list = None,
|
6935
|
+
strict: bool = False,
|
6936
|
+
sortBy: str = None,
|
6937
|
+
reverse: bool = False,
|
6938
|
+
silent: bool = False,
|
6939
|
+
tolerance: float = 0.0001
|
6940
|
+
) -> list: # list[topologic_core.Edge]
|
6933
6941
|
"""
|
6934
|
-
Returns the
|
6942
|
+
Returns the list of edges from `graph` whose endpoints match the given `vertices`
|
6943
|
+
according to the `strict` rule.
|
6944
|
+
|
6945
|
+
If `strict` is True, both endpoints of an edge must be in `vertices`.
|
6946
|
+
If `strict` is False, at least one endpoint must be in `vertices`.
|
6935
6947
|
|
6936
6948
|
Parameters
|
6937
6949
|
----------
|
6938
|
-
graph :
|
6950
|
+
graph : topologicpy.Graph
|
6939
6951
|
The input graph.
|
6940
|
-
vertices : list
|
6941
|
-
|
6952
|
+
vertices : list[topologicpy.Vertex]
|
6953
|
+
The list of vertices to test membership against.
|
6954
|
+
strict : bool, optional
|
6955
|
+
If set to True, require both endpoints to be in `vertices`. Otherwise,
|
6956
|
+
require at least one endpoint to be in `vertices`. Default is False.
|
6957
|
+
sortBy : str , optional
|
6958
|
+
The dictionary key to use for sorting the returned edges. Special strings include "length" and "distance" to sort by the length of the edge. Default is None.
|
6959
|
+
reverse : bool , optional
|
6960
|
+
If set to True, the sorted list is reversed. This has no effect if the sortBy parameter is not set. Default is False.
|
6961
|
+
silent : bool, optional
|
6962
|
+
Isilent : bool, optional
|
6963
|
+
If set to True, all errors and warnings are suppressed. Default is False.
|
6942
6964
|
tolerance : float , optional
|
6943
6965
|
The desired tolerance. Default is 0.0001.
|
6944
6966
|
|
6945
6967
|
Returns
|
6946
6968
|
-------
|
6947
|
-
list
|
6948
|
-
The list of edges
|
6969
|
+
list[topologic_core.Edge]
|
6970
|
+
The list of matching edges from the original graph (not recreated).
|
6949
6971
|
|
6950
6972
|
"""
|
6973
|
+
from topologicpy.Vertex import Vertex
|
6951
6974
|
from topologicpy.Topology import Topology
|
6975
|
+
from topologicpy.Edge import Edge
|
6976
|
+
from topologicpy.Helper import Helper
|
6977
|
+
from topologicpy.Dictionary import Dictionary
|
6978
|
+
|
6979
|
+
def sort_edges(edges, sortBy, reverse):
|
6980
|
+
if not sortBy is None:
|
6981
|
+
if "length" in sortBy.lower() or "dist" in sortBy.lower():
|
6982
|
+
edge_values = [Edge.Length(e) for e in edges]
|
6983
|
+
else:
|
6984
|
+
edge_values = [Dictionary.ValueAtKey(Topology.Dictionary(e), sortBy, "0") for e in edges]
|
6985
|
+
edges = Helper.Sort(edges, edge_values)
|
6986
|
+
if reverse:
|
6987
|
+
edges.reverse()
|
6988
|
+
return edges
|
6952
6989
|
|
6953
6990
|
if not Topology.IsInstance(graph, "Graph"):
|
6954
|
-
|
6955
|
-
|
6991
|
+
if not silent:
|
6992
|
+
print("Graph.InducedEdges - Error: The input 'graph' is not a valid Graph. Returning [].")
|
6993
|
+
return []
|
6994
|
+
|
6995
|
+
graph_edges = []
|
6996
|
+
_ = graph.Edges(graph_edges, tolerance) # Hook to Core
|
6997
|
+
graph_edges = list(dict.fromkeys(graph_edges)) # remove duplicates
|
6998
|
+
|
6999
|
+
if not graph_edges:
|
7000
|
+
return []
|
6956
7001
|
if not vertices:
|
6957
|
-
|
6958
|
-
|
6959
|
-
|
6960
|
-
|
6961
|
-
|
6962
|
-
|
6963
|
-
|
6964
|
-
|
6965
|
-
|
6966
|
-
|
6967
|
-
|
6968
|
-
|
6969
|
-
|
7002
|
+
graph_edges = sort_edges(graph_edges, sortBy, reverse)
|
7003
|
+
return graph_edges
|
7004
|
+
|
7005
|
+
if not isinstance(vertices, list):
|
7006
|
+
if not silent:
|
7007
|
+
print("Graph.Edges - Error: The input 'vertices' is not a list. Returning [].")
|
7008
|
+
return []
|
7009
|
+
|
7010
|
+
valid_vertices = [v for v in vertices if Topology.IsInstance(v, "Vertex")]
|
7011
|
+
if not valid_vertices:
|
7012
|
+
if not silent:
|
7013
|
+
print("Graph.Edges - Warning: No valid vertices provided. Returning [].")
|
7014
|
+
return []
|
7015
|
+
|
7016
|
+
return_edges = []
|
7017
|
+
for e in graph_edges:
|
7018
|
+
sv = Edge.StartVertex(e)
|
7019
|
+
ev = Edge.EndVertex(e)
|
7020
|
+
|
7021
|
+
in_start = not Vertex.Index(sv, valid_vertices) is None
|
7022
|
+
in_end = not Vertex.Index(ev, valid_vertices) is None
|
7023
|
+
if strict:
|
7024
|
+
if in_start and in_end:
|
7025
|
+
return_edges.append(e)
|
7026
|
+
else:
|
7027
|
+
if in_start or in_end:
|
7028
|
+
return_edges.append(e)
|
7029
|
+
|
7030
|
+
return_edges = sort_edges(return_edges, sortBy, reverse)
|
7031
|
+
return return_edges
|
7032
|
+
|
7033
|
+
# @staticmethod
|
7034
|
+
# def Edges(graph, vertices=None, tolerance=0.0001):
|
7035
|
+
# """
|
7036
|
+
# Returns the edges found in the input graph. If the input list of vertices is specified, this method returns the edges connected to this list of vertices. Otherwise, it returns all graph edges.
|
7037
|
+
|
7038
|
+
# Parameters
|
7039
|
+
# ----------
|
7040
|
+
# graph : topologic_core.Graph
|
7041
|
+
# The input graph.
|
7042
|
+
# vertices : list , optional
|
7043
|
+
# An optional list of vertices to restrict the returned list of edges only to those connected to this list.
|
7044
|
+
# tolerance : float , optional
|
7045
|
+
# The desired tolerance. Default is 0.0001.
|
7046
|
+
|
7047
|
+
# Returns
|
7048
|
+
# -------
|
7049
|
+
# list
|
7050
|
+
# The list of edges in the graph.
|
7051
|
+
|
7052
|
+
# """
|
7053
|
+
# from topologicpy.Topology import Topology
|
7054
|
+
|
7055
|
+
# if not Topology.IsInstance(graph, "Graph"):
|
7056
|
+
# print("Graph.Edges - Error: The input graph is not a valid graph. Returning None.")
|
7057
|
+
# return None
|
7058
|
+
# if not vertices:
|
7059
|
+
# edges = []
|
7060
|
+
# _ = graph.Edges(edges, tolerance) # Hook to Core
|
7061
|
+
# if not edges:
|
7062
|
+
# return []
|
7063
|
+
# return list(dict.fromkeys(edges)) # remove duplicates
|
7064
|
+
# else:
|
7065
|
+
# vertices = [v for v in vertices if Topology.IsInstance(v, "Vertex")]
|
7066
|
+
# if len(vertices) < 1:
|
7067
|
+
# print("Graph.Edges - Error: The input list of vertices does not contain any valid vertices. Returning None.")
|
7068
|
+
# return None
|
7069
|
+
# edges = []
|
7070
|
+
# _ = graph.Edges(vertices, tolerance, edges) # Hook to Core
|
7071
|
+
# return list(dict.fromkeys(edges)) # remove duplicates
|
6970
7072
|
|
6971
7073
|
@staticmethod
|
6972
7074
|
def EigenVectorCentrality(graph, normalize: bool = False, key: str = "eigen_vector_centrality", colorKey: str = "evc_color", colorScale: str = "viridis", mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
@@ -8412,6 +8514,57 @@ class Graph:
|
|
8412
8514
|
edge = Topology.SetDictionary(edge, d)
|
8413
8515
|
return graph
|
8414
8516
|
|
8517
|
+
|
8518
|
+
@staticmethod
|
8519
|
+
def InducedSubgraph(graph, vertices: list = None, strict: bool = False, silent: bool = False, tolerance: float = 0.0001):
|
8520
|
+
"""
|
8521
|
+
Returns the subgraph whose edges are connected to the given `vertices`
|
8522
|
+
according to the `strict` rule. Isolated vertices are included as-is.
|
8523
|
+
|
8524
|
+
If `strict` is True, both endpoints of an edge must be in `vertices`.
|
8525
|
+
If `strict` is False, at least one endpoint must be in `vertices`.
|
8526
|
+
|
8527
|
+
Parameters
|
8528
|
+
----------
|
8529
|
+
graph : topologicpy.Graph
|
8530
|
+
The input graph.
|
8531
|
+
vertices : list[topologicpy.Vertex]
|
8532
|
+
The list of vertices to test membership against.
|
8533
|
+
strict : bool, optional
|
8534
|
+
If set to True, require both endpoints to be in `vertices`. Otherwise,
|
8535
|
+
require at least one endpoint to be in `vertices`. Default is False.
|
8536
|
+
silent : bool, optional
|
8537
|
+
Isilent : bool, optional
|
8538
|
+
If set to True, all errors and warnings are suppressed. Default is False
|
8539
|
+
tolerance : float , optional
|
8540
|
+
The desired tolerance. Default is 0.0001.
|
8541
|
+
|
8542
|
+
Returns
|
8543
|
+
-------
|
8544
|
+
list[topologic_core.Edge]
|
8545
|
+
The list of matching edges from the original graph (not recreated).
|
8546
|
+
|
8547
|
+
"""
|
8548
|
+
from topologicpy.Topology import Topology
|
8549
|
+
|
8550
|
+
if not Topology.IsInstance(graph, "Graph"):
|
8551
|
+
if not silent:
|
8552
|
+
print("Graph.InducedSubgraph - Error: The input graph parameter is not a valid graph. Returning None.")
|
8553
|
+
|
8554
|
+
if not isinstance(vertices, list):
|
8555
|
+
if not silent:
|
8556
|
+
print("Graph.InducedSubgraph - Error: The input 'vertices' is not a list. Returning None.")
|
8557
|
+
return None
|
8558
|
+
|
8559
|
+
valid_vertices = [v for v in vertices if Topology.IsInstance(v, "Vertex")]
|
8560
|
+
if not valid_vertices:
|
8561
|
+
if not silent:
|
8562
|
+
print("Graph.InducedSubgraph - Warning: No valid vertices provided. Returning None.")
|
8563
|
+
return None
|
8564
|
+
connected_vertices = [v for v in valid_vertices if Graph.VertexDegree(graph, v) > 0]
|
8565
|
+
edges = Graph.Edges(graph, connected_vertices, strict=strict, tolerance=tolerance)
|
8566
|
+
return Graph.ByVerticesEdges(valid_vertices, edges)
|
8567
|
+
|
8415
8568
|
@staticmethod
|
8416
8569
|
def IsEmpty(graph, silent: bool = False):
|
8417
8570
|
"""
|
@@ -11215,7 +11368,166 @@ class Graph:
|
|
11215
11368
|
print(f'Graph.Kernel - Error: Unsupported method "{method}". '
|
11216
11369
|
f'Supported methods are "WL" and "Hopper". Returning None.')
|
11217
11370
|
return None
|
11218
|
-
|
11371
|
+
|
11372
|
+
@staticmethod
|
11373
|
+
def KHopsSubgraph(
|
11374
|
+
graph,
|
11375
|
+
vertices: list,
|
11376
|
+
k: int = 1,
|
11377
|
+
direction: str = "both",
|
11378
|
+
silent: bool = False,
|
11379
|
+
):
|
11380
|
+
"""
|
11381
|
+
Returns a subgraph consisting of the k-hop neighborhood around the input list of seed vertices.
|
11382
|
+
|
11383
|
+
Parameters
|
11384
|
+
----------
|
11385
|
+
graph : topologicpy.Graph
|
11386
|
+
The input graph.
|
11387
|
+
vertices : list
|
11388
|
+
The input list of seed vertices.
|
11389
|
+
k : int, optional
|
11390
|
+
Number of hops. Default is 1.
|
11391
|
+
direction : str, optional
|
11392
|
+
'both', 'out', or 'in'. Default 'both'.
|
11393
|
+
silent : bool, optional
|
11394
|
+
Suppress warnings/errors. Default False.
|
11395
|
+
|
11396
|
+
Returns
|
11397
|
+
-------
|
11398
|
+
topologicpy.Graph or None
|
11399
|
+
The resulting subgraph, or None on error.
|
11400
|
+
"""
|
11401
|
+
from topologicpy.Vertex import Vertex
|
11402
|
+
from topologicpy.Edge import Edge
|
11403
|
+
from topologicpy.Graph import Graph
|
11404
|
+
from topologicpy.Topology import Topology
|
11405
|
+
from topologicpy.Dictionary import Dictionary
|
11406
|
+
|
11407
|
+
# ---- validate inputs ----
|
11408
|
+
if not Topology.IsInstance(graph, "graph"):
|
11409
|
+
if not silent:
|
11410
|
+
print("Graph.KHopsSubgraph - Error: The input graph parameter is not a valid graph. Returning None.")
|
11411
|
+
return None
|
11412
|
+
|
11413
|
+
if not isinstance(vertices, list):
|
11414
|
+
if not silent:
|
11415
|
+
print("Graph.KHopsSubgraph - Error: The input vertices parameter is not a valid list. Returning None.")
|
11416
|
+
return None
|
11417
|
+
|
11418
|
+
graph_vertices = Graph.Vertices(graph)
|
11419
|
+
if not graph_vertices:
|
11420
|
+
if not silent:
|
11421
|
+
print("Graph.KHopsSubgraph - Error: The input graph does not contain any vertices. Returning None.")
|
11422
|
+
return None
|
11423
|
+
|
11424
|
+
# Keep only valid vertex objects
|
11425
|
+
seed_vertices = [v for v in vertices if Topology.IsInstance(v, "vertex")]
|
11426
|
+
if not seed_vertices:
|
11427
|
+
if not silent:
|
11428
|
+
print("Graph.KHopsSubgraph - Error: The input vertices list does not contain any valid vertices. Returning None.")
|
11429
|
+
return None
|
11430
|
+
|
11431
|
+
# ---- map seeds to vertex indices (prefer identity; fallback to list.index) ----
|
11432
|
+
id_to_index = {Topology.UUID(v): i for i, v in enumerate(graph_vertices)}
|
11433
|
+
seed_indices = []
|
11434
|
+
for sv in seed_vertices:
|
11435
|
+
idx = id_to_index.get(Topology.UUID(sv))
|
11436
|
+
if idx is None:
|
11437
|
+
try:
|
11438
|
+
idx = graph_vertices.index(sv) # fallback if same object not used
|
11439
|
+
except ValueError:
|
11440
|
+
idx = None
|
11441
|
+
if idx is not None:
|
11442
|
+
seed_indices.append(idx)
|
11443
|
+
|
11444
|
+
if not seed_indices:
|
11445
|
+
if not silent:
|
11446
|
+
print("Graph.KHopsSubgraph - Error: None of the seed vertices are found in the graph. Returning None.")
|
11447
|
+
return None
|
11448
|
+
|
11449
|
+
# ---- get mesh data (index-based edge list) ----
|
11450
|
+
# Expect: mesh_data["vertices"] (list), mesh_data["edges"] (list of [a, b] indices)
|
11451
|
+
mesh_data = Graph.MeshData(graph)
|
11452
|
+
edges_idx = mesh_data.get("edges") or []
|
11453
|
+
# Compute number of vertices robustly
|
11454
|
+
n_verts = len(mesh_data.get("vertices") or graph_vertices)
|
11455
|
+
|
11456
|
+
# ---- build adjacency (directed; BFS respects 'direction') ----
|
11457
|
+
adj_out = {i: set() for i in range(n_verts)}
|
11458
|
+
adj_in = {i: set() for i in range(n_verts)}
|
11459
|
+
for (a, b) in edges_idx:
|
11460
|
+
if 0 <= a < n_verts and 0 <= b < n_verts:
|
11461
|
+
adj_out[a].add(b)
|
11462
|
+
adj_in[b].add(a)
|
11463
|
+
|
11464
|
+
# ---- BFS up to k hops ----
|
11465
|
+
dir_norm = (direction or "both").lower()
|
11466
|
+
if dir_norm not in ("both", "out", "in"):
|
11467
|
+
dir_norm = "both"
|
11468
|
+
|
11469
|
+
visited = set(seed_indices)
|
11470
|
+
frontier = set(seed_indices)
|
11471
|
+
for _ in range(max(0, int(k))):
|
11472
|
+
nxt = set()
|
11473
|
+
for v in frontier:
|
11474
|
+
if dir_norm in ("both", "out"):
|
11475
|
+
nxt |= adj_out.get(v, set())
|
11476
|
+
if dir_norm in ("both", "in"):
|
11477
|
+
nxt |= adj_in.get(v, set())
|
11478
|
+
nxt -= visited
|
11479
|
+
if not nxt:
|
11480
|
+
break
|
11481
|
+
visited |= nxt
|
11482
|
+
frontier = nxt
|
11483
|
+
|
11484
|
+
if not visited:
|
11485
|
+
if not silent:
|
11486
|
+
print("Graph.KHopsSubgraph - Warning: No vertices found within the specified k hops. Returning None.")
|
11487
|
+
return None
|
11488
|
+
|
11489
|
+
# ---- assemble subgraph ----
|
11490
|
+
# Vertices: actual TopologicPy Vertex objects
|
11491
|
+
sub_vertex_indices = sorted(visited)
|
11492
|
+
sub_vertices = [graph_vertices[i] for i in sub_vertex_indices]
|
11493
|
+
|
11494
|
+
# Edges: include only those whose endpoints are both in the subgraph
|
11495
|
+
sub_index_set = set(sub_vertex_indices)
|
11496
|
+
# Map from global index -> actual Vertex object for edge reconstruction
|
11497
|
+
idx_to_vertex = {i: graph_vertices[i] for i in sub_vertex_indices}
|
11498
|
+
|
11499
|
+
sub_edges = []
|
11500
|
+
for (a, b) in edges_idx:
|
11501
|
+
if a in sub_index_set and b in sub_index_set:
|
11502
|
+
# Recreate edge to ensure it references the subgraph vertices
|
11503
|
+
ea = idx_to_vertex[a]
|
11504
|
+
eb = idx_to_vertex[b]
|
11505
|
+
try:
|
11506
|
+
e = Edge.ByStartVertexEndVertex(ea, eb)
|
11507
|
+
except Exception:
|
11508
|
+
# If creation fails, skip this edge
|
11509
|
+
continue
|
11510
|
+
# Preserve edge label if present
|
11511
|
+
try:
|
11512
|
+
# Find original edge and copy its dictionary if possible
|
11513
|
+
# (best-effort; safe if Graph.Edges aligns with edges_idx order)
|
11514
|
+
# Otherwise, leave edge as-is.
|
11515
|
+
pass
|
11516
|
+
except Exception:
|
11517
|
+
pass
|
11518
|
+
sub_edges.append(e)
|
11519
|
+
|
11520
|
+
try:
|
11521
|
+
return Graph.ByVerticesEdges(sub_vertices, sub_edges)
|
11522
|
+
except Exception:
|
11523
|
+
# As a fallback, some environments accept edges alone
|
11524
|
+
try:
|
11525
|
+
return Graph.ByEdges(sub_edges)
|
11526
|
+
except Exception:
|
11527
|
+
if not silent:
|
11528
|
+
print("Graph.KHopsSubgraph - Error: Failed to construct the subgraph. Returning None.")
|
11529
|
+
return None
|
11530
|
+
|
11219
11531
|
@staticmethod
|
11220
11532
|
def Laplacian(graph, silent: bool = False, normalized: bool = False):
|
11221
11533
|
"""
|
@@ -14267,7 +14579,7 @@ class Graph:
|
|
14267
14579
|
return round(degree, mantissa)
|
14268
14580
|
|
14269
14581
|
@staticmethod
|
14270
|
-
def Vertices(graph,
|
14582
|
+
def Vertices(graph, sortBy=None, reverse=False):
|
14271
14583
|
"""
|
14272
14584
|
Returns the list of vertices in the input graph.
|
14273
14585
|
|
@@ -14275,11 +14587,14 @@ class Graph:
|
|
14275
14587
|
----------
|
14276
14588
|
graph : topologic_core.Graph
|
14277
14589
|
The input graph.
|
14278
|
-
|
14279
|
-
|
14590
|
+
sortBy : str , optional
|
14591
|
+
The dictionary key to use for sorting the returned edges. Special strings include "length" and "distance" to sort by the length of the edge. Default is None.
|
14280
14592
|
reverse : bool , optional
|
14281
|
-
If set to True, the
|
14282
|
-
|
14593
|
+
If set to True, the sorted list is reversed. This has no effect if the sortBy parameter is not set. Default is False.
|
14594
|
+
silent : bool, optional
|
14595
|
+
Isilent : bool, optional
|
14596
|
+
If set to True, all errors and warnings are suppressed. Default is False.
|
14597
|
+
|
14283
14598
|
Returns
|
14284
14599
|
-------
|
14285
14600
|
list
|
@@ -14299,13 +14614,13 @@ class Graph:
|
|
14299
14614
|
_ = graph.Vertices(vertices) # Hook to Core
|
14300
14615
|
except:
|
14301
14616
|
vertices = []
|
14302
|
-
if not
|
14303
|
-
|
14617
|
+
if not sortBy == None:
|
14618
|
+
vertex_values = []
|
14304
14619
|
for v in vertices:
|
14305
14620
|
d = Topology.Dictionary(v)
|
14306
|
-
value = Dictionary.ValueAtKey(d,
|
14307
|
-
|
14308
|
-
vertices = Helper.Sort(vertices,
|
14621
|
+
value = str(Dictionary.ValueAtKey(d, sortBy, "0"))
|
14622
|
+
vertex_values.append(value)
|
14623
|
+
vertices = Helper.Sort(vertices, vertex_values)
|
14309
14624
|
if reverse == True:
|
14310
14625
|
vertices.reverse()
|
14311
14626
|
return vertices
|