topologicpy 0.7.72__py3-none-any.whl → 0.7.73__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.
@@ -1006,6 +1006,64 @@ class CellComplex():
1006
1006
  shells = Topology.Shells(cellComplex)
1007
1007
  return shells
1008
1008
 
1009
+ @staticmethod
1010
+ def Torus(origin= None, majorRadius: float = 0.5, minorRadius: float = 0.125, uSides: int = 16, vSides: int = 8, direction: list = [0, 0, 1], placement: str = "center", tolerance: float = 0.0001):
1011
+ """
1012
+ Creates a torus.
1013
+
1014
+ Parameters
1015
+ ----------
1016
+ origin : topologic_core.Vertex , optional
1017
+ The origin location of the torus. The default is None which results in the torus being placed at (0, 0, 0).
1018
+ majorRadius : float , optional
1019
+ The major radius of the torus. The default is 0.5.
1020
+ minorRadius : float , optional
1021
+ The minor radius of the torus. The default is 0.1.
1022
+ uSides : int , optional
1023
+ The number of sides along the longitude of the torus. The default is 16.
1024
+ vSides : int , optional
1025
+ The number of sides along the latitude of the torus. The default is 8.
1026
+ direction : list , optional
1027
+ The vector representing the up direction of the torus. The default is [0, 0, 1].
1028
+ placement : str , optional
1029
+ The description of the placement of the origin of the torus. This can be "bottom", "center", or "lowerleft". It is case insensitive. The default is "center".
1030
+ tolerance : float , optional
1031
+ The desired tolerance. The default is 0.0001.
1032
+
1033
+ Returns
1034
+ -------
1035
+ topologic_core.Cell
1036
+ The created torus.
1037
+
1038
+ """
1039
+
1040
+ from topologicpy.Vertex import Vertex
1041
+ from topologicpy.Wire import Wire
1042
+ from topologicpy.Face import Face
1043
+ from topologicpy.Cell import Cell
1044
+ from topologicpy.Topology import Topology
1045
+
1046
+ if not Topology.IsInstance(origin, "Vertex"):
1047
+ origin = Vertex.ByCoordinates(0, 0, 0)
1048
+ if not Topology.IsInstance(origin, "Vertex"):
1049
+ print("Cell.Torus - Error: The input origin parameter is not a valid topologic vertex. Returning None.")
1050
+ return None
1051
+ c = Wire.Circle(origin=Vertex.Origin(), radius=minorRadius, sides=vSides, fromAngle=0, toAngle=360, close=False, direction=[0, 1, 0], placement="center")
1052
+ c = Face.ByWire(c)
1053
+ c = Topology.Translate(c, abs(majorRadius-minorRadius), 0, 0)
1054
+ torus = Topology.Spin(c, origin=Vertex.Origin(), triangulate=False, direction=[0, 0, 1], angle=360, sides=uSides, tolerance=tolerance)
1055
+ if Topology.Type(torus) == Topology.TypeID("Shell"):
1056
+ faces = Topology.Faces(torus)
1057
+ torus = CellComplex.ByFaces(faces)
1058
+ if placement.lower() == "bottom":
1059
+ torus = Topology.Translate(torus, 0, 0, minorRadius)
1060
+ elif placement.lower() == "lowerleft":
1061
+ torus = Topology.Translate(torus, majorRadius, majorRadius, minorRadius)
1062
+
1063
+ torus = Topology.Orient(torus, origin=Vertex.Origin(), dirA=[0, 0, 1], dirB=direction)
1064
+ torus = Topology.Place(torus, originA=Vertex.Origin(), originB=origin)
1065
+ return torus
1066
+
1009
1067
  @staticmethod
1010
1068
  def Vertices(cellComplex) -> list:
