PyPyNum 1.7.0__py3-none-any.whl → 1.8.1__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.
- {PyPyNum-1.7.0.dist-info → PyPyNum-1.8.1.dist-info}/METADATA +44 -86
- {PyPyNum-1.7.0.dist-info → PyPyNum-1.8.1.dist-info}/RECORD +15 -12
- pypynum/Graph.py +270 -0
- pypynum/Matrix.py +236 -32
- pypynum/PyPyNum.png +0 -0
- pypynum/README.md +778 -0
- pypynum/Tree.py +1 -1
- pypynum/__init__.py +4 -2
- pypynum/equations.py +3 -4
- pypynum/maths.py +81 -1
- pypynum/plotting.py +1 -0
- pypynum/polynomial.py +158 -0
- pypynum/tools.py +97 -1
- pypynum/__temporary.py +0 -169
- {PyPyNum-1.7.0.dist-info → PyPyNum-1.8.1.dist-info}/WHEEL +0 -0
- {PyPyNum-1.7.0.dist-info → PyPyNum-1.8.1.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PyPyNum
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.1
|
|
4
4
|
Summary: A multifunctional mathematical calculation package written in pure Python programming language [Python>=3.5]
|
|
5
5
|
Home-page: https://www.gitee.com/PythonSJL/PyPyNum
|
|
6
6
|
Author: Shen Jiayi
|
|
@@ -668,6 +668,7 @@ License:
|
|
|
668
668
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
|
669
669
|
<http://www.gnu.org/licenses/>.
|
|
670
670
|
|
|
671
|
+
Keywords: math,数学,mathematics,数学计算,numerical,数值,computation,计算,scientific,科学,algebra,代数,calculus,微积分,statistics,统计,linear-algebra,线性代数,optimization,优化,numerical-analysis,数值分析,matrix,矩阵,vector,向量,tensor,张量,numerics,数值计算,library,库,tools,工具,utils,实用程序,algorithms,算法,software,软件,package,包,methods,方法,data-science,数据科学,machine-learning,机器学习,computational,计算的,operations,操作,functions,函数,processing,处理,programming,编程,simulation,仿真,visualization,可视化,physics,物理
|
|
671
672
|
Requires-Python: >=3.5
|
|
672
673
|
Description-Content-Type: text/markdown
|
|
673
674
|
|
|
@@ -691,7 +692,7 @@ Description-Content-Type: text/markdown
|
|
|
691
692
|
[](https://pepy.tech/project/pypynum)
|
|
692
693
|
[](https://pepy.tech/project/pypynum)
|
|
693
694
|
|
|
694
|
-
## Version -> 1.
|
|
695
|
+
## Version -> 1.8.1 | PyPI -> https://pypi.org/project/PyPyNum/ | Gitee -> https://www.gitee.com/PythonSJL/PyPyNum
|
|
695
696
|
|
|
696
697
|

|
|
697
698
|
|
|
@@ -740,54 +741,11 @@ Python interpreter and run it!)
|
|
|
740
741
|
```
|
|
741
742
|
!=!=!=!=!=!=!=!=!=!=!=!=!=!=!=!=
|
|
742
743
|
|
|
743
|
-
|
|
744
|
-
约八百行
|
|
744
|
+
eig函数修复了计算错误并改名为eigen
|
|
745
745
|
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
!=!=!=!=!=!=!=!=!=!=!=!=!=!=!=!=
|
|
750
|
-
|
|
751
|
-
部分函数再次优化,性能提高一倍。
|
|
752
|
-
|
|
753
|
-
Partial functions were optimized
|
|
754
|
-
again, resulting in a doubling
|
|
755
|
-
of performance.
|
|
756
|
-
|
|
757
|
-
!=!=!=!=!=!=!=!=!=!=!=!=!=!=!=!=
|
|
758
|
-
|
|
759
|
-
新增的好玩功能举例。
|
|
760
|
-
|
|
761
|
-
Examples of newly added fun
|
|
762
|
-
features.
|
|
763
|
-
|
|
764
|
-
新增的有序集合包含绝大多数内置集合的运算
|
|
765
|
-
,并且另有几个新函数。请注意它不是从内置
|
|
766
|
-
集合继承的。
|
|
767
|
-
|
|
768
|
-
The newly added ordered set
|
|
769
|
-
contains the majority of
|
|
770
|
-
built-in set operations, and
|
|
771
|
-
there are also several new
|
|
772
|
-
functions. Please note that it
|
|
773
|
-
does not inherit from the
|
|
774
|
-
built-in set.
|
|
775
|
-
|
|
776
|
-
新增的无穷迭代器支持迭代多种数列,默认的
|
|
777
|
-
空字符串即为自增数列。目前支持的数列有等
|
|
778
|
-
差数列、等比数列、斐波那契数列与卡特兰数
|
|
779
|
-
列。
|
|
780
|
-
|
|
781
|
-
The newly added infinite
|
|
782
|
-
iterator supports iterating
|
|
783
|
-
multiple sequences, and the
|
|
784
|
-
default empty string is the self
|
|
785
|
-
increasing sequence. The
|
|
786
|
-
currently supported sequences
|
|
787
|
-
include arithmetic sequences,
|
|
788
|
-
proportional sequences,
|
|
789
|
-
Fibonacci sequences, and Catalan
|
|
790
|
-
sequences.
|
|
746
|
+
The eig function fixed
|
|
747
|
+
calculation errors and changed
|
|
748
|
+
its name to eigen
|
|
791
749
|
|
|
792
750
|
!=!=!=!=!=!=!=!=!=!=!=!=!=!=!=!=
|
|
793
751
|
|
|
@@ -796,34 +754,13 @@ sequences.
|
|
|
796
754
|
<<<The ellipsis in the following structure represents the original part>>>
|
|
797
755
|
|
|
798
756
|
PyPyNum
|
|
799
|
-
★
|
|
800
|
-
CLASSES
|
|
801
|
-
MultiTree
|
|
802
|
-
MultiTreeNode
|
|
803
|
-
★ maths [Mathematical functions]
|
|
804
|
-
FUNCTIONS
|
|
805
|
-
...
|
|
806
|
-
totient(n: int) -> int
|
|
807
|
-
mod_order(a: int, n: int, b: int) -> int
|
|
808
|
-
primitive_root(a: int, single: bool = False) -> Union[int, list]
|
|
809
|
-
normalize(data: arr, target: num = 1) -> arr
|
|
810
|
-
average(data, weights, expected=False)
|
|
811
|
-
exgcd(a: int, b: int) -> tuple
|
|
812
|
-
crt(n: arr, a: arr) -> int
|
|
813
|
-
★ sequence [Various sequences]
|
|
757
|
+
★ Matrix [Matrix calculation]
|
|
814
758
|
FUNCTIONS
|
|
815
|
-
farey(n: int) -> list
|
|
816
759
|
...
|
|
817
|
-
|
|
818
|
-
|
|
760
|
+
rotate90(matrix: pypynum.Matrix.Matrix, times: int) -> pypynum.Matrix.Matrix
|
|
761
|
+
hessenberg(matrix: pypynum.Matrix.Matrix) -> tuple
|
|
762
|
+
eigen(matrix: pypynum.Matrix.Matrix) -> tuple
|
|
819
763
|
...
|
|
820
|
-
primality(n: int, iter_num: int = 10) -> bool
|
|
821
|
-
generate_primes(limit: int) -> list
|
|
822
|
-
prime_factors(integer: int, dictionary: bool = False, pollard_rho: bool = True) -> Union[list, dict]
|
|
823
|
-
★ utils [Other useful tools]
|
|
824
|
-
CLASSES
|
|
825
|
-
InfIterator
|
|
826
|
-
OrderedSet
|
|
827
764
|
```
|
|
828
765
|
|
|
829
766
|
### 运行用时测试
|
|
@@ -893,6 +830,14 @@ PyPyNum
|
|
|
893
830
|
Triangle
|
|
894
831
|
FUNCTIONS
|
|
895
832
|
distance(g1, g2, error: int | float = 0) -> float
|
|
833
|
+
★ Graph [Graph theory]
|
|
834
|
+
CLASSES
|
|
835
|
+
BaseGraph
|
|
836
|
+
BaseWeGraph
|
|
837
|
+
WeDiGraph
|
|
838
|
+
WeUnGraph
|
|
839
|
+
DiGraph
|
|
840
|
+
UnGraph
|
|
896
841
|
★ Group [Group theory]
|
|
897
842
|
CLASSES
|
|
898
843
|
Group
|
|
@@ -930,14 +875,16 @@ PyPyNum
|
|
|
930
875
|
CLASSES
|
|
931
876
|
Matrix
|
|
932
877
|
FUNCTIONS
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
878
|
+
eigen(matrix: pypynum.Matrix.Matrix) -> tuple
|
|
879
|
+
hessenberg(matrix: pypynum.Matrix.Matrix) -> tuple
|
|
880
|
+
identity(n: int) -> pypynum.Matrix.Matrix
|
|
881
|
+
lu(matrix: pypynum.Matrix.Matrix) -> tuple
|
|
936
882
|
mat(data)
|
|
937
|
-
qr(matrix)
|
|
883
|
+
qr(matrix: pypynum.Matrix.Matrix) -> tuple
|
|
884
|
+
rotate90(matrix: pypynum.Matrix.Matrix, times: int) -> pypynum.Matrix.Matrix
|
|
938
885
|
same(rows, cols, value=0)
|
|
939
|
-
svd(matrix)
|
|
940
|
-
tril_indices(n, k=0, m=None)
|
|
886
|
+
svd(matrix: pypynum.Matrix.Matrix) -> tuple
|
|
887
|
+
tril_indices(n: int, k: int = 0, m: int = None) -> tuple
|
|
941
888
|
zeros(_dimensions)
|
|
942
889
|
zeros_like(_nested_list)
|
|
943
890
|
★ NeuralN [A simple neural network model]
|
|
@@ -1121,6 +1068,9 @@ PyPyNum
|
|
|
1121
1068
|
average(data, weights, expected=False)
|
|
1122
1069
|
exgcd(a: int, b: int) -> tuple
|
|
1123
1070
|
crt(n: arr, a: arr) -> int
|
|
1071
|
+
isqrt(x: int) -> int
|
|
1072
|
+
is_possibly_square(n: int) -> bool
|
|
1073
|
+
is_square(n: int) -> bool
|
|
1124
1074
|
★ numbers [Conversion of various numbers]
|
|
1125
1075
|
FUNCTIONS
|
|
1126
1076
|
float2fraction(number: float, mixed: bool = False, error: float = 1e-15) -> tuple
|
|
@@ -1138,6 +1088,11 @@ PyPyNum
|
|
|
1138
1088
|
unary(function, right: real = 5, left: real = -5, top: real = 5, bottom: real = -5, complexity: real = 5...
|
|
1139
1089
|
binary(function, right: real = 5, left: real = -5, top: real = 5, bottom: real = -5, complexity: real = 5...
|
|
1140
1090
|
c_unary(function, start: real, end: real, interval: real = 5, projection: str = "ri", right: real = 5...
|
|
1091
|
+
★ polynomial [Polynomial object]
|
|
1092
|
+
CLASSES
|
|
1093
|
+
Polynomial
|
|
1094
|
+
FUNCTIONS
|
|
1095
|
+
poly(terms=None)
|
|
1141
1096
|
★ probability [Probability function]
|
|
1142
1097
|
FUNCTIONS
|
|
1143
1098
|
binomial(sample_size: int, successes: int, success_probability: Union[int, float]) -> float
|
|
@@ -1176,6 +1131,7 @@ PyPyNum
|
|
|
1176
1131
|
primality(n: int, iter_num: int = 10) -> bool
|
|
1177
1132
|
generate_primes(limit: int) -> list
|
|
1178
1133
|
prime_factors(integer: int, dictionary: bool = False, pollard_rho: bool = True) -> Union[list, dict]
|
|
1134
|
+
magic_square(n)
|
|
1179
1135
|
★ utils [Other useful tools]
|
|
1180
1136
|
CLASSES
|
|
1181
1137
|
InfIterator
|
|
@@ -1344,7 +1300,7 @@ print(v1.angles())
|
|
|
1344
1300
|
6.62607015e-34
|
|
1345
1301
|
1.618033988749895
|
|
1346
1302
|
3.141592653589793
|
|
1347
|
-
1000000000000
|
|
1303
|
+
1000000000000
|
|
1348
1304
|
|
|
1349
1305
|
>>> p = [1, -2, -3, 4]
|
|
1350
1306
|
>>> m = [
|
|
@@ -1358,7 +1314,9 @@ print(v1.angles())
|
|
|
1358
1314
|
>>> print(equations.polynomial_equation(p))
|
|
1359
1315
|
>>> print(equations.linear_equation(*m))
|
|
1360
1316
|
|
|
1361
|
-
[(-1.5615528128088307-6.5209667308287455e-24j)
|
|
1317
|
+
[[(-1.5615528128088307-6.5209667308287455e-24j) 0 0]
|
|
1318
|
+
[ 0 (2.5615528128088294+4.456233626665941e-24j) 0]
|
|
1319
|
+
[ 0 0 (1.0000000000000007+3.241554513744382e-25j)]]
|
|
1362
1320
|
[ 1.6666666666666667 -0.6666666666666666 -0.4444444444444444]
|
|
1363
1321
|
|
|
1364
1322
|
>>> print(maths.cot(constants.pi / 3))
|
|
@@ -1453,10 +1411,10 @@ print(v1.angles())
|
|
|
1453
1411
|
>>> print(random.randint(0, 9, [2, 3, 4]))
|
|
1454
1412
|
>>> print(random.uniform(0, 9, [2, 3, 4]))
|
|
1455
1413
|
|
|
1456
|
-
[[[
|
|
1457
|
-
[[[0.
|
|
1458
|
-
[[[
|
|
1459
|
-
[[[
|
|
1414
|
+
[[[1.524086835643172, -0.20868457467847845, 0.5240261503975477, -0.6439838767682032], [-1.091904210196648, -0.20567633973733265, 1.374424576574523, 0.6563097903476932], [0.2171635934136032, 1.0821030876490199, -0.8410496800310051, -0.8321549344577578]], [[0.5306996954571072, -0.4441704154154241, 1.0481960055260355, 0.39805451821848287], [-0.4006858882593715, -0.06238294764009237, -1.1536673264483728, -0.8063185246185602], [0.3029117113345387, -0.32570360518676644, 0.6608320231980702, 1.7415150171137153]]]
|
|
1415
|
+
[[[0.3736243541521843, 0.8599079983285199, 0.4260061864869946, 0.8441437619796597], [0.8955986631978392, 0.7570336992646656, 0.6706841989644684, 0.328634366074538], [0.4371430562585502, 0.9576395263025738, 0.2380278778546957, 0.806813631306664]], [[0.18549375381453237, 0.5749941389233029, 0.7009767023241946, 0.30017399397762223], [0.6661914823434657, 0.7802291606608635, 0.6847755352217044, 0.2661053533652564], [0.07937643994416943, 0.5452043474222034, 0.8026792060861194, 0.07776400257578953]]]
|
|
1416
|
+
[[[9, 0, 9, 0], [2, 6, 3, 4], [5, 8, 4, 7]], [[7, 7, 6, 3], [5, 5, 5, 8], [3, 4, 6, 6]]]
|
|
1417
|
+
[[[5.049093842782947, 1.3880585421884204, 8.533634113864629, 3.550264239771317], [3.3311351975225176, 5.131771033264564, 0.9570872044431911, 5.165536082759862], [1.2035779060925538, 8.292998518472567, 8.014641974770818, 6.251632912237915]], [[6.411677800595937, 5.365937405245105, 8.70943859614565, 4.348757668525482], [7.827612569569748, 1.3718742546020972, 0.5252489627763138, 2.065015517785291], [4.620664668451086, 2.604569735623819, 5.548107842615733, 7.60342292447815]]]
|
|
1460
1418
|
|
|
1461
1419
|
>>> print(regression.linear_regression(list(range(5)), [2, 4, 6, 7, 8]))
|
|
1462
1420
|
>>> print(regression.parabolic_regression(list(range(5)), [2, 4, 6, 7, 8]))
|
|
@@ -1,36 +1,39 @@
|
|
|
1
1
|
pypynum/Array.py,sha256=MLGvkYC9V7fGAR3g1Xykt_-hJYDC8mE47ji8dBcqFhk,6632
|
|
2
2
|
pypynum/FourierT.py,sha256=AtG0tESykzEs4gDsXhcizW7qhQnmw0gjcWcXefBqzhs,1401
|
|
3
3
|
pypynum/Geometry.py,sha256=bJCuif-wHO-t7oHFEE7ntzIdQwzUEbT3mcKgmBV6Wps,13982
|
|
4
|
+
pypynum/Graph.py,sha256=m9iTCNYRCZmAexDzwJ8Y6J7v1aweT-6TZkqh4fOtZDE,10131
|
|
4
5
|
pypynum/Group.py,sha256=m39OZNRoG9b3p_7sS1u50A0rJl0aYqYPVvnttkYQ_gw,2944
|
|
5
6
|
pypynum/Logic.py,sha256=IJAv59ECHU0HmG9lYCAQ_puqeL6Zor3-IDIVH48KBWE,11000
|
|
6
|
-
pypynum/Matrix.py,sha256=
|
|
7
|
+
pypynum/Matrix.py,sha256=vjkz-m90aWDIv2vzXBriyb4vwaZv8tsPYZzPUeUh-Vk,18050
|
|
7
8
|
pypynum/NeuralN.py,sha256=iSOvC9JW1h4AFGokGGOTkKie5hAYN_YT9H4f3apI9b8,3275
|
|
9
|
+
pypynum/PyPyNum.png,sha256=t96tJPWfHxT8kcXm_qZI2z5W36TgOqjCU9qdgbmlFws,11623
|
|
8
10
|
pypynum/Quaternion.py,sha256=E7ajc4sDJyOuQQIwKPhUEHgiaeeR5BEzFZHhJMxvbok,8007
|
|
11
|
+
pypynum/README.md,sha256=eouG6yg8No8iooz_5cLZqS-pR0eMzgtbLBassoqspVE,42891
|
|
9
12
|
pypynum/Symbolics.py,sha256=Nfo0DEch7LII53ye1wZAdIfd3IAOKbECnZQMSk_cmCs,2898
|
|
10
13
|
pypynum/Tensor.py,sha256=SJzGRNwHZzOgEabt47scccb-plA25-6s01SFyHd6lJo,3801
|
|
11
|
-
pypynum/Tree.py,sha256=
|
|
14
|
+
pypynum/Tree.py,sha256=MUT9LErZ3ER_cbiga-nOaZC7Hln8jEV8tRca2dRPWmY,2827
|
|
12
15
|
pypynum/Vector.py,sha256=eiFCY6H35pMvvDX7NpLux_bSfLI8rK8JHkaRxv7pOW8,3552
|
|
13
|
-
pypynum/__init__.py,sha256=
|
|
14
|
-
pypynum/__temporary.py,sha256=OAs7it7xjDovgAmKLcj-9Pqp0228SSon3OZx0ih_h4I,5860
|
|
16
|
+
pypynum/__init__.py,sha256=wjl8Vtz9hWI7UP-Hh2JggiLf1FR0VMusXUyG2CGfzAg,1843
|
|
15
17
|
pypynum/chars.py,sha256=VcK9w0i73FMCzc-9aIibjdHqyMsofJXdoBq0d8L7Vr0,1001
|
|
16
18
|
pypynum/cipher.py,sha256=J5PZl8Xt71LuX29eSBu4cybNK6Z3rhA9og_YzD0YJfU,1002
|
|
17
19
|
pypynum/constants.py,sha256=s2P1K8HH2nqoA6_YOVf6TKRl1Ozjf79GmCmLN9YbWxI,843
|
|
18
|
-
pypynum/equations.py,sha256=
|
|
20
|
+
pypynum/equations.py,sha256=Bn1_VjwMnnvzT0mHYI0eAARRqIHuc3IpOfYvzojTPx0,713
|
|
19
21
|
pypynum/errors.py,sha256=11-Au4aV8H5ExaDuMtu5iuGvpRaJP8gW7XbGNRmefSI,173
|
|
20
22
|
pypynum/file.py,sha256=rqrPdcX0NOEPM8s40-ymgPKsTn0HKABW-VEh1OtPnsk,3188
|
|
21
|
-
pypynum/maths.py,sha256=
|
|
23
|
+
pypynum/maths.py,sha256=Nf_1k1VpKDFWUJQlwB40ljML6xHcW9INlAtstJi3Uc0,26637
|
|
22
24
|
pypynum/numbers.py,sha256=WOxwwAN3yHakN4eHcVNn35qsfDcgw3UPSblv4woWyDE,6028
|
|
23
|
-
pypynum/plotting.py,sha256=
|
|
25
|
+
pypynum/plotting.py,sha256=xoaG6KVoKTu2Zax2FXk3_bHkiu5LguGi_siNi1FLE98,8463
|
|
26
|
+
pypynum/polynomial.py,sha256=psFukA31Ed4U7hZHcCGWCpYMi8tanTsZl-pUdklikfg,5998
|
|
24
27
|
pypynum/probability.py,sha256=kZLCfZb2q_y1CVbozSZj9xQ8Dw3il5WcAojX0jsNyXw,2130
|
|
25
28
|
pypynum/random.py,sha256=vfTtyH5yOSKJoSI_-NT_Tg8wC-ZXT0wt34f87oaSpJY,4610
|
|
26
29
|
pypynum/regression.py,sha256=D9J9lM23HiyY4eE8vHKaHoiwuvD1RYhkVNO0jQ4yml4,2118
|
|
27
30
|
pypynum/sequence.py,sha256=7NSZm_p_B00KFj5XZrtSm2FXhsowxs0qg_Q_P4pAA8o,7194
|
|
28
31
|
pypynum/test.py,sha256=Bksa7HZaywKBbLaCw2R5kGRFj6eKzkkJ7BdJBgIB3uM,8428
|
|
29
32
|
pypynum/this.py,sha256=8Swp75xE5g6436NCVDfYUVwUzUcQFPLcCNFWQWY5eGQ,2129
|
|
30
|
-
pypynum/tools.py,sha256=
|
|
33
|
+
pypynum/tools.py,sha256=jqmzsRi2INRlnI4hb4IbpMKHlvEww3ZKO9y6DxrJUbA,12697
|
|
31
34
|
pypynum/types.py,sha256=CVWPZo_ACr_QGH5gAOhoG3jK35peiqipu3PH8ScEYHE,181
|
|
32
35
|
pypynum/utils.py,sha256=V1k-JFHLr_VGUVqwOeAVH9Ju7AHQVEoVgYA7M-dPsLw,9881
|
|
33
|
-
PyPyNum-1.
|
|
34
|
-
PyPyNum-1.
|
|
35
|
-
PyPyNum-1.
|
|
36
|
-
PyPyNum-1.
|
|
36
|
+
PyPyNum-1.8.1.dist-info/METADATA,sha256=y9fXQuOCwcMcXjemYXpTwz5vPiQKTACt3l_9w-nhjxA,84338
|
|
37
|
+
PyPyNum-1.8.1.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
|
38
|
+
PyPyNum-1.8.1.dist-info/top_level.txt,sha256=4wW_Xb4bRglmiMsdPAe9f75MkXhNpuN88H17g_Cr5u8,8
|
|
39
|
+
PyPyNum-1.8.1.dist-info/RECORD,,
|
pypynum/Graph.py
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
class BaseGraph:
|
|
2
|
+
def __init__(self):
|
|
3
|
+
self.graph = {}
|
|
4
|
+
|
|
5
|
+
def __repr__(self):
|
|
6
|
+
return "{}({})".format(self.__class__.__name__, sorted(self.graph.items()))
|
|
7
|
+
|
|
8
|
+
def add_vertex(self, vertex):
|
|
9
|
+
if vertex not in self.graph:
|
|
10
|
+
self.graph[vertex] = []
|
|
11
|
+
|
|
12
|
+
def remove_vertex(self, vertex):
|
|
13
|
+
if vertex in self.graph:
|
|
14
|
+
neighbors = self.graph[vertex]
|
|
15
|
+
del self.graph[vertex]
|
|
16
|
+
for neighbor in neighbors:
|
|
17
|
+
self.graph[neighbor].remove(vertex)
|
|
18
|
+
|
|
19
|
+
def has_vertex(self, vertex):
|
|
20
|
+
return vertex in self.graph
|
|
21
|
+
|
|
22
|
+
def has_edge(self, vertex1, vertex2):
|
|
23
|
+
return vertex1 in self.graph and vertex2 in self.graph[vertex1]
|
|
24
|
+
|
|
25
|
+
def get_edges(self, vertex):
|
|
26
|
+
return self.graph.get(vertex, {})
|
|
27
|
+
|
|
28
|
+
def all_vertices(self):
|
|
29
|
+
return sorted(set(list(self.graph) + sum([list(self.graph[vertex]) for vertex in self.graph], [])))
|
|
30
|
+
|
|
31
|
+
def all_edges(self):
|
|
32
|
+
edges = []
|
|
33
|
+
for vertex, neighbours in self.graph.items():
|
|
34
|
+
for neighbour in neighbours:
|
|
35
|
+
edges.append((vertex, neighbour))
|
|
36
|
+
return sorted(edges)
|
|
37
|
+
|
|
38
|
+
def to_adjacency_matrix(self):
|
|
39
|
+
vertices = self.all_vertices()
|
|
40
|
+
num_vertices = len(vertices)
|
|
41
|
+
matrix = [[0] * num_vertices for _ in range(num_vertices)]
|
|
42
|
+
if isinstance(self, BaseWeGraph):
|
|
43
|
+
for u in self.graph:
|
|
44
|
+
for v in self.graph[u].items():
|
|
45
|
+
try:
|
|
46
|
+
v, w = v
|
|
47
|
+
matrix_index_u = vertices.index(u)
|
|
48
|
+
matrix_index_v = vertices.index(v)
|
|
49
|
+
matrix[matrix_index_u][matrix_index_v] = w
|
|
50
|
+
except ValueError:
|
|
51
|
+
continue
|
|
52
|
+
else:
|
|
53
|
+
for u in self.graph:
|
|
54
|
+
for v in self.graph[u]:
|
|
55
|
+
try:
|
|
56
|
+
matrix_index_u = vertices.index(u)
|
|
57
|
+
matrix_index_v = vertices.index(v)
|
|
58
|
+
matrix[matrix_index_u][matrix_index_v] = 1
|
|
59
|
+
except ValueError:
|
|
60
|
+
continue
|
|
61
|
+
return [[self.__class__.__name__] + vertices] + [[vertex] + row for vertex, row in zip(vertices, matrix)]
|
|
62
|
+
|
|
63
|
+
def dfs(self, start_vertex, visited=None):
|
|
64
|
+
if visited is None:
|
|
65
|
+
visited = set()
|
|
66
|
+
visited.add(start_vertex)
|
|
67
|
+
search_list = [start_vertex]
|
|
68
|
+
if start_vertex not in self.graph:
|
|
69
|
+
return [start_vertex]
|
|
70
|
+
for neighbour in self.graph[start_vertex]:
|
|
71
|
+
if neighbour not in visited:
|
|
72
|
+
search_list.extend(self.dfs(neighbour, visited))
|
|
73
|
+
return search_list
|
|
74
|
+
|
|
75
|
+
def bfs(self, start_vertex):
|
|
76
|
+
visited = {start_vertex}
|
|
77
|
+
queue = [start_vertex]
|
|
78
|
+
search_list = [start_vertex]
|
|
79
|
+
while queue:
|
|
80
|
+
vertex = queue.pop(0)
|
|
81
|
+
if vertex in self.graph:
|
|
82
|
+
for neighbour in self.graph[vertex]:
|
|
83
|
+
if neighbour not in visited:
|
|
84
|
+
visited.add(neighbour)
|
|
85
|
+
queue.append(neighbour)
|
|
86
|
+
search_list.append(neighbour)
|
|
87
|
+
return search_list
|
|
88
|
+
|
|
89
|
+
def is_connected(self):
|
|
90
|
+
visited = set()
|
|
91
|
+
queue = []
|
|
92
|
+
for node in self.graph:
|
|
93
|
+
if node not in visited:
|
|
94
|
+
visited.add(node)
|
|
95
|
+
queue.append(node)
|
|
96
|
+
break
|
|
97
|
+
while queue:
|
|
98
|
+
node = queue.pop(0)
|
|
99
|
+
for neighbor in self.graph[node]:
|
|
100
|
+
if neighbor not in visited:
|
|
101
|
+
visited.add(neighbor)
|
|
102
|
+
queue.append(neighbor)
|
|
103
|
+
return len(visited) == len(self.graph)
|
|
104
|
+
|
|
105
|
+
def is_complete(self):
|
|
106
|
+
num_nodes = len(self.graph)
|
|
107
|
+
return all([len(self.graph[node]) == num_nodes - 1 for node in self.graph])
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class DiGraph(BaseGraph):
|
|
111
|
+
def add_edge(self, vertex1, vertex2):
|
|
112
|
+
if vertex1 in self.graph:
|
|
113
|
+
self.graph[vertex1].append(vertex2)
|
|
114
|
+
else:
|
|
115
|
+
self.graph[vertex1] = [vertex2]
|
|
116
|
+
|
|
117
|
+
def remove_edge(self, vertex1, vertex2):
|
|
118
|
+
if vertex1 in self.graph and vertex2 in self.graph[vertex1]:
|
|
119
|
+
self.graph[vertex1].remove(vertex2)
|
|
120
|
+
if not self.graph[vertex1]:
|
|
121
|
+
del self.graph[vertex1]
|
|
122
|
+
|
|
123
|
+
def __str__(self):
|
|
124
|
+
edges = []
|
|
125
|
+
for vertex, neighbours in self.graph.items():
|
|
126
|
+
for neighbour in neighbours:
|
|
127
|
+
edges.append("{} -> {}".format(vertex, neighbour))
|
|
128
|
+
return "\n".join(sorted(edges))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class UnGraph(BaseGraph):
|
|
132
|
+
def add_edge(self, vertex1, vertex2):
|
|
133
|
+
if vertex1 in self.graph:
|
|
134
|
+
self.graph[vertex1].append(vertex2)
|
|
135
|
+
else:
|
|
136
|
+
self.graph[vertex1] = [vertex2]
|
|
137
|
+
if vertex2 in self.graph:
|
|
138
|
+
self.graph[vertex2].append(vertex1)
|
|
139
|
+
else:
|
|
140
|
+
self.graph[vertex2] = [vertex1]
|
|
141
|
+
|
|
142
|
+
def remove_edge(self, vertex1, vertex2):
|
|
143
|
+
if vertex1 in self.graph and vertex2 in self.graph:
|
|
144
|
+
if vertex2 in self.graph[vertex1]:
|
|
145
|
+
self.graph[vertex1].remove(vertex2)
|
|
146
|
+
if vertex1 in self.graph[vertex2]:
|
|
147
|
+
self.graph[vertex2].remove(vertex1)
|
|
148
|
+
if not self.graph[vertex1]:
|
|
149
|
+
del self.graph[vertex1]
|
|
150
|
+
if not self.graph[vertex2]:
|
|
151
|
+
del self.graph[vertex2]
|
|
152
|
+
|
|
153
|
+
def __str__(self):
|
|
154
|
+
edges = []
|
|
155
|
+
for vertex, neighbours in self.graph.items():
|
|
156
|
+
for neighbour in neighbours:
|
|
157
|
+
edges.append("{} -- {}".format(vertex, neighbour))
|
|
158
|
+
return "\n".join(sorted(edges))
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class BaseWeGraph(BaseGraph):
|
|
162
|
+
def add_edge(self, vertex1, vertex2, weight=0):
|
|
163
|
+
raise NotImplementedError
|
|
164
|
+
|
|
165
|
+
def remove_edge(self, vertex1, vertex2):
|
|
166
|
+
raise NotImplementedError
|
|
167
|
+
|
|
168
|
+
def add_vertex(self, vertex):
|
|
169
|
+
if vertex not in self.graph:
|
|
170
|
+
self.graph[vertex] = {}
|
|
171
|
+
|
|
172
|
+
def remove_vertex(self, vertex):
|
|
173
|
+
if vertex in self.graph:
|
|
174
|
+
neighbors = self.graph[vertex]
|
|
175
|
+
del self.graph[vertex]
|
|
176
|
+
for neighbor in neighbors:
|
|
177
|
+
self.remove_edge(neighbor, vertex)
|
|
178
|
+
|
|
179
|
+
def get_edge_weight(self, vertex1, vertex2):
|
|
180
|
+
if self.has_edge(vertex1, vertex2):
|
|
181
|
+
return self.graph[vertex1][vertex2]
|
|
182
|
+
|
|
183
|
+
def get_in_degree_weight_sum(self, vertex):
|
|
184
|
+
return sum([self.get_edge_weight(neighbor, vertex)
|
|
185
|
+
for neighbor in self.graph if vertex in self.graph[neighbor]])
|
|
186
|
+
|
|
187
|
+
def get_out_degree_weight_sum(self, vertex):
|
|
188
|
+
return sum([self.get_edge_weight(vertex, neighbor) for neighbor in self.graph.get(vertex, {})])
|
|
189
|
+
|
|
190
|
+
def dijkstra(self, start):
|
|
191
|
+
distances = {vertex: float("inf") for vertex in self.graph}
|
|
192
|
+
distances[start] = 0
|
|
193
|
+
queue = [(0, start)]
|
|
194
|
+
visited = set()
|
|
195
|
+
while queue:
|
|
196
|
+
current_distance, current_vertex = min(queue, key=lambda x: x[0])
|
|
197
|
+
if current_vertex in visited:
|
|
198
|
+
queue.remove((current_distance, current_vertex))
|
|
199
|
+
continue
|
|
200
|
+
visited.add(current_vertex)
|
|
201
|
+
queue.remove((current_distance, current_vertex))
|
|
202
|
+
if current_distance > distances[current_vertex] or current_vertex not in self.graph:
|
|
203
|
+
continue
|
|
204
|
+
for neighbor, weight in self.graph[current_vertex].items():
|
|
205
|
+
distance = current_distance + weight
|
|
206
|
+
if neighbor in distances:
|
|
207
|
+
if distance < distances[neighbor]:
|
|
208
|
+
distances[neighbor] = distance
|
|
209
|
+
queue.append((distance, neighbor))
|
|
210
|
+
else:
|
|
211
|
+
distances[neighbor] = distance
|
|
212
|
+
queue.append((distance, neighbor))
|
|
213
|
+
return distances
|
|
214
|
+
|
|
215
|
+
def reconstruct_path(self, start, end, distances):
|
|
216
|
+
current = end
|
|
217
|
+
path = [current]
|
|
218
|
+
while current != start:
|
|
219
|
+
for neighbor, weight in self.get_edges(current).items():
|
|
220
|
+
if distances[current] == distances[neighbor] + weight:
|
|
221
|
+
current = neighbor
|
|
222
|
+
path.append(current)
|
|
223
|
+
break
|
|
224
|
+
return path[::-1]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class WeDiGraph(BaseWeGraph):
|
|
228
|
+
def add_edge(self, vertex1, vertex2, weight=0):
|
|
229
|
+
if vertex1 not in self.graph:
|
|
230
|
+
self.graph[vertex1] = {}
|
|
231
|
+
self.graph[vertex1][vertex2] = weight
|
|
232
|
+
|
|
233
|
+
def remove_edge(self, vertex1, vertex2):
|
|
234
|
+
if vertex1 in self.graph and vertex2 in self.graph[vertex1]:
|
|
235
|
+
del self.graph[vertex1][vertex2]
|
|
236
|
+
if not self.graph[vertex1]:
|
|
237
|
+
del self.graph[vertex1]
|
|
238
|
+
|
|
239
|
+
def __str__(self):
|
|
240
|
+
edges = []
|
|
241
|
+
for vertex, neighbours in self.graph.items():
|
|
242
|
+
for neighbour, weight in neighbours.items():
|
|
243
|
+
edges.append("{} -[{}]> {}".format(vertex, weight, neighbour))
|
|
244
|
+
return "\n".join(sorted(edges))
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class WeUnGraph(BaseWeGraph):
|
|
248
|
+
def add_edge(self, vertex1, vertex2, weight=0):
|
|
249
|
+
if vertex1 not in self.graph:
|
|
250
|
+
self.graph[vertex1] = {}
|
|
251
|
+
if vertex2 not in self.graph:
|
|
252
|
+
self.graph[vertex2] = {}
|
|
253
|
+
self.graph[vertex1][vertex2] = weight
|
|
254
|
+
self.graph[vertex2][vertex1] = weight
|
|
255
|
+
|
|
256
|
+
def remove_edge(self, vertex1, vertex2):
|
|
257
|
+
if vertex1 in self.graph and vertex2 in self.graph[vertex1]:
|
|
258
|
+
del self.graph[vertex1][vertex2]
|
|
259
|
+
del self.graph[vertex2][vertex1]
|
|
260
|
+
if not self.graph[vertex1]:
|
|
261
|
+
del self.graph[vertex1]
|
|
262
|
+
if vertex1 != vertex2 and not self.graph[vertex2]:
|
|
263
|
+
del self.graph[vertex2]
|
|
264
|
+
|
|
265
|
+
def __str__(self):
|
|
266
|
+
edges = []
|
|
267
|
+
for vertex, neighbours in self.graph.items():
|
|
268
|
+
for neighbour, weight in neighbours.items():
|
|
269
|
+
edges.append("{} -[{}]- {}".format(vertex, weight, neighbour))
|
|
270
|
+
return "\n".join(sorted(edges))
|