1011
1069
  """
topologicpy/Graph.py CHANGED
@@ -742,6 +742,102 @@ class Graph:
742
742
  _ = graph.AllPaths(vertexA, vertexB, True, timeLimit, paths) # Hook to Core
743
743
  return paths
744
744
 
745
+ @staticmethod
746
+ def AreIsomorphic(graphA, graphB, maxIterations=10, silent=False):
747
+ """
748
+ Tests if the two input graphs are isomorphic according to the Weisfeiler Lehman graph isomorphism test. See https://en.wikipedia.org/wiki/Weisfeiler_Leman_graph_isomorphism_test
749
+
750
+ Parameters
751
+ ----------
752
+ graphA : topologic_core.Graph
753
+ The first input graph.
754
+ graphB : topologic_core.Graph
755
+ The second input graph.
756
+ maxIterations : int , optional
757
+ This number limits the number of iterations to prevent the function from running indefinitely, particularly for very large or complex graphs.
758
+ silent : bool , optional
759
+ If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
760
+
761
+ Returns
762
+ -------
763
+ bool
764
+ True if the two input graphs are isomorphic. False otherwise
765
+
766
+ """
767
+
768
+ from topologicpy.Topology import Topology
769
+
770
+ def weisfeiler_lehman_test(graph1, graph2, max_iterations=10):
771
+ """
772
+ Test if two graphs are isomorphic using the Weisfeiler-Leman (WL) algorithm with early stopping.
773
+
774
+ Parameters:
775
+ graph1 (dict): Adjacency list representation of the first graph.
776
+ graph2 (dict): Adjacency list representation of the second graph.
777
+ max_iterations (int): Maximum WL iterations allowed (default is 10).
778
+
779
+ Returns:
780
+ bool: True if the graphs are WL-isomorphic, False otherwise.
781
+ """
782
+
783
+ def wl_iteration(labels, graph):
784
+ """Perform one WL iteration and return updated labels."""
785
+ new_labels = {}
786
+ for node in graph:
787
+ neighborhood_labels = sorted([labels[neighbor] for neighbor in graph[node]])
788
+ new_labels[node] = (labels[node], tuple(neighborhood_labels))
789
+ unique_labels = {}
790
+ count = 0
791
+ for node in sorted(new_labels):
792
+ if new_labels[node] not in unique_labels:
793
+ unique_labels[new_labels[node]] = count
794
+ count += 1
795
+ new_labels[node] = unique_labels[new_labels[node]]
796
+ return new_labels
797
+
798
+ # Initialize labels
799
+ labels1 = {node: 1 for node in graph1}
800
+ labels2 = {node: 1 for node in graph2}
801
+
802
+ for i in range(max_iterations):
803
+ # Perform WL iteration for both graphs
804
+ new_labels1 = wl_iteration(labels1, graph1)
805
+ new_labels2 = wl_iteration(labels2, graph2)
806
+
807
+ # Check if the label distributions match
808
+ if sorted(new_labels1.values()) != sorted(new_labels2.values()):
809
+ return False
810
+
811
+ # Check for stability (early stopping)
812
+ if new_labels1 == labels1 and new_labels2 == labels2:
813
+ break
814
+
815
+ # Update labels for next iteration
816
+ labels1, labels2 = new_labels1, new_labels2
817
+
818
+ return True
819
+
820
+ if not Topology.IsInstance(graphA, "Graph") and not Topology.IsInstance(graphB, "Graph"):
821
+ if not silent:
822
+ print("Graph.AreIsomorphic - Error: The input graph parameters are not valid graphs. Returning None.")
823
+ return None
824
+ if not Topology.IsInstance(graphA, "Graph"):
825
+ if not silent:
826
+ print("Graph.AreIsomorphic - Error: The input graphA parameter is not a valid graph. Returning None.")
827
+ return None
828
+ if not Topology.IsInstance(graphB, "Graph"):
829
+ if not silent:
830
+ print("Graph.AreIsomorphic - Error: The input graphB parameter is not a valid graph. Returning None.")
831
+ return None
832
+ if maxIterations <= 0:
833
+ if not silent:
834
+ print("Graph.AreIsomorphic - Error: The input maxIterations parameter is not within a valid range. Returning None.")
835
+ return None
836
+
837
+ g1 = Graph.AdjacencyDictionary(graphA)
838
+ g2 = Graph.AdjacencyDictionary(graphB)
839
+ return weisfeiler_lehman_test(g1, g2, max_iterations=maxIterations)
840
+
745
841
  @staticmethod
746
842
  def AverageClusteringCoefficient(graph, mantissa: int = 6, silent: bool = False):
747
843
  """
topologicpy/Plotly.py CHANGED
@@ -571,8 +571,6 @@ class Plotly:
571
571
  from topologicpy.Color import Color
572
572
  from topologicpy.Dictionary import Dictionary
573
573
  from topologicpy.Helper import Helper
574
- for d in dictionaries[:30]:
575
- print(Dictionary.Keys(d), Dictionary.Values(d))
576
574
  traces = []
577
575
  x = []
578
576
  y = []
topologicpy/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.7.72'
1
+ __version__ = '0.7.73'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: topologicpy
3
- Version: 0.7.72
3
+ Version: 0.7.73
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
@@ -2,7 +2,7 @@ topologicpy/ANN.py,sha256=XAuUjNvDRK1hhXfo82S-zXmnAPZGEdHJMRdfpu0aJ8I,47901
2
2
  topologicpy/Aperture.py,sha256=p9pUzTQSBWoUaDiug1V1R1hnEIEwYSXFg2t7iRAmNRY,2723
3
3
  topologicpy/BVH.py,sha256=mKVCAu9K8qzcWXtPDVH5usXZV1DNNNJl4n3rU5Lh1ZM,12931
4
4
  topologicpy/Cell.py,sha256=2izd-YGqy897_JHHgrGlIo5WwUeEIWVD3KspV1z_sj8,107860
5
- topologicpy/CellComplex.py,sha256=x3Exodx2PeXynnnqzb3ZLKtlSdey8KaaiKpkcx8HoCc,48207
5
+ topologicpy/CellComplex.py,sha256=5PtnRrDx_3zmtt4aTosxK9XBzZtayzaOC50pkJiIlFY,51170
6
6
  topologicpy/Cluster.py,sha256=51q5G1L5xAzRMfVU8YBXhq0g3g2X9aVNcahU-vYZRrI,55672
7
7
  topologicpy/Color.py,sha256=wPhA7rLr9BTZsWYUUVnQpbmL5ZMkGlDSsa8f3S5B-d4,20250
8
8
  topologicpy/Context.py,sha256=ppApYKngZZCQBFWaxIMi2z2dokY23c935IDCBosxDAE,3055
@@ -11,13 +11,13 @@ topologicpy/Dictionary.py,sha256=0AsGoz48pGTye_F4KcJopNjD9STeQ50LHc6PPvERFaA,319
11
11
  topologicpy/Edge.py,sha256=9u9SdUxuenLUIK26xwFvPoYV34p0dCfXmHHBxdgvAdM,67164
12
12
  topologicpy/EnergyModel.py,sha256=AqTtmXE35SxvRXhG3vYAQd7GQDW-6HtjYPHua6ME4Eg,53762
13
13
  topologicpy/Face.py,sha256=q7x6auTju6IS3mdOhhXZdU3rqKSuJCE-5EOfxofDDMI,124348
14
- topologicpy/Graph.py,sha256=M4m0URB812Fb8ISdiSftaZ-XJv8tOHY9eeba43-C6W0,386261
14
+ topologicpy/Graph.py,sha256=ULniT6Notyt9D-2AGws1B87FiVCV0qQp1bxgD0qpLQY,390517
15
15
  topologicpy/Grid.py,sha256=9N6PE84qCm40TRi2WtlVZSBwXXr47zHpscEpZHg_JW4,18205
16
16
  topologicpy/Helper.py,sha256=Sv35czP_j0oLDeJcN8usswUm4U3auiK1LQ_Z_HBvxxg,21716
17
17
  topologicpy/Honeybee.py,sha256=HfTaEV1R8K1xOVQQy9sBOhBTF_ap8A2RxZOYhirp_Mw,21835
18
18
  topologicpy/Matrix.py,sha256=umgR7An919-wGInXJ1wpqnoQ2jCPdyMe2rcWTZ16upk,8079
19
19
  topologicpy/Neo4j.py,sha256=t52hgE9cVsqkGc7m7fjRsLnyfRHakVHwdvF4ms7ow78,22342
20
- topologicpy/Plotly.py,sha256=KU76pKFCfPUTmWMqMeyzbRbyri5VEPASKQZ9DQX4Evc,118323
20
+ topologicpy/Plotly.py,sha256=-Ewc-MPR7wI0Ml_NHoBOMLAJQjFTZRAPbSvVcv9q_Wg,118227
21
21
  topologicpy/Polyskel.py,sha256=EFsuh2EwQJGPLiFUjvtXmAwdX-A4r_DxP5hF7Qd3PaU,19829
22
22
  topologicpy/PyG.py,sha256=LU9LCCzjxGPUM31qbaJXZsTvniTtgugxJY7y612t4A4,109757
23
23
  topologicpy/Shell.py,sha256=8OJjlWk9eCZ3uGOTht6ZVrcMczCafw-YWoDGueaz7eg,87673
@@ -28,9 +28,9 @@ topologicpy/Vector.py,sha256=A1g83zDHep58iVPY8WQ8iHNrSOfGWFEzvVeDuMnjDNY,33078
28
28
  topologicpy/Vertex.py,sha256=ZS6xK89JKokBKc0W8frdRhhuzR8c-dI1TTLt7pTf1iA,71032
29
29
  topologicpy/Wire.py,sha256=eVet2OToVsXi9AkDYo35LpfMPqJ6aKGD6QkiU4-Jvs8,182271
30
30
  topologicpy/__init__.py,sha256=vlPCanUbxe5NifC4pHcnhSzkmmYcs_UrZrTlVMsxcFs,928
31
- topologicpy/version.py,sha256=aAQjVNTNHAmKloX4yKWiynz5GQOXtst-3Q4eQldJrXM,23
32
- topologicpy-0.7.72.dist-info/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
33
- topologicpy-0.7.72.dist-info/METADATA,sha256=Tj5f47D3-QD3OHRQDGyO-_BByNcAXuEWIEsdT6Nuob0,10493
34
- topologicpy-0.7.72.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
35
- topologicpy-0.7.72.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
36
- topologicpy-0.7.72.dist-info/RECORD,,
31
+ topologicpy/version.py,sha256=_EZM97Nx9ZHcqJT-3j_L8-CxcswiiAnQpZx_aTh--Yc,23
32
+ topologicpy-0.7.73.dist-info/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
33
+ topologicpy-0.7.73.dist-info/METADATA,sha256=DXCQK7AXT5405KD8O3PBcTDNL0gEjLfwM802I_H8QH4,10493
34
+ topologicpy-0.7.73.dist-info/WHEEL,sha256=a7TGlA-5DaHMRrarXjVbQagU3Man_dCnGIWMJr5kRWo,91
35
+ topologicpy-0.7.73.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
36
+ topologicpy-0.7.73.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.4.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5