From 4634bba930822cdd9974daea122a0ababfe6645b Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 28 Mar 2020 17:03:59 +0100 Subject: [PATCH 01/60] Add weighted interval scheduling test --- .travis.yml | 1 + .../weighted_interval_scheduling_test.py | 76 ++++++++++++++++-- ...eighted_interval_scheduling.cpython-37.pyc | Bin 2686 -> 2778 bytes .../weighted_interval_scheduling.py | 7 +- 4 files changed, 76 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index afa3c2f..f6618ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ script: - awesome_bot README.md --allow-dupe --allow-redirect - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py + - python Algorithm_tests/dynamic_programming_tests\weighted_interval_scheduling/weighted_interval_scheduling.py - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py - python Algorithm_tests/other_tests/test_binarysearch.py - python Algorithm_tests/math_tests/intersection_test.py diff --git a/Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py b/Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py index aeaa145..d413cc1 100644 --- a/Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py +++ b/Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py @@ -3,37 +3,103 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -#sys.path.append('Algorithms/dynamic_programming/') +sys.path.append('Algorithms/dynamic_programming/') # If run from local: -sys.path.append('../../../Algorithms/dynamic_programming/') +#sys.path.append('../../../Algorithms/dynamic_programming/') from weighted_interval_scheduling import WeightedIntervalScheduling class test_weighted_interval_scheduling(unittest.TestCase): def setUp(self): self.I1 = [] self.correct_maxweight1 = 0 + self.correct_intervals1 = [] self.I2 = [(0,3,10)] self.correct_maxweight2 = 10 + self.correct_intervals2 = [(0,3,10)] self.I3 = [(0,3,5), (2,5,15), (4, 6, 5)] - self.correct_maxweight3 = 5 + self.correct_maxweight3 = 15 + self.correct_intervals3 = [(2,5,15)] + + self.I4 = [(0, 3, 5), (3, 5, 15), (5, 7, 5)] + self.correct_maxweight4 = 25 + self.correct_intervals4 = [(0, 3, 5), (3, 5, 15), (5, 7, 5)] + + self.I5 = [(0, 3, 5), (3, 5, -100), (5, 7, -50)] + self.correct_maxweight5 = 5 + self.correct_intervals5 = [(0,3,5)] + + self.I6 = [(0, 50, 1), (0, 49, 1), (0, 48, 1), (15,20,10)] + self.correct_maxweight6 = 10 + self.correct_intervals6 = [(15, 20, 10)] + + self.I7 = [(0, 50, 1), (0, 50, 1), (0, 50, 1), (0, 50, 1)] + self.correct_maxweight7 = 1 + self.correct_intervals7 = [(0, 50, 1)] + + self.I8 = [(0, 50, 1), (0, 49, 1), (0, 48, 1), (0, 47, 1)] + self.correct_maxweight8 = 1 + self.correct_intervals8 = [(0, 47, 1)] + + self.I9 = [(0, 50, 2), (0, 49, 1), (0, 48, 1), (0, 47, 1)] + self.correct_maxweight9 = 2 + self.correct_intervals9 = [(0, 50, 2)] def test_empty_interval(self): weightedinterval = WeightedIntervalScheduling(self.I1) max_weight, best_intervals = weightedinterval.weighted_interval() self.assertEqual(self.correct_maxweight1, max_weight) + self.assertEqual(self.correct_intervals1, best_intervals) def test_single_interval(self): weightedinterval = WeightedIntervalScheduling(self.I2) max_weight, best_intervals = weightedinterval.weighted_interval() self.assertEqual(self.correct_maxweight2, max_weight) + self.assertEqual(self.correct_intervals2, best_intervals) def test_overlapping_intervals(self): - weightedinterval = WeightedIntervalScheduling(self.I2) + weightedinterval = WeightedIntervalScheduling(self.I3) max_weight, best_intervals = weightedinterval.weighted_interval() - self.assertEqual(self.correct_maxweight2, max_weight) + self.assertEqual(self.correct_maxweight3, max_weight) + self.assertEqual(self.correct_intervals3, best_intervals) + + def test_no_overlapping_intervals(self): + weightedinterval = WeightedIntervalScheduling(self.I4) + max_weight, best_intervals = weightedinterval.weighted_interval() + self.assertEqual(self.correct_maxweight4, max_weight) + self.assertEqual(self.correct_intervals4, best_intervals) + + def test_negative_weights(self): + weightedinterval = WeightedIntervalScheduling(self.I5) + max_weight, best_intervals = weightedinterval.weighted_interval() + self.assertEqual(self.correct_maxweight5, max_weight) + self.assertEqual(self.correct_intervals5, best_intervals) + + def test_interval_contained_in_all_intervals(self): + weightedinterval = WeightedIntervalScheduling(self.I6) + max_weight, best_intervals = weightedinterval.weighted_interval() + self.assertEqual(self.correct_maxweight6, max_weight) + self.assertEqual(self.correct_intervals6, best_intervals) + + def test_all_intervals_same(self): + weightedinterval = WeightedIntervalScheduling(self.I7) + max_weight, best_intervals = weightedinterval.weighted_interval() + self.assertEqual(self.correct_maxweight7, max_weight) + self.assertEqual(self.correct_intervals7, best_intervals) + + def test_earliest_finish_time(self): + weightedinterval = WeightedIntervalScheduling(self.I8) + max_weight, best_intervals = weightedinterval.weighted_interval() + self.assertEqual(self.correct_maxweight8, max_weight) + self.assertEqual(self.correct_intervals8, best_intervals) + + def test_earliest_finish_time_not_best(self): + weightedinterval = WeightedIntervalScheduling(self.I9) + max_weight, best_intervals = weightedinterval.weighted_interval() + self.assertEqual(self.correct_maxweight9, max_weight) + self.assertEqual(self.correct_intervals9, best_intervals) if __name__ == '__main__': print("Running Weighted Interval Scheduling tests:") diff --git a/Algorithms/dynamic_programming/__pycache__/weighted_interval_scheduling.cpython-37.pyc b/Algorithms/dynamic_programming/__pycache__/weighted_interval_scheduling.cpython-37.pyc index 07306a39572c5b80798f3cf23ca42d494dc58369..0cc24273db679d81a27555adbc07596d5989aac8 100644 GIT binary patch delta 430 zcmew-a!ZuYiIf;V`PUMqdoHkKiiE+|IFB6wkrc|D0#wgxY-UWOM8Df~C z_@e|;1yguag;M#O8O0fz85tRXd_EvwAcYYK`CFMKfuazZ6vki%O@WQ)d{`#?GICB< zW|fo4Vyt1vVya=3WRPSKX8^JpYZz0QC4jta*2%G~fviP5K&MRJ&1xYn2V}?taWP1Q zfsuoeg-M4|h*5~SN@MZ^7U{{FY@3X4aVO{J7L=Bx#^)E56iEQpX)+b@0jVO8&LS2# z!3JU}0tv0jZ0zn_APHw6E-slI&R#tE3cI-sND^#$kr;>tvR#uIYSv_R4jo35$srsS tY#{L>#mSdA3>mp6vvAIw{E+ji5=fAPNx+nYiG>jriZF37@-Pc90sv~4LMH$K diff --git a/Algorithms/dynamic_programming/weighted_interval_scheduling.py b/Algorithms/dynamic_programming/weighted_interval_scheduling.py index 3305773..f25b9ca 100644 --- a/Algorithms/dynamic_programming/weighted_interval_scheduling.py +++ b/Algorithms/dynamic_programming/weighted_interval_scheduling.py @@ -31,8 +31,9 @@ def previous_intervals(self): def find_solution(self, j): if j == -1: return + else: - if (self.I[j][2] + self.OPT[self.p[j]]) >= self.OPT[j - 1]: + if (self.I[j][2] + self.compute_opt(self.p[j])) > self.compute_opt(j - 1): self.solution.append(self.I[j]) self.find_solution(self.p[j]) @@ -61,7 +62,7 @@ def weighted_interval(self): self.find_solution(len(self.I) - 1) - return self.OPT[-1], self.solution + return self.OPT[-1], self.solution[::-1] if __name__ == '__main__': # They are labeled as: (start, end, weight) @@ -74,7 +75,7 @@ def weighted_interval(self): t7 = (5,10,2) t8 = (8,10,1) I = [t1,t2,t3,t4,t5,t6,t7,t8] - + I = [(0, 50, 1), (0, 49, 1), (0, 48, 1), (15, 20, 10)] # --> [(15,20,10), (0,48,1), (0,49, 1), (0,50, 1)] weightedinterval = WeightedIntervalScheduling(I) max_weight, best_intervals = weightedinterval.weighted_interval() From 8a8cc5e013471de7af74e276df10d0329d1cf697 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 28 Mar 2020 17:10:42 +0100 Subject: [PATCH 02/60] Add weighted interval scheduling test --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f6618ac..1c17bdc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ script: - awesome_bot README.md --allow-dupe --allow-redirect - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py - - python Algorithm_tests/dynamic_programming_tests\weighted_interval_scheduling/weighted_interval_scheduling.py + - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling.py - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py - python Algorithm_tests/other_tests/test_binarysearch.py - python Algorithm_tests/math_tests/intersection_test.py From 20537384a94db5dab5c47dc09993fd7dbe37a73c Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 28 Mar 2020 17:13:30 +0100 Subject: [PATCH 03/60] Add weighted interval scheduling test --- .travis.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1c17bdc..1a38c09 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ script: - awesome_bot README.md --allow-dupe --allow-redirect - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py - - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling.py + - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py - python Algorithm_tests/other_tests/test_binarysearch.py - python Algorithm_tests/math_tests/intersection_test.py diff --git a/README.md b/README.md index f7462f0..55702ea 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Whenever I face an interesting problem I document the algorithm that I learned t # Dynamic Programming * :white_check_mark: [Knapsack 0/1](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py) **O(nC) Bottom-Up implementation (Loops)** * :white_check_mark: [:movie_camera:](https://youtu.be/XmyxiSc3LKg)[Sequence Alignment](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/sequence_alignment.py) **O(nm)** -* :small_red_triangle: [:movie_camera:](https://youtu.be/dU-coYsd7zw)[Weighted Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/weighted_interval_scheduling.py) **O(nlog(n))** +* :white_check_mark: [:movie_camera:](https://youtu.be/dU-coYsd7zw)[Weighted Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/weighted_interval_scheduling.py) **O(nlog(n))** # Graph theory * :small_red_triangle: [Kahns Topological Sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kahns-toposort/kahns.py) **- O(n + m)** From 70319b97e9cc4fc7ce29d1ad011a2314314954c5 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 28 Mar 2020 17:14:53 +0100 Subject: [PATCH 04/60] Add weighted interval scheduling test --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1a38c09..fd72e99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,5 +22,6 @@ script: - python Algorithm_tests/math_tests/intersection_test.py - python Algorithm_tests/math_tests/union_test.py - python Algorithm_tests/cryptology_tests/ceasar_test.py + - python Algorithm_tests/other_tests/test_medianmaintenance.py - python Algorithm_tests/other_tests/test_intervalscheduling.py - python Algorithm_tests/sorting_tests/test_sorting.py From 742ecce286b12dc2b7eecfea28f009c8ddce5884 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 28 Mar 2020 17:17:28 +0100 Subject: [PATCH 05/60] Updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 55702ea..56b77b5 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Whenever I face an interesting problem I document the algorithm that I learned t * :small_red_triangle: [(simple) Fixpoint iteration](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/numerical_methods/fixpoint.py) # Other -* :small_red_triangle: [Maintaining Median](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/median_maintenance.py) +* :white_check_mark: [Maintaining Median](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/median_maintenance.py) * :small_red_triangle: [Huffman Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/Huffman/Huffman.py) * :white_check_mark: [:movie_camera:](https://youtu.be/SmPxC8m0yIY)[Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/interval_scheduling.py) **- O(nlog(n))** * :white_check_mark: [Binary Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/search/binarysearch.py) **- O(log(n))** From 1dcfac75f3668a1633506a759f7ebb3283e8fb61 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 28 Mar 2020 17:18:26 +0100 Subject: [PATCH 06/60] Updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56b77b5..d555275 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Whenever I face an interesting problem I document the algorithm that I learned t * :small_red_triangle: [(simple) Fixpoint iteration](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/numerical_methods/fixpoint.py) # Other -* :white_check_mark: [Maintaining Median](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/median_maintenance.py) +* :white_check_mark: [Maintaining Median](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/median_maintenance.py) **- O(nlog(n))** * :small_red_triangle: [Huffman Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/Huffman/Huffman.py) * :white_check_mark: [:movie_camera:](https://youtu.be/SmPxC8m0yIY)[Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/interval_scheduling.py) **- O(nlog(n))** * :white_check_mark: [Binary Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/search/binarysearch.py) **- O(log(n))** From 243f357e37ad72c206b1a36f0bf6a938a7e02d42 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 28 Mar 2020 19:57:15 +0100 Subject: [PATCH 07/60] Updated read me, changed kahn topological sort, and added testing --- .travis.yml | 11 ++++ .../kahn_topological_ordering_test.py | 60 ++++++++++++++++++ .../kahn_topological_ordering.cpython-37.pyc | Bin 0 -> 1750 bytes ...{kahns.py => kahn_topological_ordering.py} | 45 +++++++------ README.md | 2 +- 5 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py create mode 100644 Algorithms/graphtheory/kahns-toposort/__pycache__/kahn_topological_ordering.cpython-37.pyc rename Algorithms/graphtheory/kahns-toposort/{kahns.py => kahn_topological_ordering.py} (50%) diff --git a/.travis.yml b/.travis.yml index fd72e99..9c9e95f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,14 +14,25 @@ before_script: script: - awesome_bot README.md --allow-dupe --allow-redirect + # Dynamic Programming Tests - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py + + # Graph Theory Tests - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py + + # Math tests - python Algorithm_tests/other_tests/test_binarysearch.py - python Algorithm_tests/math_tests/intersection_test.py - python Algorithm_tests/math_tests/union_test.py + + # Cryptography tests - python Algorithm_tests/cryptology_tests/ceasar_test.py + + # "Other" tests - python Algorithm_tests/other_tests/test_medianmaintenance.py - python Algorithm_tests/other_tests/test_intervalscheduling.py + + # Sorting tests - python Algorithm_tests/sorting_tests/test_sorting.py diff --git a/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py b/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py new file mode 100644 index 0000000..da56046 --- /dev/null +++ b/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py @@ -0,0 +1,60 @@ +# Import folder where sorting algorithms +import sys +import unittest + +# For importing from different folders +# OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from +#sys.path.append('Algorithms/graphtheory/kahns-toposort/') + +# If run from local: +sys.path.append('../../Algorithms/graphtheory/kahns-toposort') + +from kahn_topological_ordering import topological_ordering +from collections import defaultdict + +class test_TopologicalOrdering(unittest.TestCase): + def setUp(self): + self.G1 = {} + self.degree_incoming1 = defaultdict(int, {}) + self.correct_isDAG1 = False + self.correct_path1 = [] + + self.G2 = {'1': ['2'], '2':['3'], '3':['4'], '4':['5'], '5' : []} + self.degree_incoming2 = defaultdict(int, {'2':1, '3':1, '4':1, '5':1}) + self.correct_isDAG2 = True + self.correct_path2 = ['1', '2', '3', '4', '5'] + + self.G3 = {'1': ['2', '3', '4', '5'], '2': ['3', '4', '5'], '3': ['4','5'], '4': ['5'], '5': []} + self.degree_incoming3 = defaultdict(int, {'2': 1, '3': 2, '4': 3, '5': 4}) + self.correct_isDAG3 = True + self.correct_path3 = ['1', '2', '3', '4', '5'] + + self.G4 = {'1': ['2', '3', '4', '5'], '2': ['3', '4', '5'], '3': ['2', '4', '5'], '4': ['5'], '5': []} + self.degree_incoming4 = defaultdict(int, {'2': 2, '3': 2, '4': 3, '5': 4}) + self.correct_isDAG4 = False + self.correct_path4 = [] + + def test_emptygraph(self): + path_to_take, is_DAG = topological_ordering(self.G1, self.degree_incoming1) + self.assertEqual(path_to_take, self.correct_path1) + self.assertEqual(is_DAG, self.correct_isDAG1) + + def test_clear_ordering(self): + path_to_take, is_DAG = topological_ordering(self.G2, self.degree_incoming2) + self.assertEqual(path_to_take, self.correct_path2) + self.assertEqual(is_DAG, self.correct_isDAG2) + + def test_more_complicated_graph(self): + path_to_take, is_DAG = topological_ordering(self.G3, self.degree_incoming3) + self.assertEqual(path_to_take, self.correct_path3) + self.assertEqual(is_DAG, self.correct_isDAG3) + + def test_no_topological_ordering(self): + path_to_take, is_DAG = topological_ordering(self.G4, self.degree_incoming4) + self.assertEqual(path_to_take, self.correct_path4) + self.assertEqual(is_DAG, self.correct_isDAG4) + + +if __name__ == '__main__': + print("Running Topological Ordering tests:") + unittest.main() \ No newline at end of file diff --git a/Algorithms/graphtheory/kahns-toposort/__pycache__/kahn_topological_ordering.cpython-37.pyc b/Algorithms/graphtheory/kahns-toposort/__pycache__/kahn_topological_ordering.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..31bc0d6b36740ca4a3ee5fbc45b1a41140e6fae9 GIT binary patch literal 1750 zcmZ`3-)|c=*!Ep6={0S$t_-#pEMB&ZHtjlTjH*<0D;s;+s%@guX>jt+PIBv=eYKs^ zRu>^u{si9Gq*a=b;P2qCxL2OWpTHBJ(_{-sIPrJ>e*637J9Bd(g7xF8AHMsmj?kYD znXCW~U&1!O1K=n^9CMQ4oJ1t|A`c_(asMY2`J%>a`$YfBgC6E}-sln7xQF=6OFs$( z5p^EIZ zzMd1aXZRQNiZ~5^@d;`#u?>PyxI55=GJ>iuwf)pkmi3fQZ9k`gbW_Pw*`tgW%=STm zSw~JKwW?5=>ZJ+GsM1_$C)QOOM0u)3Vg;uxIZm=Pp*_utKE1ZHeZSoaA2>f^Oaog| zS%MnCEci=f`wAV;q8}yFweI zB;91^gibLgKo0uK<}A%RiORRa>y*;@fm#}ZE90UOEESJ_Z!QsuQ{3Z z+w`%>)gidc6yxJmbO$oAsgld|#lW~|4qaT+X*Nn*YJ|uQkZI2L1K%vB+yu+H3P5)`z~zr2LOvo=w*&!4wj(vNtZl97N4RaIr^kT zJLuahL$Ac8cNwM#WN1lVlhQlG7#+|()I&r6=y6H(&p`Li(6Cnez^^&}(XA4dwad=N z^6dkP-*)Yx#t_TBw+=pS*D5a)QhR_@0V`ZWt9qfJ^}4nS4p}x3racqYMq^Md zaM9C3#E?prLkXe}l7ZGSOA=vB`aBb{R4@RM?>?39<}PZvb3D}x(R`w$98K9syb8`I zqw>JrZ%EIgWbAeM%p%?z6r$E6%3tt7i_K_7G2ox>FoiOH;1j zFGY7HQ%|&xcb3`yingK(=bcF^rCk;|kxY@ZAdU zwEYTi>kGitiw<0Lzz6WwwNcyq59{P3*W2fB3bbU>7sD)~H?HWkj-ExQyJdyi{84#-^$j@TS_zGgenk*9K6Y*m>8p tj_totsT>u03d}oBV>4HLkcq7(VCE74pR`Eh;|9Kj7fB1ZpdL^i{0}Wr^5Osh literal 0 HcmV?d00001 diff --git a/Algorithms/graphtheory/kahns-toposort/kahns.py b/Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py similarity index 50% rename from Algorithms/graphtheory/kahns-toposort/kahns.py rename to Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py index 4f68b39..d1c272a 100644 --- a/Algorithms/graphtheory/kahns-toposort/kahns.py +++ b/Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py @@ -1,26 +1,22 @@ ''' Purpose of this algorithm is finding a path that is in topological ordering for a directed acyclic graph (DAG). +If the graph is not a DAG and includes cycles it will return is_DAG = 'False' meaning it has cycles. + +Time Complexity: O(n + m), n = |V|, m = |E| Programmed by Aladdin Persson * 2019-03-17 Intitial programming +* 2020-03-28 Removed load graph function, just having topological sort seems to make more sense + The loading of the graph is so varying depending on input, doesn't make much sense to include it ''' from collections import defaultdict, deque -import re - -def load_graph(filename): - graph = defaultdict(list) - degree_incoming = defaultdict(int) - - for line in open(filename): - from_node, to_node = [char.replace(' ', '') for char in re.findall(r' . ', line)] - graph[from_node].append(to_node) - degree_incoming[to_node] += 1 - return graph, degree_incoming +def topological_ordering(graph, degree_incoming): + if len(graph) == 0: + return [], False -def toposort(graph, degree_incoming): curr_accessible_nodes = deque() for node in graph: @@ -39,19 +35,22 @@ def toposort(graph, degree_incoming): curr_accessible_nodes.append(connected_node) # Check if there are still incoming edges (meaning it will have cycles) + is_DAG = True + for val in degree_incoming.values(): if val != 0: - raise ValueError("There are cycles in this graph!") - - return path + is_DAG = False + path = [] -def main(): - # Note: The load graph WILL differ depending on the input graph you have. - # There are many ways to have a textfile to describe a topological graph, and one needs to - # adapt to the specific problem. - graph, degree_incoming = load_graph('example.txt') - path_to_take = toposort(graph, degree_incoming) - print(f'One path to take that is a topological ordering is {"".join(path_to_take)}') + return path, is_DAG if __name__ == '__main__': - main() \ No newline at end of file + G = {'A': ['B'], 'B': ['C', 'D'], 'C': ['D'], 'D': []} + degree_incoming = defaultdict(int, {'B': 1, 'C': 1, 'D': 2}) + + print('The graph to check is : ' + str(G)) + print('Which has incoming edges: ' + str(degree_incoming)) + print('\n') + path_to_take, is_DAG = topological_ordering(G, degree_incoming) + print('The graph has a topological ordering <--> G is a DAG: ' + str(is_DAG)) + print(f'One path to take that is a topological ordering is {"".join(path_to_take)}') \ No newline at end of file diff --git a/README.md b/README.md index d555275..78a2a40 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Whenever I face an interesting problem I document the algorithm that I learned t * :white_check_mark: [:movie_camera:](https://youtu.be/dU-coYsd7zw)[Weighted Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/weighted_interval_scheduling.py) **O(nlog(n))** # Graph theory -* :small_red_triangle: [Kahns Topological Sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kahns-toposort/kahns.py) **- O(n + m)** +* :white_check_mark: [Kahns Topological Sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kahns-toposort/kahns.py) **- O(n + m)** * :small_red_triangle: [Bellman-Ford Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/bellman-ford/bellman_ford.py) **- Unoptimized implementation** * :small_red_triangle: [Floyd-Warshall Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py) **- O(n3)** * :small_red_triangle: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/djikstra.py) **- Naive implementation** From 8837e7ffae44d4f14c3cd802f8084d1ce863c3f3 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 28 Mar 2020 19:58:13 +0100 Subject: [PATCH 08/60] Added kahn topological ordering tests --- .travis.yml | 1 + .../graphtheory_tests/kahn_topological_ordering_test.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9c9e95f..3e3b75d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ script: # Graph Theory Tests - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py + - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py # Math tests - python Algorithm_tests/other_tests/test_binarysearch.py diff --git a/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py b/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py index da56046..d7c6a73 100644 --- a/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py +++ b/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py @@ -4,10 +4,10 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -#sys.path.append('Algorithms/graphtheory/kahns-toposort/') +sys.path.append('Algorithms/graphtheory/kahns-toposort/') # If run from local: -sys.path.append('../../Algorithms/graphtheory/kahns-toposort') +#sys.path.append('../../Algorithms/graphtheory/kahns-toposort') from kahn_topological_ordering import topological_ordering from collections import defaultdict From eebd30678c73d14941eb1009e7d04a219a021f8c Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 28 Mar 2020 22:31:50 +0100 Subject: [PATCH 09/60] Added bellman ford test --- Algorithms/graphtheory/bellman-ford/bellman_ford.py | 3 ++- README.md | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Algorithms/graphtheory/bellman-ford/bellman_ford.py b/Algorithms/graphtheory/bellman-ford/bellman_ford.py index c7bd97f..c4ae5a9 100644 --- a/Algorithms/graphtheory/bellman-ford/bellman_ford.py +++ b/Algorithms/graphtheory/bellman-ford/bellman_ford.py @@ -3,6 +3,8 @@ The difference between Dijkstra and this is that this can handle negative edges. We do pay for this as it is a lot slower than Dijkstra. +Time Complexity: O(mn) + Programmed by Aladdin Persson 2019-03-04 Initial programming ''' @@ -42,7 +44,6 @@ def bellman_ford(G, start): for _ in range(num_vertices - 1): for from_node in G: for to_node, weight in G[from_node].items(): - if shortest_distance[from_node] + weight < shortest_distance[to_node]: shortest_distance[to_node] = shortest_distance[from_node] + weight predecessor[to_node] = from_node diff --git a/README.md b/README.md index 78a2a40..db0f7c4 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,13 @@ Whenever I face an interesting problem I document the algorithm that I learned t :small_red_triangle:: If the algorithm is untested # Dynamic Programming -* :white_check_mark: [Knapsack 0/1](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py) **O(nC) Bottom-Up implementation (Loops)** -* :white_check_mark: [:movie_camera:](https://youtu.be/XmyxiSc3LKg)[Sequence Alignment](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/sequence_alignment.py) **O(nm)** -* :white_check_mark: [:movie_camera:](https://youtu.be/dU-coYsd7zw)[Weighted Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/weighted_interval_scheduling.py) **O(nlog(n))** +* :white_check_mark: [Knapsack 0/1](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py) **- O(nC) Bottom-Up implementation (Loops)** +* :white_check_mark: [:movie_camera:](https://youtu.be/XmyxiSc3LKg)[Sequence Alignment](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/sequence_alignment.py) **- O(nm)** +* :white_check_mark: [:movie_camera:](https://youtu.be/dU-coYsd7zw)[Weighted Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/weighted_interval_scheduling.py) **- O(nlog(n))** # Graph theory * :white_check_mark: [Kahns Topological Sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kahns-toposort/kahns.py) **- O(n + m)** -* :small_red_triangle: [Bellman-Ford Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/bellman-ford/bellman_ford.py) **- Unoptimized implementation** +* :white_check_mark: [Bellman-Ford Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/bellman-ford/bellman_ford.py) **-O(mn)** * :small_red_triangle: [Floyd-Warshall Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py) **- O(n3)** * :small_red_triangle: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/djikstra.py) **- Naive implementation** * :small_red_triangle: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/heapdijkstra.py) **O(mlog(n)) - Heap implementation** From e2a2d716b4f4830a6f11e0159e60ec9733c59e8d Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 28 Mar 2020 23:06:29 +0100 Subject: [PATCH 10/60] djikstra tests added --- .travis.yml | 2 + .../Djikstra/djikstra_heap_test.py | 54 +++++++++++++++++ .../Djikstra/djikstra_naive_test.py | 55 ++++++++++++++++++ .../__pycache__/dijkstra.cpython-37.pyc | Bin 0 -> 1866 bytes .../__pycache__/heapdijkstra.cpython-37.pyc | Bin 0 -> 1966 bytes .../dijkstra/{djikstra.py => dijkstra.py} | 44 +++++++------- .../graphtheory/dijkstra/heapdijkstra.py | 44 +++++++++----- README.md | 4 +- 8 files changed, 166 insertions(+), 37 deletions(-) create mode 100644 Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py create mode 100644 Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py create mode 100644 Algorithms/graphtheory/dijkstra/__pycache__/dijkstra.cpython-37.pyc create mode 100644 Algorithms/graphtheory/dijkstra/__pycache__/heapdijkstra.cpython-37.pyc rename Algorithms/graphtheory/dijkstra/{djikstra.py => dijkstra.py} (69%) diff --git a/.travis.yml b/.travis.yml index 3e3b75d..bdb1be6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,8 @@ script: # Graph Theory Tests - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py + - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py + - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py # Math tests - python Algorithm_tests/other_tests/test_binarysearch.py diff --git a/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py b/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py new file mode 100644 index 0000000..95e481f --- /dev/null +++ b/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py @@ -0,0 +1,54 @@ +# Import folder where sorting algorithms +import sys +import unittest + +# For importing from different folders +# OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from +sys.path.append('Algorithms/graphtheory/dijkstra/') + +# If run from local: +#sys.path.append('../../../Algorithms/graphtheory/dijkstra/') + +from heapdijkstra import dijkstra + +class test_Dijkstra(unittest.TestCase): + def setUp(self): + self.G1 = {} + self.correct_path1 = [] + self.correct_dist1 = float("inf") + + self.G2 = {1:{2:1, 4:10}, 2:{3:15}, 3:{6:5}, 4:{5:1}, 5:{6:1}, 6: {}} + self.correct_path2 = [1,4,5,6] + self.correct_dist2 = 12 + + self.G3 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {}, 4: {5:1}, 5: {}, 6: {}} + self.correct_path3 = [] + self.correct_dist3 = float("inf") + + self.G4 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {6: 5}, 4: {5: 1}, 5: {6: 1}, 6: {}} + self.correct_path4 = [1, 4, 5] + self.correct_dist4 = 11 + + def test_emptygraph(self): + path_to_take, distances = dijkstra(self.G1, 0, 1) + self.assertEqual(distances[1], self.correct_dist1) + self.assertEqual(path_to_take, self.correct_path1) + + def test_simplegraph(self): + path_to_take, distances = dijkstra(self.G2, 1, 6) + self.assertEqual(distances[6], self.correct_dist2) + self.assertEqual(path_to_take, self.correct_path2) + + def test_no_path_exists(self): + path_to_take, distances = dijkstra(self.G3, 1, 6) + self.assertEqual(distances[6], self.correct_dist3) + self.assertEqual(path_to_take, self.correct_path3) + + def test_not_endpoint(self): + path_to_take, distances = dijkstra(self.G4, 1, 5) + self.assertEqual(distances[5], self.correct_dist4) + self.assertEqual(path_to_take, self.correct_path4) + +if __name__ == '__main__': + print("Running Djikstra tests:") + unittest.main() \ No newline at end of file diff --git a/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py b/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py new file mode 100644 index 0000000..60dcdb6 --- /dev/null +++ b/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py @@ -0,0 +1,55 @@ +# Import folder where sorting algorithms +import sys +import unittest + +# For importing from different folders +# OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from +sys.path.append('Algorithms/graphtheory/dijkstra/') + +# If run from local: +#sys.path.append('../../../Algorithms/graphtheory/dijkstra/') + +from dijkstra import dijkstra + +class test_Dijkstra(unittest.TestCase): + def setUp(self): + self.G1 = {} + self.correct_path1 = [] + self.correct_dist1 = float("inf") + + self.G2 = {1:{2:1, 4:10}, 2:{3:15}, 3:{6:5}, 4:{5:1}, 5:{6:1}, 6: {}} + self.correct_path2 = [1,4,5,6] + self.correct_dist2 = 12 + + self.G3 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {}, 4: {5:1}, 5: {}, 6: {}} + self.correct_path3 = [] + self.correct_dist3 = float("inf") + + self.G4 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {6: 5}, 4: {5: 1}, 5: {6: 1}, 6: {}} + self.correct_path4 = [1, 4, 5] + self.correct_dist4 = 11 + + def test_emptygraph(self): + path_to_take, distance = dijkstra(self.G1, 0, 1) + self.assertEqual(distance, self.correct_dist1) + self.assertEqual(path_to_take, self.correct_path1) + + def test_simplegraph(self): + path_to_take, distance = dijkstra(self.G2, 1, 6) + self.assertEqual(distance, self.correct_dist2) + self.assertEqual(path_to_take, self.correct_path2) + + def test_no_path_exists(self): + path_to_take, distance = dijkstra(self.G3, 1, 6) + self.assertEqual(distance, self.correct_dist3) + self.assertEqual(path_to_take, self.correct_path3) + + def test_not_endpoint(self): + path_to_take, distance = dijkstra(self.G4, 1, 5) + self.assertEqual(distance, self.correct_dist4) + self.assertEqual(path_to_take, self.correct_path4) + + +if __name__ == '__main__': + print("Running Djikstra tests:") + unittest.main() \ No newline at end of file diff --git a/Algorithms/graphtheory/dijkstra/__pycache__/dijkstra.cpython-37.pyc b/Algorithms/graphtheory/dijkstra/__pycache__/dijkstra.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd049da3547f5ecd0d19d32af5748136a07425bf GIT binary patch literal 1866 zcmaJ>Pj4GV6rY*hwbyIMq#3999f3a*IbgdR#|MU;f1f)pwRDP@&lZ9HRp>hB8C4! z;`%{95?l^OZZ8sUkB5|peOC^cn+zf$St8xomjjoFuJ87R9}gVop@?8L8Zqh~PTYHe zPeI9j$V8Gvq1*NgMl(KV_|hFja^&;CrIB>I(P-0gVQjS4KUr<9uWsCNAB0?TKXBu7 z%Mio4$VO|m^|2P&3YZ^)$Kx0*Q08bDOscn{YdPhAEn2inaEoJy^f6W<19q&2*AxFj0eK1`lOsC2_zd>`1ef8S*&( z1BnWpKfm2dBFh;k(jK}bI|P17tMI`+-XzZl~B@n^9oo=@?_wX#>gMC zPOjZ-2T|7#lFjBz(MwBVfZC4GMQjkE^C)y@z*^rwGXoy7JivnJeiBt6m%ZKie{T&l zGozS=S^2@&p9>L*tRk3CwdEwUx8Wdf!ozL(_;bV1wglrtr}C1&dpg>#BTaK&-VXfyOdbZ3U&ZJ#_Rhw5B<9K<2zT zFK6NroP(`G6X%*`hz208^VBeQG@yG0a;(hi1(6T%=8}z)%!s2nEAcR4LT2_?Y?9Z# zu^`@rT0jp-ANU3fsdr`m%ylSK+z-3VtHy#+)@AUT39ot#Mp(E5Pfp_5;E=;pHOWl< zD0*fHY_B}x`MFo=4tPMds8{-)@%})1)$XwnER>r0I+pBtBVB`_l1(58FX9?8vHomq z5(jp+QOZ{~F2Sj7T*b?|RNXL14UkuZZxJt%njvoJ%h{a{Jhfq`Gt<2?(@1QPneNM( z2INe4+U!G3@;)>31{CiCL%gTS`#?^Xwu-Qe7vJT{UAJh|hMko=9U65zogCyBK0|-R zfLG)<7Vy-Fx51KU&+~if_PTR~jxMv?qlg{{Y*ROTautY4?7F>f8~VDsnd*2E8tMf? C&B1d3 literal 0 HcmV?d00001 diff --git a/Algorithms/graphtheory/dijkstra/__pycache__/heapdijkstra.cpython-37.pyc b/Algorithms/graphtheory/dijkstra/__pycache__/heapdijkstra.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e63d035ff115b4798f813a1d6aa99e34d7604de3 GIT binary patch literal 1966 zcmaJ?&u`pB6rLIXTxSzPTa`^g#h|KmE3!=kNCia^g;Hoip`u7BR?1>_W_QhcZD+=5 zv(Z>cq(~eqaimDuBe(t={0qKt=xMJUdqBKrH)-er&-!`hy?O7OdGo#5kLKq+0?*%n z{`jqQ33-Bp!^eWohw!Q#1SbLEl(U!ylpEZ9Kmx{3aEsdyXkZAFJ0m7D?(zor9x*=0 zn-K*$AJK^Lg-2#!@s|RdF9wb>FDwaD#^M_{+lmjr`8`DJ8-a4g7L;o3u~v z{pDSYei*4-hHoi9j0dTV^5NL;r_%3736GM2pAUtvhN;Yj%Ka?NhaK<6IFso;!Toze zswhqT``}eg+)?2`_-WrCiZD|h&$}hlfegoEnEd_3zZ!=eg8H|>Pl4ZBSSvc&GewyD z!!#dKzQB^QcE^^6hH8o@WL^WkKt7}K};5Mq9O77te~4DX_+LaBTt^E1RG~R(Qin? z?hs86*pw8kJ{rxgk$qYipf#p2PaBX-Yonxc@6`1u7O-}q`~)^2b|aO)afHtR(uVgo z;$Hy~0s7sQf@&&F4(oV;NMs7g-1wO-5yZ*CTItLs82!q&O+@=oOy@A>>S4@_bxhbD zJ)oRSDW~XtYz)zlq8U%=+cQj(MA2rY5hZzPsVt6i7_rVuY2-WEA4E35{`5+xbE*Da zJ*14f1jn2Wfh?((XAqM*5b4m z#%jIueCn~T#3S5zwoHk+lvqb?CNT%48Apkz7Fi3dJ~;>CINI6&M{Apof}_% zB4sMeh7=*k$f~q@ajFDP>BB*nv>!Ck(2e1oOZw>x(53erY93ahPJkek(FJH8a}Ari z(Bvu5_6)SagA@!sS-&zk5d$?Jki6t3vq$+SQi! z0Ov@5h*rJakX=&#G*Vx1rLe%CGDVk8o zXP}Uskq16s)TIo$GB8JX$V0ll2r+9vTKPG(t!-~0@%z_-O;`tC*Rt)FRzFU|yfjB* z0u(?}ZI?{zxy)Vg&byXNZD=kvVbhC{h<^b~?c1;b literal 0 HcmV?d00001 diff --git a/Algorithms/graphtheory/dijkstra/djikstra.py b/Algorithms/graphtheory/dijkstra/dijkstra.py similarity index 69% rename from Algorithms/graphtheory/dijkstra/djikstra.py rename to Algorithms/graphtheory/dijkstra/dijkstra.py index 380a910..c778bfa 100644 --- a/Algorithms/graphtheory/dijkstra/djikstra.py +++ b/Algorithms/graphtheory/dijkstra/dijkstra.py @@ -1,5 +1,10 @@ -# Dijkstra's algorithm for finding the shortest path in a graph -# Programmed 2019-01-28 +''' +Dijkstra's algorithm for finding the shortest path in a graph + +Programmed by Aladdin Persson + 2019-01-28 Initial programming + 2020-03-28 Cleaned up code +''' def make_graph(file): try: @@ -9,16 +14,16 @@ def make_graph(file): line_list = f.readlines() - # Found on mukeshmithrakumar github, thought this was clean.. - # populate the graph using data from the text file via dictionary comprehensions G = {int(line.split()[0]): {(int(tup.split(',')[0])): int(tup.split(',')[1]) for tup in line.split()[1:] if tup} for line in line_list if line} f.close() return G - def dijkstra(G, start, end): + if start not in G or end not in G: + return [], float('inf') + shortest_distance = {} predecessor = {} unseenNodes = G @@ -34,7 +39,6 @@ def dijkstra(G, start, end): while unseenNodes: minNode = None - # priority-queue? -> Hittar bästa noden hittils for node in unseenNodes: if minNode is None: minNode = node @@ -49,8 +53,7 @@ def dijkstra(G, start, end): unseenNodes.pop(minNode) - print("pred") - print(predecessor) + # Find path from start node s to end node t currentNode = end while currentNode != start: @@ -58,23 +61,24 @@ def dijkstra(G, start, end): path.insert(0, currentNode) currentNode = predecessor[currentNode] except KeyError: - print('Path not reachable') - break + return [], float('inf') + path.insert(0,start) - return path, shortest_distance[end] + return path, shortest_distance[end] +if __name__ == '__main__': + #G = make_graph('dijkstraData.txt') -#G = make_graph('dijkstraData.txt') + G = {1:{2:10, 3:20}, + 2:{4:40}, + 3:{4:5}, + 4:{}} -G = {1:{2:10, 3:20}, - 2:{4:40}, - 3:{4:5}, - 4:{}} -print(f'Current graph is: {G}') -path, shortest = dijkstra(G, 1, 4) + print(f'Current graph is: {G}') + path, shortest = dijkstra(G, 1, 4) -print(path) -print(shortest) + print(path) + print(shortest) \ No newline at end of file diff --git a/Algorithms/graphtheory/dijkstra/heapdijkstra.py b/Algorithms/graphtheory/dijkstra/heapdijkstra.py index def99fa..1b59293 100644 --- a/Algorithms/graphtheory/dijkstra/heapdijkstra.py +++ b/Algorithms/graphtheory/dijkstra/heapdijkstra.py @@ -1,8 +1,12 @@ -# Dijkstra's algorithm for finding the shortest path. -# Improved version with the usage of heaps. +''' +Dijkstra's algorithm for finding the shortest path. +Improved version with the usage of heaps. -# Programmed by Aladdin Persson -# 2019-02-15 Initial coding +Programmed by Aladdin Persson + 2019-02-15 Initial coding + 2020-03-28 Small code changes, fixed for edge cases not covered + +''' import heapq @@ -14,14 +18,16 @@ def make_graph(file): line_list = f.readlines() - # Kinda messy. - # populate the graph using data from the text file via dictionary comprehensions + # Kinda messy graph loading G = {int(line.split()[0]): {(int(tup.split(',')[0])): int(tup.split(',')[1]) for tup in line.split()[1:] if tup} for line in line_list if line} f.close() return G def dijkstra(G, start, end=None): + if start not in G or (end != None and end not in G): + return [], {end:float('inf')} + distance, visited, history, heap, path = {}, {}, {}, [], [] for node in G.keys(): @@ -48,19 +54,27 @@ def dijkstra(G, start, end=None): try: path.insert(0, current_node) current_node = history[current_node] + except KeyError: - print('Path not reachable') - break + return [], distance path.insert(0, start) - return distance, path + return path, distance if __name__ == '__main__': - start, end = 1, 160 - print(f'Goal is to find the path from node {start} to node {end}') - G = make_graph('dijkstraData.txt') - - dist, path = dijkstra(G, start, end) - print(f'Path found: {path}') \ No newline at end of file + # start, end = 1, 160 + # print(f'Goal is to find the path from node {start} to node {end}') + # G = make_graph('dijkstraData.txt') + + G = {1: {2: 10, 3: 20}, + 2: {4: 40}, + 3: {4: 5}, + 4: {}} + start=1 + end=2 + + path, dist = dijkstra(G, start, end) + print(f'Path found: {path}') + print(dist) \ No newline at end of file diff --git a/README.md b/README.md index db0f7c4..db8322f 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ Whenever I face an interesting problem I document the algorithm that I learned t * :white_check_mark: [Kahns Topological Sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kahns-toposort/kahns.py) **- O(n + m)** * :white_check_mark: [Bellman-Ford Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/bellman-ford/bellman_ford.py) **-O(mn)** * :small_red_triangle: [Floyd-Warshall Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py) **- O(n3)** -* :small_red_triangle: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/djikstra.py) **- Naive implementation** -* :small_red_triangle: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/heapdijkstra.py) **O(mlog(n)) - Heap implementation** +* :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/djikstra.py) **- Naive implementation** +* :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/heapdijkstra.py) **O(mlog(n)) - Heap implementation** * :small_red_triangle: [Karger's Minimum cut](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kargers/kargermincut.py) * :small_red_triangle: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prims_algorithm.py) **- Naive implementation** * :small_red_triangle: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/primheap.py) **- mlog(n)** From 5e1c07b9b6d9617ab62f5701bd3f7d2b1cb167ac Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:19:54 +0200 Subject: [PATCH 11/60] Cleaned up graph algorithms, included testing for many of them --- .travis.yml | 5 ++ Algorithm_tests/graphtheory_tests/BFS_test.py | 69 +++++++++++++++++ Algorithm_tests/graphtheory_tests/DFS_test.py | 67 +++++++++++++++++ .../kruskal_unionfind_test.py | 70 ++++++++++++++++++ .../graphtheory_tests/prims_algorithm_test.py | 69 +++++++++++++++++ .../BFS_queue_iterative.py | 2 +- .../BFS_queue_iterative.cpython-37.pyc | Bin 0 -> 1322 bytes .../depth-first-search/DFS_recursive.py | 10 ++- .../depth-first-search/DFS_stack_iterative.py | 18 ++--- .../__pycache__/DFS_recursive.cpython-37.pyc | Bin 0 -> 1195 bytes .../DFS_stack_iterative.cpython-37.pyc | Bin 0 -> 1346 bytes .../__pycache__/kruskal.cpython-37.pyc | Bin 0 -> 1745 bytes .../kruskal_unionfind.cpython-37.pyc | Bin 0 -> 1251 bytes Algorithms/graphtheory/kruskal/kruskal.py | 18 ++--- .../graphtheory/kruskal/kruskal_unionfind.py | 4 +- .../__pycache__/prim_heap.cpython-37.pyc | Bin 0 -> 2347 bytes .../prims/{primheap.py => prim_heap.py} | 44 ++++++----- .../{prims_algorithm.py => prim_naive.py} | 10 +-- README.md | 14 ++-- 19 files changed, 337 insertions(+), 63 deletions(-) create mode 100644 Algorithm_tests/graphtheory_tests/BFS_test.py create mode 100644 Algorithm_tests/graphtheory_tests/DFS_test.py create mode 100644 Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py create mode 100644 Algorithm_tests/graphtheory_tests/prims_algorithm_test.py create mode 100644 Algorithms/graphtheory/breadth-first-search/__pycache__/BFS_queue_iterative.cpython-37.pyc create mode 100644 Algorithms/graphtheory/depth-first-search/__pycache__/DFS_recursive.cpython-37.pyc create mode 100644 Algorithms/graphtheory/depth-first-search/__pycache__/DFS_stack_iterative.cpython-37.pyc create mode 100644 Algorithms/graphtheory/kruskal/__pycache__/kruskal.cpython-37.pyc create mode 100644 Algorithms/graphtheory/kruskal/__pycache__/kruskal_unionfind.cpython-37.pyc create mode 100644 Algorithms/graphtheory/prims/__pycache__/prim_heap.cpython-37.pyc rename Algorithms/graphtheory/prims/{primheap.py => prim_heap.py} (53%) rename Algorithms/graphtheory/prims/{prims_algorithm.py => prim_naive.py} (92%) diff --git a/.travis.yml b/.travis.yml index bdb1be6..e5d5227 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ before_script: script: - awesome_bot README.md --allow-dupe --allow-redirect + # Dynamic Programming Tests - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py @@ -24,6 +25,10 @@ script: - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py + - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py + - python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py + - python Algorithm_tests/graphtheory_tests/BFS_test.py + - python Algorithm_tests/graphtheory_tests/DFS_test.py # Math tests - python Algorithm_tests/other_tests/test_binarysearch.py diff --git a/Algorithm_tests/graphtheory_tests/BFS_test.py b/Algorithm_tests/graphtheory_tests/BFS_test.py new file mode 100644 index 0000000..09f4aff --- /dev/null +++ b/Algorithm_tests/graphtheory_tests/BFS_test.py @@ -0,0 +1,69 @@ +# Import folder where sorting algorithms +import sys +import unittest +from collections import deque + +# For importing from different folders +# OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from +sys.path.append('Algorithms/graphtheory/breadth-first-search/') + +# If run from local: +#sys.path.append('../../Algorithms/graphtheory/breadth-first-search/') +from BFS_queue_iterative import BFS + +class test_BFS(unittest.TestCase): + + def setUp(self): + self.G1 = {1:[2],2:[1,3],3:[2]} + self.correct_visited1 = [True] * 3 + self.correct_path1 = [1,2,3] + + self.G2 = {1:[2], 2:[1,3,4], 3:[2], 4:[2,5], 5:[4]} + self.correct_visited2 = [True] * 5 + + self.G3 = {1:[2], 2:[1,3,4], 3:[2], 4:[2], 5:[]} + self.correct_visited3 = [True]*4 + [False] + + self.G4 = {1:[2,3,4], 2:[1,3,4], 3:[1,2,4], 4:[1,2,3]} + self.correct_visited4 = [True]*4 + + self.G5 = {1:[2,3,4], 2:[1,5], 3:[1,7], 4:[1,6], 5:[2], 6:[4], 7:[3]} + self.correct_visited5 = [True]*7 + + def test_linear_graph(self): + visited, path = BFS(self.G1, start_node=1) + self.assertEqual(visited, self.correct_visited1) + self.assertEqual(path, self.correct_path1) + + def test_simple_graph(self): + visited, path = BFS(self.G2, start_node=1) + self.assertTrue(path.index(3) < path.index(5)) + self.assertEqual(visited, self.correct_visited2) + + def test_disconnected_graph(self): + visited, path = BFS(self.G3, start_node=1) + self.assertEqual(visited, self.correct_visited3) + + def test_complete_graph(self): + visited, path = BFS(self.G4, start_node=1) + self.assertEqual(visited, self.correct_visited4) + + def test_breadth_before_depth(self): + visited, path = BFS(self.G5, start_node=1) + self.assertEqual(visited, self.correct_visited5) + + # Make sure it goes breadth first + self.assertTrue(path.index(2) < path.index(5)) + self.assertTrue(path.index(2) < path.index(6)) + self.assertTrue(path.index(2) < path.index(7)) + self.assertTrue(path.index(3) < path.index(5)) + self.assertTrue(path.index(3) < path.index(6)) + self.assertTrue(path.index(3) < path.index(7)) + self.assertTrue(path.index(4) < path.index(5)) + self.assertTrue(path.index(4) < path.index(6)) + self.assertTrue(path.index(4) < path.index(7)) + + +if __name__ == '__main__': + print("Running BFS/DFS tests:") + unittest.main() \ No newline at end of file diff --git a/Algorithm_tests/graphtheory_tests/DFS_test.py b/Algorithm_tests/graphtheory_tests/DFS_test.py new file mode 100644 index 0000000..25ed177 --- /dev/null +++ b/Algorithm_tests/graphtheory_tests/DFS_test.py @@ -0,0 +1,67 @@ +# Import folder where sorting algorithms +import sys +import unittest +from collections import deque + +# For importing from different folders +# OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from +sys.path.append('Algorithms/graphtheory/depth-first-search/') + +# If run from local: +#sys.path.append('../../Algorithms/graphtheory/depth-first-search/') +from DFS_recursive import DFS as DFS_rec +from DFS_stack_iterative import DFS as DFS_stack + +class test_DFS(unittest.TestCase): + + def setUp(self): + self.G1 = {1:[2],2:[1,3],3:[2]} + self.correct_visited1 = [True] * 3 + self.correct_path1 = [1,2,3] + self.DFS_recursive_visited1 = [False for i in range(1, len(self.G1) + 1)] + + self.G2 = {1:[2], 2:[1,3,4], 3:[2], 4:[2,5], 5:[4]} + self.correct_visited2 = [True] * 5 + self.DFS_recursive_visited2 = [False for i in range(1, len(self.G2) + 1)] + + self.G3 = {1:[2], 2:[1,3,4], 3:[2], 4:[2], 5:[]} + self.correct_visited3 = [True]*4 + [False] + self.DFS_recursive_visited3= [False for i in range(1, len(self.G3) + 1)] + + self.G4 = {1:[2,3,4], 2:[1,3,4], 3:[1,2,4], 4:[1,2,3]} + self.correct_visited4 = [True]*4 + self.DFS_recursive_visited4 = [False for i in range(1, len(self.G4) + 1)] + + + def test_linear_graph(self): + visited, path = DFS_stack(self.G1, start_node=1) + self.assertEqual(visited, self.correct_visited1) + self.assertEqual(path, self.correct_path1) + + DFS_rec(self.G1, 1, self.DFS_recursive_visited1) + self.assertEqual(self.DFS_recursive_visited1, self.correct_visited1) + + def test_simple_graph(self): + visited, path = DFS_stack(self.G2, start_node=1) + self.assertEqual(visited, self.correct_visited2) + + DFS_rec(self.G2, 1, self.DFS_recursive_visited2) + self.assertEqual(self.DFS_recursive_visited2, self.correct_visited2) + + def test_disconnected_graph(self): + visited, path = DFS_stack(self.G3, start_node=1) + self.assertEqual(visited, self.correct_visited3) + + DFS_rec(self.G3, 1, self.DFS_recursive_visited3) + self.assertEqual(self.DFS_recursive_visited3, self.correct_visited3) + + def test_complete_graph(self): + visited, path = DFS_stack(self.G4, start_node=1) + self.assertEqual(visited, self.correct_visited4) + + DFS_rec(self.G4, 1, self.DFS_recursive_visited4) + self.assertEqual(self.DFS_recursive_visited4, self.correct_visited4) + +if __name__ == '__main__': + print("Running BFS/DFS tests:") + unittest.main() \ No newline at end of file diff --git a/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py b/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py new file mode 100644 index 0000000..35e1375 --- /dev/null +++ b/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py @@ -0,0 +1,70 @@ +# Import folder where sorting algorithms +import sys +import unittest + +# For importing from different folders +# OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from +#sys.path.append('Algorithms/graphtheory/kruskal/') + +# If run from local: +sys.path.append('../../Algorithms/graphtheory/kruskal/') +from kruskal_unionfind import kruskal + +class test_Kruskal(unittest.TestCase): + + def setUp(self): + #self.G1 = {1:[(10, 2, 1)], 2:[(10, 1, 2), (10, 3, 2)], 3:[(10, 2, 3)]} + self.G1 = [(10, 2, 1), (10, 1, 2), (10, 3, 2), (10, 2, 3)] + self.num_nodes1 = 3 + self.correct_cost1 = 20 + self.correct_MST1 = [(1,2,10),(2,3,10)] + + self.G2 = [(10,2,1),(10,3,1),(10,1,2),(100,3,2),(10,1,3),(100,2,3)] + self.num_nodes2 = 3 + self.correct_cost2 = 20 + self.correct_MST2 = [(1, 2, 10), (1, 3, 10)] + + self.G3 = [(1,2,1),(1,1,2),(1,3,2),(1,4,3),(5,5,3),(1,3,4),(1,5,4),(5,3,5),(1,4,5)] + self.num_nodes3 = 5 + self.correct_cost3 = 4 + self.correct_MST3 = [(1, 2, 1), (2,3,1), (3,4,1), (4,5,1)] + + self.G4 = [(1,2,1),(1,1,2),(1,4,3),(1,3,4)] + self.num_nodes4 = 4 + self.correct_cost4 = 2 + self.correct_MST4 = [(1,2,1), (3,4,1)] + + self.G5 = {} + self.num_nodes5 = 0 + self.correct_cost5 = 0 + self.correct_MST5 = [] + + # Takes as input G which will have {node1: [(cost, to_node, node1), ...], node2:[(...)] } + def test_linear_graph(self): + MST, cost = kruskal(sorted(self.G1, key=lambda tup:tup[0]), self.num_nodes1) + self.assertEqual(MST, self.correct_MST1) + self.assertEqual(cost, self.correct_cost1) + + def test_triangle_graph(self): + MST, cost = kruskal(sorted(self.G2, key=lambda tup:tup[0]),self.num_nodes2) + self.assertEqual(MST, self.correct_MST2) + self.assertEqual(cost, self.correct_cost2) + + def test_trickier_mst(self): + MST, cost = kruskal(sorted(self.G3, key=lambda tup:tup[0]),self.num_nodes3) + self.assertEqual(MST, self.correct_MST3) + self.assertEqual(cost, self.correct_cost3) + + def test_disconnected_graph(self): + MST, cost = kruskal(sorted(self.G4, key=lambda tup:tup[0]), self.num_nodes4) + self.assertEqual(MST, self.correct_MST4) + self.assertEqual(cost, self.correct_cost4) + + def test_empty_graph(self): + MST, cost = kruskal(self.G5, self.num_nodes5) + self.assertEqual(MST, self.correct_MST5) + self.assertEqual(cost, self.correct_cost5) + +if __name__ == '__main__': + print("Running Kruskal tests:") + unittest.main() \ No newline at end of file diff --git a/Algorithm_tests/graphtheory_tests/prims_algorithm_test.py b/Algorithm_tests/graphtheory_tests/prims_algorithm_test.py new file mode 100644 index 0000000..8122085 --- /dev/null +++ b/Algorithm_tests/graphtheory_tests/prims_algorithm_test.py @@ -0,0 +1,69 @@ +# Import folder where sorting algorithms +import sys +import unittest + +# For importing from different folders +# OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from +sys.path.append('Algorithms/graphtheory/prims/') + +# If run from local: +#sys.path.append('../../Algorithms/graphtheory/prims/') +from prim_heap import prims_algo + +class test_primsHeap(unittest.TestCase): + + def setUp(self): + # How I've decided to construct the graph is confusing, but the reason is because we're using a min heap and + # want first element in the tuple to be the cost of the edge. However when I return the MST, we want it to be + # returned as: from_node, to_node, edge_cost, rather than the reverse for constructing the graph. + + self.G1 = {1:[(10, 2, 1)], 2:[(10, 1, 2), (10, 3, 2)], 3:[(10, 2, 3)]} + self.correct_cost1 = 20 + self.correct_MST1 = [(1,2,10),(2,3,10)] + + self.G2 = {1:[(10, 2, 1), (10, 3, 1)], 2 :[(10, 1, 2), (100, 3, 2)], 3: [(10, 1, 3), (100, 2, 3)]} + self.correct_cost2 = 20 + self.correct_MST2 = [(1, 2, 10), (1, 3, 10)] + + self.G3 = {1:[(1, 2, 1)], 2:[(1, 1, 2), (1, 3, 2)], 3:[(1, 4, 3), (5, 5, 3)], 4:[(1,3,4),(1,5,4)], 5:[(5,3,5),(1,4,5)]} + self.correct_cost3 = 4 + self.correct_MST3 = [(1, 2, 1), (2,3,1), (3,4,1), (4,5,1)] + + self.G4 = {1:[(1, 2, 1)], 2:[(1,1,2)], 3:[(1,4,3)], 4:[(1, 3, 4)]} + self.correct_cost4 = 1 + self.correct_MST4 = [(1,2,1)] + + self.G5 = {} + self.correct_cost5 = 0 + self.correct_MST5 = [] + + # Takes as input G which will have {node1: [(cost, to_node, node1), ...], node2:[(...)] } + def test_linear_graph(self): + MST, cost = prims_algo(self.G1,start=1) + self.assertEqual(MST, self.correct_MST1) + self.assertEqual(cost, self.correct_cost1) + + def test_triangle_graph(self): + MST, cost = prims_algo(self.G2,start=1) + self.assertEqual(MST, self.correct_MST2) + self.assertEqual(cost, self.correct_cost2) + + def test_trickier_mst(self): + MST, cost = prims_algo(self.G3,start=1) + self.assertEqual(MST, self.correct_MST3) + self.assertEqual(cost, self.correct_cost3) + + def test_disconnected_graph(self): + MST, cost = prims_algo(self.G4, start=1) + self.assertEqual(MST, self.correct_MST4) + self.assertEqual(cost, self.correct_cost4) + + def test_empty_graph(self): + MST, cost = prims_algo(self.G5, start=1) + self.assertEqual(MST, self.correct_MST5) + self.assertEqual(cost, self.correct_cost5) + + +if __name__ == '__main__': + print("Running Prims Heap tests:") + unittest.main() \ No newline at end of file diff --git a/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py b/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py index ccfd057..c5344be 100644 --- a/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py +++ b/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py @@ -37,7 +37,7 @@ def BFS(G, start_node=1): if __name__ == '__main__': G, num_nodes = load_graph() - #G = {1:[2,3], 2:[1,4], 3:[1,4],4:[]} + # G = {1:[2,3], 2:[1,4], 3:[1,4],4:[]} visited, path = BFS(G) diff --git a/Algorithms/graphtheory/breadth-first-search/__pycache__/BFS_queue_iterative.cpython-37.pyc b/Algorithms/graphtheory/breadth-first-search/__pycache__/BFS_queue_iterative.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00bb44405c5a15c68308001e8cac47d87d03950c GIT binary patch literal 1322 zcmZWo&u`pB6rMLT_IkaWl$J_qs)Eb`BqO>(Iie+kQWZ{-Xd*>grMRwVvg_7sd&je7 z8`%=lh6^_&{s401Uz#hY{tMy4n+Zvvj6Bb8e!lO0-=lrf(d>G6Dl@^FM8-P$wlyrs$)sl>(izw_Y(91m`#0E| zr)V^35!jk`kduzCc3XH%o_*ReK?OS_E&CnL$z!sHj<;NJL4Ky&q^0P4+hj}@caMms zEyZ;YXT1}OK>U3J>N+CDAV>^3uo3T~nPS9e!wxVqtl?L>;0NRni<{-8j;W!e&kd}U zMd{4Nccak`eqR^UO67VsZ+2W>dL}FNX6J>HsnD~BC%J0$!$zhmn;k!Ta*!YgOPS@GNW(>{Qv=@`UgV{mu%gkXUoPiKSqa(PEP+A?W2(GUoM z(-7{!JsMDD$x;I}nZ;>a5Bs%xzu`cDpl7I|U>aIfNw6)lrcN)av5-233bGc?u}G$* zZgH}iRb?qNTz2Dk5E_PvZdru)(GYk*eF!N>8{mHkL%In=xI@(kHfWF}^E5A$ z -# 2019-02-17 Initial programming +Programmed by Aladdin Persson + 2019-02-17 Initial programming + 2020-03-29 Cleaned up code, made test cases +''' -# Improvements: think this should work pretty well (include tests would be good) - -import time def load_graph(file='exgraph.txt'): data = open(file, 'r') @@ -21,8 +21,6 @@ def load_graph(file='exgraph.txt'): return G, num_nodes def DFS(G, start_node): - start = time.time() - visited = [False for i in range(1, len(G) + 1)] path = [start_node] stack = [] @@ -38,7 +36,6 @@ def DFS(G, start_node): stack.append(connected_node) path.append(connected_node) - total_time = (time.time() - start) print(f'Total time: {total_time} seconds') return visited, path @@ -46,7 +43,6 @@ def DFS(G, start_node): if __name__ == '__main__': G, num_nodes = load_graph() start_node = 1 - #G = {1:[2,3], 2:[1,4], 3:[1,4],4:[]} visited = DFS(G, start_node) if all(visited) == True: diff --git a/Algorithms/graphtheory/depth-first-search/__pycache__/DFS_recursive.cpython-37.pyc b/Algorithms/graphtheory/depth-first-search/__pycache__/DFS_recursive.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a09c3cc4fb308c851124a0b0f8f9317bb8885b04 GIT binary patch literal 1195 zcmZ8gL2u(k6n<|!P94|jR!d=1gittorA-mXRa7lYDHl|sZKZ;>i)Av?#9C*Zj;E`n zawJ5G#1#&l;mBW_E2sSnJ@IB*TG)x-^US>Qy!UxwvwB}y)1**?i^XvcNrNa;bg}y;|{qAWqg&a zkTT;Me`V+V82*A3ZBQzcGRuaaT3qOWj(T_fY&hJb=ksb(>(WeT&7Q|)rn1({Jt602 z`sA$Cjd{|@LXW2}4-SuWEyowSDc{K9e0d#@sQ;jsxCx+L(-_K z$3@lb5ATn@b)>x|gEX+bo=auJW?q%X29;E4$MUnXl9r3Y6c)d-yegH{&myMZqn)vX?}lsEUBjN!f@ns8eb@!PEr?Y? z^xy1^h}af)VHGU;Z9r|@UUApnmQ#aBE9Z|-!F`biN4iTlojA^kt2ETxw9LB1nD$lM zjW=ae8Y!|^$#OFNp(ZY~u96Gm zM)#-PBfD+Bc56?=;pO0kY%VJEbZ{~)o7>W8GOm@9V`AZxqZG9hLz?*J+@Vs%Oy;=_ zJqAyren`h`_hdPj9*_-np(axIT(Ez+ub2|bU$Ug90@Yih zT%$GLsWllc5upqyT6dAe1Bf@?5(4bsuB-V(r}cDb<|acoM}x`&kL(+=<~2D3Ep1z} z1?I3|^DkQ5gX3olE}7(4(DG}%fjwB_LbO5(2|u#|w2WeJ03$ei@&*iR8U6QY);nQT zfWL21uMio52(kl*_=Mbq5Rdx{BxGFTuk1`5z@HGK<#}mhX4&wi#kqESI(PegIQ(3y z+Du=ZD1&GYFPht8;**+FOO z@m)hkMU|yRvpalP`qni_I~Q{+s#=xSYw995mKUmweJf7#LRleGlUn@NiXtyn!i&b( zweoy6E-R^;hnjUjC)w};bDi>LlN?}(f`#}Pw^_jS2Q-tp65UuMTaoiOB?hkHhG>x} z*%cU+oSIE!NWKM2*3rUSoDew^AOgH=%5F#p^Q86kZ5tA3 zodkOO|KZ<>zvJIA((xZGP{JMeF}~^=7c=eDX)%AVkJ|O+BeHugw}^V;?tdg|_xuho z`-hcDi^$|NwG&+iQKPb|l#L_N%~?;UxVEU?2NzlRW8z_3;tYpU@f`jK{MyFUR9|7mQvjbFRys=x~}hQK#vMf>jNlUVgb> znJ6uasMBTiqtYtUD$SD@vDvt-0So)VR&e(q=(-{M7gMG-t^fc4 literal 0 HcmV?d00001 diff --git a/Algorithms/graphtheory/kruskal/__pycache__/kruskal.cpython-37.pyc b/Algorithms/graphtheory/kruskal/__pycache__/kruskal.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6222719954cca188d96a7c96962feefa6c929733 GIT binary patch literal 1745 zcmZ`)%ZnQ~7?(6pPi*J4d3Xz9(!;hctap<`Ld&u=%{C!~CWQ?o9X1^XOSUJT*Gh8O zHDf4sax10KV=3&?Q~Ou+RQe|rT?>U=d(5T%G-Gc{pc?BN>3c|{-|y4sPg*SxLHpy` zS6}Yg2>q!i%VxmfW9Z^L5EKQ7VoDMmV1}QOBZC^p7;BxGn5h+5Fg{If>b$^#OYkbYEQuUIG|>5p=mMsecPT>AYy-S&KF*Eg?y zxW0LP{n`!xUKYz3HY<1z%cijR(DPmabm+nKLa(<$Ss_R3gP04sE?C6-qb^p)&Yj)Y z4MvAd^yGo;W9<*kf$l=T4PAT-Vu)t=uq{yuh|kH4JVx1N6G=Sw_y-s;1@y_+_zRSg zC#WPx}N;)DSpO!yg~!VY2~uX25cSC#k&TDPIhykMDf z?mhgJ^PH;&XAw=}j0t6=QK5`DlgbiB5=&)A1^7~B$w`qgWs96kM!SwO2e6gGcNHE4 z4ILaNu$gLPlQhh7%0y5NDTg(+@PAVzhMB35sGI9CDeF< zB%)>scjXfBu!H7!W*+=rYW#nlS*2N8)aoD$br6iq4jST{$Us}DvcP;{0iUHs0uyyq z#j8DYB#}nx%z-0G^c(KoZ>0e~xPxv&Hq_oF89V$J$dE;}X1Ct6vi!BMz@8QFYs+2g z90Fe*2iE0$f9)~kTWKt^q9Xq!i#0YT^j+xU9Ece5_o+9-Lsa7L$-cQ;b5s%4C5rSm zl`&?A)w~uLA?mfaMdQANOIK`P)l2DhZ8UvnN!nJD_oGB?_ulw%3w&N_$F8j`9%Vzu z^-LKFhW%W~z?Lj6!n=XXqW&m^u)uj9ix`qp znMEW=Z+)tA7TlAl+sX+;n)kyHkUJDylTgEV9_m*pWYiyrfC-Oe{Jh4wx*R8G%c7J) zuvKul>uWgb)y*LWuOCl~PuL?JD-&t+MM~Y_F7@ zb`j#zSH1v3N*?)2e&s1&p)W9Y+O#ltGqz{O_RR0+yDv94Q$YD(`Rh;j0)W5m;<C(Km%? z8CSWRIwXy66aE5u3oCj0@$T*(e!r*}t*rF2QF{wnc1ykFtvuU1k-a)8>!W95al^`P zcV^PMEm`5xEg5Qx28d57ncyd-F}+Q<$Q>%*K>sndQIrHVM0MPq;{;hl8uk7@@YaZWI z*$vT|-M+eYzn7Wik+aM(nN{kOZ1s+Hy94{?e+Rnws}Ea^SK02|hJzWA_J0JSv8Xx5 zZ|W6@Us0H#llYWhKqq%FGfxq_vUcdbgo%Bc(g72H+O({%`DgacDC^pw=~g_65tWdp Jbb@vR?Z3DKH-P{E literal 0 HcmV?d00001 diff --git a/Algorithms/graphtheory/kruskal/kruskal.py b/Algorithms/graphtheory/kruskal/kruskal.py index 55f8334..0961ee8 100644 --- a/Algorithms/graphtheory/kruskal/kruskal.py +++ b/Algorithms/graphtheory/kruskal/kruskal.py @@ -1,16 +1,15 @@ -# Kruskal's algorithm for finding minimal spanning tree (MST) of a graph. +''' +Kruskal's algorithm for finding minimal spanning tree (MST) of a graph. -# Aladdin Persson -# 2019-02-16 Initial programming +Aladdin Persson + 2019-02-16 Initial programming -# Improvements: -# * The for-loop inside Kruskal can be improved for sure. Not sure exactly how to do it though +''' import sys -sys.path.append('graphtheory/depth-first-search') +sys.path.append('../depth-first-search') from DFS_stack_iterative import DFS - def load_graph(file='edges.txt'): G = [] @@ -28,8 +27,7 @@ def load_graph(file='edges.txt'): return sorted(G), num_nodes - -def kruskal(G): +def kruskal(G, num_nodes): MST = [] tot_cost = 0 temp_G = {key: [] for key in range(1, num_nodes + 1)} @@ -62,8 +60,6 @@ def kruskal(G): G, num_nodes = load_graph() print(f'Our loaded graph is: {G}') - print() - MST, total_cost = kruskal(G) print(f'Our minimum spanning tree is: {MST}') diff --git a/Algorithms/graphtheory/kruskal/kruskal_unionfind.py b/Algorithms/graphtheory/kruskal/kruskal_unionfind.py index 50fbf7e..96ec4e0 100644 --- a/Algorithms/graphtheory/kruskal/kruskal_unionfind.py +++ b/Algorithms/graphtheory/kruskal/kruskal_unionfind.py @@ -23,7 +23,7 @@ def load_graph(file='edges.txt'): return sorted(G), num_nodes -def kruskal(G): +def kruskal(G, num_nodes): uf = unionfind(num_nodes) tot_cost, MST = 0, [] @@ -33,7 +33,7 @@ def kruskal(G): if not uf.issame(from_node-1, to_node-1): tot_cost += cost uf.unite(from_node-1, to_node-1) - MST.extend([from_node, to_node]) + MST.append((from_node, to_node, cost)) return MST, tot_cost diff --git a/Algorithms/graphtheory/prims/__pycache__/prim_heap.cpython-37.pyc b/Algorithms/graphtheory/prims/__pycache__/prim_heap.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1783ecd96e348c193c37661ed5dd6cfe79827178 GIT binary patch literal 2347 zcmaJ?OK%)S5bo}I?CivLqF@3>C^S(>JW{-Ij06N(Rzi3r2OLYW6j(Wo#@oHSBhSk{ zz41e{2;m@-TM$QtWFPql9N}+_xN*u~$OWo;z3U_r%x>58RCjf~zN-FYdfF%Ogqz=e z6Ts|m{1`tLOm4s^*MSJqCV~o<&^8rQ!WPaW+Gb)}G=v8;OWLBj#nhT~gnvLOk?er9 zU1>@8fNrpMqwT@UDe3(}er32W*gX==M1N93{52J)C6AI`u43I!c{f+Q8)qWUdOVG@ zIE@ls7EzWVLn|ry{FnFE1D zuG1(^TAe&y@i{z8i`T9%EG{iv`+(ocVjV+R3YCMd6r$8S-mOWnD`VS#s!rTh7g@e<+#b`%4Q&3p#T zPOcP$D%lJCXMhi~`n)McPnIpct2>ZY^Ef~~7zm{@0kSuvNd-VUU_*MJWN+F;(=A_J zq6B|}eNVq88T*P<^pG8qC*&~^)*Lysj>rZZvZ3`O=~4qePus%PP6c2R?i=KQeM%1K z&;~j82u`YOfLCL+rfPro^BCL|IRqffHHS=;`dx(uF!$K+?WjVkQP84Sc4<1^M^(!(=u4=FfI59tw9(43LnV&&q5N5?#6 zYo@I+{{Y=$MkBcY)3GjN^fNSe_1Qo01a@u3nXa9(NMd;D0RXMG(x?bn&034K1)PA^ zHm3hK^89M6h5wu5LMyKtoC11twRaW4UTz=_`%pBkV(+=XoItQJ?<;SC*3t&z5=Qrf zB#%TmD!t_-??g$t(pnaAXSBI>BBxMhRZRm8sKRCg1~t*35YGnQ6!6px5KuQc!KlNK zx@`aa|0^>Zf<|rUh0N;4ox7hYm8-g`WF!pk6{e+j6qbX+G}lfi$x9hHwcQ15)U?}f zW`i`$av{sn)IhnWUyKbu17gO=+CQ-djV@<_5X$Hb{CwuIGq%spF^?*A!PwS8Kkz|M zu_A84D6c>su@)fF6dLDj4`9}Xrie*@1XUsI<5hctZq_41OCZYGA*<*Sw9(2sv_>;n zb1Hz^92vUWK6EM<*LVM@*i))5z**3Ujizrar?OEK>~e9}hBa&qyd`WJ90=oJU5JIP@$KIwkwV6+S zpdO-^P9cKf3kE%F=owsrpT}nCIi|2X)?OIG&6I`V{>=q=%oR7#|9xGLuHrRw%}=@y zH=_Rj<@H>{O@Cbn=T^3Ui1RNDz3fdG#7(Ju3(2UXo83^f7TB?@Z6 -# 2019-02-16 Initial programming +Aladdin Persson + 2019-02-16 Initial programming + 2020-03-29 Changed few lines to be able to handle empty graphs, etc, and changed how MST is computed (now correctly) +''' import heapq @@ -19,42 +21,50 @@ def load_graph(file='edges.txt'): num_nodes, num_edges = line_list[0].split() + # We want to have edge cost first because the min heap will be based on edge cost + # concretely that's why we do [::-1], a bit confusing maybe G = {line: [tuple(map(int, tup.split()))[::-1] for tup in line_list[1:] if (int(tup.split()[0]) == line or int(tup.split()[1]) == line)] for line in range(1, int(num_nodes) + 1)} f.close() - return G, int(num_nodes) + return G +# Takes as input G which will have {node1: [(cost, to_node, node1), ...], node2:[(...)] } +def prims_algo(G, start=1): + if len(G) == 0: + return [], 0 -def prims_algo(G, num_nodes): - unvisited_nodes = [i for i in range(1, num_nodes + 1)] + unvisited_nodes = [i for i in range(1, len(G) + 1)] visited_nodes = [] - - start = 1 tot_cost = 0 unvisited_nodes.remove(start) visited_nodes.append(start) - MST = [start] + MST = [] heap = G[start] heapq.heapify(heap) while unvisited_nodes: + if len(heap) == 0: + # there is no MST because graph is disconnected then return MST of subgraph + return MST, tot_cost + (cost, n2, n1) = heapq.heappop(heap) new_node = None if n1 in unvisited_nodes and n2 in visited_nodes: new_node = n1 + MST.append((n2, n1, cost)) elif n1 in visited_nodes and n2 in unvisited_nodes: new_node = n2 + MST.append((n1, n2, cost)) if new_node != None: unvisited_nodes.remove(new_node) visited_nodes.append(new_node) - MST.append(new_node) tot_cost += cost for each in G[new_node]: @@ -65,10 +75,8 @@ def prims_algo(G, num_nodes): if __name__ == '__main__': print('---- Computing minimal spanning tree using Prims Algorithm ---- \n') - G, num_nodes = load_graph() - print(f'Our loaded graph is: {G} \n') - - MST, tot_cost = prims_algo(G, num_nodes) + G = load_graph() + MST, tot_cost = prims_algo(G) - print(f'The minimum spanning tree is: {MST}') + #print(f'The minimum spanning tree is: {MST}') print(f'Total cost of minimum spanning tree is {tot_cost}') diff --git a/Algorithms/graphtheory/prims/prims_algorithm.py b/Algorithms/graphtheory/prims/prim_naive.py similarity index 92% rename from Algorithms/graphtheory/prims/prims_algorithm.py rename to Algorithms/graphtheory/prims/prim_naive.py index ef55a83..2cc7dca 100644 --- a/Algorithms/graphtheory/prims/prims_algorithm.py +++ b/Algorithms/graphtheory/prims/prim_naive.py @@ -18,23 +18,18 @@ def load_graph(path = 'edges.txt'): node1,node2,edge_cost = [int(i) for i in line.split()] edge_list.append( (node1,node2,edge_cost)) - return edge_list, num_nodes, num_edges - def prims_algo(edge_list, num_nodes): - X = [] V = [i for i in range(1, num_nodes + 1)] E = [] total_cost = 0 - start = 1 X.append(start) V.remove(start) - while len(V) != 0: lowest_cost = float('inf') nodeX = None @@ -67,9 +62,6 @@ def prims_algo(edge_list, num_nodes): edge_list, num_nodes, num_edges = load_graph() - E,tot_cost = prims_algo(edge_list, num_nodes) - - #print(E) - print(f'total cost of minimum spanning tree is {tot_cost}') + E, tot_cost = prims_algo(edge_list, num_nodes) diff --git a/README.md b/README.md index db8322f..c589736 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,13 @@ Whenever I face an interesting problem I document the algorithm that I learned t * :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/djikstra.py) **- Naive implementation** * :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/heapdijkstra.py) **O(mlog(n)) - Heap implementation** * :small_red_triangle: [Karger's Minimum cut](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kargers/kargermincut.py) -* :small_red_triangle: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prims_algorithm.py) **- Naive implementation** -* :small_red_triangle: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/primheap.py) **- mlog(n)** -* :small_red_triangle: [Kruskal's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal.py) **- Naive implementation** -* :small_red_triangle: [Kruskal's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal_unionfind.py) **- mlog(n)** -* :small_red_triangle: [Breadth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py) **O(n + m) - Queue Implementation** -* :small_red_triangle: [Depth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py) **O(n + m) - Stack Implementation** -* :small_red_triangle: [Depth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_recursive.py) **O(n + m) - Recursive Implementation** +* :small_red_triangle: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prims_algorithm.py) **- O(mn) Naive implementation** +* :white_check_mark: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/primheap.py) **- O(mlog(n))** +* :small_red_triangle: [Kruskal's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal.py) **- O(mn) implementation** +* :white_check_mark: [Kruskal's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal_unionfind.py) **- O(mlog(n))** +* :white_check_mark: [Breadth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py) **O(n + m) - Queue Implementation** +* :white_check_mark: [Depth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py) **O(n + m) - Stack Implementation** +* :white_check_mark: [Depth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_recursive.py) **O(n + m) - Recursive Implementation** # Mathematics ### Algebra From 897caedb2014031aa573117aee48e711da6639d6 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:21:50 +0200 Subject: [PATCH 12/60] updated readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c589736..e20890e 100644 --- a/README.md +++ b/README.md @@ -19,18 +19,18 @@ Whenever I face an interesting problem I document the algorithm that I learned t * :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/heapdijkstra.py) **O(mlog(n)) - Heap implementation** * :small_red_triangle: [Karger's Minimum cut](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kargers/kargermincut.py) * :small_red_triangle: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prims_algorithm.py) **- O(mn) Naive implementation** -* :white_check_mark: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/primheap.py) **- O(mlog(n))** +* :white_check_mark: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/primheap.py) **- O(mlog(n)) Heap implementation** * :small_red_triangle: [Kruskal's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal.py) **- O(mn) implementation** * :white_check_mark: [Kruskal's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal_unionfind.py) **- O(mlog(n))** -* :white_check_mark: [Breadth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py) **O(n + m) - Queue Implementation** -* :white_check_mark: [Depth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py) **O(n + m) - Stack Implementation** -* :white_check_mark: [Depth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_recursive.py) **O(n + m) - Recursive Implementation** +* :white_check_mark: [Breadth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py) **- O(n + m) - Queue Implementation** +* :white_check_mark: [Depth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py) **- O(n + m) - Stack Implementation** +* :white_check_mark: [Depth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_recursive.py) **- O(n + m) - Recursive Implementation** # Mathematics ### Algebra * :small_red_triangle: [Karatsuba Multiplication](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/karatsuba/karatsuba.py) **- O(n1.585)** -* :small_red_triangle: [Intersection of two sets](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/intersection_of_two_sets/intersection_of_two_sets.py) **- O(nlog(n)) + O(mlog(m))** -* :small_red_triangle: [Union of two sets](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/union_of_two_sets/union_of_two_sets.py) **- O(nlog(n)) + O(mlog(m))** +* :white_check_mark: [Intersection of two sets](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/intersection_of_two_sets/intersection_of_two_sets.py) **- O(nlog(n)) + O(mlog(m))** +* :white_check_mark: [Union of two sets](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/union_of_two_sets/union_of_two_sets.py) **- O(nlog(n)) + O(mlog(m))** ### Number Theory * :small_red_triangle: [Pollard p-1 factorization](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/pollard_p1/pollard_p1.py) From 5c266d02bdb74f0b7048940ffffdbd9db0f7e053 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:23:00 +0200 Subject: [PATCH 13/60] Updated tests --- Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py | 4 ++-- .../graphtheory/depth-first-search/DFS_stack_iterative.py | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py b/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py index 35e1375..491ca71 100644 --- a/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py +++ b/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py @@ -4,10 +4,10 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -#sys.path.append('Algorithms/graphtheory/kruskal/') +sys.path.append('Algorithms/graphtheory/kruskal/') # If run from local: -sys.path.append('../../Algorithms/graphtheory/kruskal/') +#sys.path.append('../../Algorithms/graphtheory/kruskal/') from kruskal_unionfind import kruskal class test_Kruskal(unittest.TestCase): diff --git a/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py b/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py index c234320..bc226ee 100644 --- a/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py +++ b/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py @@ -36,8 +36,6 @@ def DFS(G, start_node): stack.append(connected_node) path.append(connected_node) - print(f'Total time: {total_time} seconds') - return visited, path if __name__ == '__main__': From 48c7f9406abfefba2fcf34b923eb16be9d288a8e Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:23:34 +0200 Subject: [PATCH 14/60] updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e20890e..54e3c38 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Whenever I face an interesting problem I document the algorithm that I learned t * :small_red_triangle: [Prime factorization](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/prime_factorization/primefactorization.py) **- O(sqrt(n))** ### Cryptography -* :small_red_triangle: [Ceasar Cipher](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py) +* :white_check_mark: [Ceasar Cipher](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py) * :small_red_triangle: [Hill Cipher](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/hill_cipher/hill_cipher.py) * :small_red_triangle: [Vigenere Cipher](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/vigenere_cipher/vigenere.py)* * :small_red_triangle: [One time pad](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/one_time_pad/one_time_pad.py) From 2f3321a5c672fb06bf7de1689fcf2865530ca171 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:29:54 +0200 Subject: [PATCH 15/60] updated tests --- Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py | 1 + Algorithms/math/prime_factorization/primefactorization.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py b/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py index 491ca71..afd64e5 100644 --- a/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py +++ b/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py @@ -1,6 +1,7 @@ # Import folder where sorting algorithms import sys import unittest +from unionfind import unionfind # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from diff --git a/Algorithms/math/prime_factorization/primefactorization.py b/Algorithms/math/prime_factorization/primefactorization.py index 2d95d3a..507ac44 100644 --- a/Algorithms/math/prime_factorization/primefactorization.py +++ b/Algorithms/math/prime_factorization/primefactorization.py @@ -31,4 +31,4 @@ def primefactorization(n): if __name__ == '__main__': #primefactorization(2**2**6 + 1) - primefactorization(137) \ No newline at end of file + primefactorization(9985345712831283923105983448123) \ No newline at end of file From ec7ecb9d8a5df5892ff615fa95733542cd1b80e5 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:32:00 +0200 Subject: [PATCH 16/60] updated travis yml --- .travis.yml | 7 +++++-- requirements.gitignore | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 requirements.gitignore diff --git a/.travis.yml b/.travis.yml index e5d5227..dd77d3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,9 +12,12 @@ before_install: before_script: - gem install awesome_bot + +install: + - pip install -r requirements.txt + script: - awesome_bot README.md --allow-dupe --allow-redirect - # Dynamic Programming Tests - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py @@ -26,7 +29,7 @@ script: - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py - - python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py + #- python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py - python Algorithm_tests/graphtheory_tests/BFS_test.py - python Algorithm_tests/graphtheory_tests/DFS_test.py diff --git a/requirements.gitignore b/requirements.gitignore new file mode 100644 index 0000000..0d3155d --- /dev/null +++ b/requirements.gitignore @@ -0,0 +1 @@ +pip install unionfind \ No newline at end of file From 9f31c741d21070b287a16b02095d19d26d8921dd Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:39:01 +0200 Subject: [PATCH 17/60] updated travis yml --- .travis.yml | 5 ++--- requirements.gitignore | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd77d3e..440cbca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,9 @@ before_install: before_script: - gem install awesome_bot - install: - pip install -r requirements.txt - + script: - awesome_bot README.md --allow-dupe --allow-redirect # Dynamic Programming Tests @@ -28,8 +27,8 @@ script: - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py - - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py #- python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py + - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py - python Algorithm_tests/graphtheory_tests/BFS_test.py - python Algorithm_tests/graphtheory_tests/DFS_test.py diff --git a/requirements.gitignore b/requirements.gitignore index 0d3155d..910f215 100644 --- a/requirements.gitignore +++ b/requirements.gitignore @@ -1 +1 @@ -pip install unionfind \ No newline at end of file +unionfind \ No newline at end of file From 34ed013d28b66b34b7c09282dce89a4bd79099e1 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:42:47 +0200 Subject: [PATCH 18/60] updated travis yml --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 440cbca..9c303d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,7 @@ before_install: before_script: - gem install awesome_bot -install: - - pip install -r requirements.txt +install "pip install -r requirements.txt" script: - awesome_bot README.md --allow-dupe --allow-redirect From ff432e88bbe4375929f56e858bd5920661bb6454 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:45:01 +0200 Subject: [PATCH 19/60] updated travis yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9c303d0..9cd5fd3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ before_install: before_script: - gem install awesome_bot -install "pip install -r requirements.txt" +#install "pip install -r requirements.txt" script: - awesome_bot README.md --allow-dupe --allow-redirect From 8f9e22dab33fe6dfd3701aaab582f8982c4e0801 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:48:23 +0200 Subject: [PATCH 20/60] updated travis yml --- .travis.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9cd5fd3..7a60dab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,14 +5,15 @@ python: 3.7 # Install ruby to get gem command before_install: - - sudo apt-add-repository -y ppa:brightbox/ruby-ng - - sudo apt-get -y update - - sudo apt-get -y install ruby-full + - sudo apt-add-repository -y ppa:brightbox/ruby-ng + - sudo apt-get -y update + - sudo apt-get -y install ruby-full before_script: - - gem install awesome_bot + - gem install awesome_bot -#install "pip install -r requirements.txt" +#install: +# - "pip install -r requirements.txt" script: - awesome_bot README.md --allow-dupe --allow-redirect From 14b59070574d27049a546c28efc0a14eac19812d Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:50:41 +0200 Subject: [PATCH 21/60] updated travis yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 7a60dab..78714d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ before_install: before_script: - gem install awesome_bot + - pip3 install unionfind #install: # - "pip install -r requirements.txt" From d533e5779bd00306c28b31f84d8c03fac729e8a1 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:51:07 +0200 Subject: [PATCH 22/60] updated travis yml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 78714d8..142402b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,10 +8,11 @@ before_install: - sudo apt-add-repository -y ppa:brightbox/ruby-ng - sudo apt-get -y update - sudo apt-get -y install ruby-full + - pip3 install unionfind before_script: - gem install awesome_bot - - pip3 install unionfind + #install: # - "pip install -r requirements.txt" From d157e9461b2d5d4b3b4a2bd05e9a85753048337f Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:53:13 +0200 Subject: [PATCH 23/60] updated travis yml --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 142402b..fdd1484 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,14 +8,13 @@ before_install: - sudo apt-add-repository -y ppa:brightbox/ruby-ng - sudo apt-get -y update - sudo apt-get -y install ruby-full - - pip3 install unionfind before_script: - gem install awesome_bot -#install: -# - "pip install -r requirements.txt" +install: + - pip3 install unionfind script: - awesome_bot README.md --allow-dupe --allow-redirect From 3fa8c2d41f002e2e2eadf0bbad3c0a716be3270a Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:54:44 +0200 Subject: [PATCH 24/60] updated travis yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fdd1484..1a95e24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,8 @@ before_script: - gem install awesome_bot -install: - - pip3 install unionfind +#install: +# - pip3 install unionfind script: - awesome_bot README.md --allow-dupe --allow-redirect From 59f4fa19463ee92c9c7cdf302ed33b1afbce588e Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:57:38 +0200 Subject: [PATCH 25/60] add kruskal --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1a95e24..4cc3f50 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ script: - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py - #- python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py + - python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py - python Algorithm_tests/graphtheory_tests/BFS_test.py - python Algorithm_tests/graphtheory_tests/DFS_test.py From 1f19995cdab5fc551d296dd816b887c1fe1136c8 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 12:59:20 +0200 Subject: [PATCH 26/60] add kruskal --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4cc3f50..6ee889d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,8 @@ before_script: - gem install awesome_bot -#install: -# - pip3 install unionfind +install: + - pip3 install unionfind script: - awesome_bot README.md --allow-dupe --allow-redirect From bc592719d196dfe1e673a73c01c577e4419b8098 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 13:02:23 +0200 Subject: [PATCH 27/60] add kruskal --- .travis.yml | 3 ++- requirements.gitignore => requirements.txt.gitignore | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename requirements.gitignore => requirements.txt.gitignore (100%) diff --git a/.travis.yml b/.travis.yml index 6ee889d..86f44b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,8 @@ before_script: install: - - pip3 install unionfind + #- pip3 install unionfind + - pip3 install -r requirements.txt script: - awesome_bot README.md --allow-dupe --allow-redirect diff --git a/requirements.gitignore b/requirements.txt.gitignore similarity index 100% rename from requirements.gitignore rename to requirements.txt.gitignore From 4e62862131ca40f72d82335697ff6fdc374fbbb1 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 14:55:59 +0200 Subject: [PATCH 28/60] add kruskal --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 86f44b5..91f7751 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,8 @@ before_script: install: - #- pip3 install unionfind - - pip3 install -r requirements.txt + - pip3 install unionfind + #- pip3 install -r requirements.txt script: - awesome_bot README.md --allow-dupe --allow-redirect From 702dd88082a1bcc4b3c7142a338368abe313ad2b Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 14:57:13 +0200 Subject: [PATCH 29/60] add kruskal --- .travis.yml | 4 ++-- requirements.txt.gitignore => requirements.txt | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename requirements.txt.gitignore => requirements.txt (100%) diff --git a/.travis.yml b/.travis.yml index 91f7751..86f44b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,8 @@ before_script: install: - - pip3 install unionfind - #- pip3 install -r requirements.txt + #- pip3 install unionfind + - pip3 install -r requirements.txt script: - awesome_bot README.md --allow-dupe --allow-redirect diff --git a/requirements.txt.gitignore b/requirements.txt similarity index 100% rename from requirements.txt.gitignore rename to requirements.txt From 4b274ee695637ef7d82a7bbdd5a84021b34eb78a Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 15:14:31 +0200 Subject: [PATCH 30/60] add kruskal --- .travis.yml | 1 - Algorithms/math/prime_factorization/primefactorization.py | 4 ++-- requirements.txt | 6 +++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 86f44b5..59fc8d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ before_script: install: - #- pip3 install unionfind - pip3 install -r requirements.txt script: diff --git a/Algorithms/math/prime_factorization/primefactorization.py b/Algorithms/math/prime_factorization/primefactorization.py index 507ac44..c3299ac 100644 --- a/Algorithms/math/prime_factorization/primefactorization.py +++ b/Algorithms/math/prime_factorization/primefactorization.py @@ -1,7 +1,7 @@ ''' Purpose is given a number write it only as a factorization of primes. -Time complexity: O(sqrt(n)) +Time complexity: O(sqrt(n)) PSEUDO-POLYNOMIAL, actually exponential! Programmed by Aladdin Persson * 2019-03-18 Initial programming @@ -31,4 +31,4 @@ def primefactorization(n): if __name__ == '__main__': #primefactorization(2**2**6 + 1) - primefactorization(9985345712831283923105983448123) \ No newline at end of file + primefactorization(123) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 910f215..c833bdb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,5 @@ -unionfind \ No newline at end of file +unionfind==0.0.10 +numpy==1.18.1 +bitarray==1.2.1 +egcd==0.0.1.1 +sympy==1.5.1 From 6d3602eaab3338455de15b0e9ecb52d3086cc1cd Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 15:17:17 +0200 Subject: [PATCH 31/60] updated travis, try code coverage --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 59fc8d8..c44291e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ before_script: install: - pip3 install -r requirements.txt + - pip3 install coveralls script: - awesome_bot README.md --allow-dupe --allow-redirect @@ -47,3 +48,6 @@ script: # Sorting tests - python Algorithm_tests/sorting_tests/test_sorting.py + +after_success: + - coveralls \ No newline at end of file From 5c44458713cc868f372f55fb88e953db6bd9cc98 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 15:29:17 +0200 Subject: [PATCH 32/60] updated travis, try code coverage --- .travis.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c44291e..7257d4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,16 @@ language: python # Default Python version is usually 2.7 +python: 3.5 +python: 3.6 python: 3.7 # Install ruby to get gem command before_install: + - python --version + - pip install -U pip + - pip install -U pytest + - pip install codecov - sudo apt-add-repository -y ppa:brightbox/ruby-ng - sudo apt-get -y update - sudo apt-get -y install ruby-full @@ -15,7 +21,7 @@ before_script: install: - pip3 install -r requirements.txt - - pip3 install coveralls + #- pip3 install coveralls script: - awesome_bot README.md --allow-dupe --allow-redirect @@ -50,4 +56,4 @@ script: - python Algorithm_tests/sorting_tests/test_sorting.py after_success: - - coveralls \ No newline at end of file + #- coveralls \ No newline at end of file From a41b7375c82601b5072fa0ea9baf79bbbb5ca0dc Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 15:46:56 +0200 Subject: [PATCH 33/60] testing pytest --- .travis.yml | 53 ++++++++++++++++++++++++++--------------------------- pytest.ini | 3 +++ 2 files changed, 29 insertions(+), 27 deletions(-) create mode 100644 pytest.ini diff --git a/.travis.yml b/.travis.yml index 7257d4e..8ccf268 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,6 @@ language: python # Default Python version is usually 2.7 -python: 3.5 -python: 3.6 python: 3.7 # Install ruby to get gem command @@ -24,36 +22,37 @@ install: #- pip3 install coveralls script: - - awesome_bot README.md --allow-dupe --allow-redirect - # Dynamic Programming Tests - - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py - - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py - - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py + pytest + # - awesome_bot README.md --allow-dupe --allow-redirect + # # Dynamic Programming Tests + # - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py + # - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py + # - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py - # Graph Theory Tests - - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py - - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py - - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py - - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py - - python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py - - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py - - python Algorithm_tests/graphtheory_tests/BFS_test.py - - python Algorithm_tests/graphtheory_tests/DFS_test.py + # # Graph Theory Tests + # - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py + # - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py + # - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py + # - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py + # - python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py + # - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py + # - python Algorithm_tests/graphtheory_tests/BFS_test.py + # - python Algorithm_tests/graphtheory_tests/DFS_test.py - # Math tests - - python Algorithm_tests/other_tests/test_binarysearch.py - - python Algorithm_tests/math_tests/intersection_test.py - - python Algorithm_tests/math_tests/union_test.py + # # Math tests + # - python Algorithm_tests/other_tests/test_binarysearch.py + # - python Algorithm_tests/math_tests/intersection_test.py + # - python Algorithm_tests/math_tests/union_test.py - # Cryptography tests - - python Algorithm_tests/cryptology_tests/ceasar_test.py + # # Cryptography tests + # - python Algorithm_tests/cryptology_tests/ceasar_test.py - # "Other" tests - - python Algorithm_tests/other_tests/test_medianmaintenance.py - - python Algorithm_tests/other_tests/test_intervalscheduling.py + # # "Other" tests + # - python Algorithm_tests/other_tests/test_medianmaintenance.py + # - python Algorithm_tests/other_tests/test_intervalscheduling.py - # Sorting tests - - python Algorithm_tests/sorting_tests/test_sorting.py + # # Sorting tests + # - python Algorithm_tests/sorting_tests/test_sorting.py after_success: #- coveralls \ No newline at end of file diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..287c729 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +testpaths = + Algorithms_tests From 57129e44da068feaa92dbb7cb0f268a787288edd Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 15:50:22 +0200 Subject: [PATCH 34/60] update travis --- .travis.yml | 63 ++++++++++++++++++++++++++--------------------------- pytest.ini | 3 --- 2 files changed, 31 insertions(+), 35 deletions(-) delete mode 100644 pytest.ini diff --git a/.travis.yml b/.travis.yml index 8ccf268..02aaa08 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,37 +22,36 @@ install: #- pip3 install coveralls script: - pytest - # - awesome_bot README.md --allow-dupe --allow-redirect - # # Dynamic Programming Tests - # - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py - # - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py - # - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py - - # # Graph Theory Tests - # - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py - # - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py - # - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py - # - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py - # - python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py - # - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py - # - python Algorithm_tests/graphtheory_tests/BFS_test.py - # - python Algorithm_tests/graphtheory_tests/DFS_test.py - - # # Math tests - # - python Algorithm_tests/other_tests/test_binarysearch.py - # - python Algorithm_tests/math_tests/intersection_test.py - # - python Algorithm_tests/math_tests/union_test.py - - # # Cryptography tests - # - python Algorithm_tests/cryptology_tests/ceasar_test.py - - # # "Other" tests - # - python Algorithm_tests/other_tests/test_medianmaintenance.py - # - python Algorithm_tests/other_tests/test_intervalscheduling.py - - # # Sorting tests - # - python Algorithm_tests/sorting_tests/test_sorting.py + - awesome_bot README.md --allow-dupe --allow-redirect + # Dynamic Programming Tests + - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py + - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py + - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py + + # Graph Theory Tests + - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py + - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py + - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py + - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py + - python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py + - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py + - python Algorithm_tests/graphtheory_tests/BFS_test.py + - python Algorithm_tests/graphtheory_tests/DFS_test.py + + # Math tests + - python Algorithm_tests/other_tests/test_binarysearch.py + - python Algorithm_tests/math_tests/intersection_test.py + - python Algorithm_tests/math_tests/union_test.py + + # Cryptography tests + - python Algorithm_tests/cryptology_tests/ceasar_test.py + + # "Other" tests + - python Algorithm_tests/other_tests/test_medianmaintenance.py + - python Algorithm_tests/other_tests/test_intervalscheduling.py + + # Sorting tests + - python Algorithm_tests/sorting_tests/test_sorting.py after_success: - #- coveralls \ No newline at end of file + #- coveralls diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 287c729..0000000 --- a/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -testpaths = - Algorithms_tests From d7954f869cf3350fbfcf5f38964c862c60735136 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 16:00:44 +0200 Subject: [PATCH 35/60] try with setup.py --- .travis.yml | 62 ++++++++++++++++++++++++++--------------------------- setup.py | 9 ++++++++ 2 files changed, 40 insertions(+), 31 deletions(-) create mode 100644 setup.py diff --git a/.travis.yml b/.travis.yml index 02aaa08..5d79802 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,37 +21,37 @@ install: - pip3 install -r requirements.txt #- pip3 install coveralls -script: - - awesome_bot README.md --allow-dupe --allow-redirect - # Dynamic Programming Tests - - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py - - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py - - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py - - # Graph Theory Tests - - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py - - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py - - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py - - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py - - python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py - - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py - - python Algorithm_tests/graphtheory_tests/BFS_test.py - - python Algorithm_tests/graphtheory_tests/DFS_test.py - - # Math tests - - python Algorithm_tests/other_tests/test_binarysearch.py - - python Algorithm_tests/math_tests/intersection_test.py - - python Algorithm_tests/math_tests/union_test.py - - # Cryptography tests - - python Algorithm_tests/cryptology_tests/ceasar_test.py - - # "Other" tests - - python Algorithm_tests/other_tests/test_medianmaintenance.py - - python Algorithm_tests/other_tests/test_intervalscheduling.py - - # Sorting tests - - python Algorithm_tests/sorting_tests/test_sorting.py +script: pytest + # - awesome_bot README.md --allow-dupe --allow-redirect + # # Dynamic Programming Tests + # - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py + # - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py + # - python Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py + # + # # Graph Theory Tests + # - python Algorithm_tests/graphtheory_tests/bellman_ford_test.py + # - python Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py + # - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py + # - python Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py + # - python Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py + # - python Algorithm_tests/graphtheory_tests/prims_algorithm_test.py + # - python Algorithm_tests/graphtheory_tests/BFS_test.py + # - python Algorithm_tests/graphtheory_tests/DFS_test.py + # + # # Math tests + # - python Algorithm_tests/other_tests/test_binarysearch.py + # - python Algorithm_tests/math_tests/intersection_test.py + # - python Algorithm_tests/math_tests/union_test.py + # + # # Cryptography tests + # - python Algorithm_tests/cryptology_tests/ceasar_test.py + # + # # "Other" tests + # - python Algorithm_tests/other_tests/test_medianmaintenance.py + # - python Algorithm_tests/other_tests/test_intervalscheduling.py + # + # # Sorting tests + # - python Algorithm_tests/sorting_tests/test_sorting.py after_success: #- coveralls diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..aa8bbb2 --- /dev/null +++ b/setup.py @@ -0,0 +1,9 @@ +from distutils.core import setup + +setup( + name='Algorithms', + packages=['Algorithm_test'], + version='0.0.7', + description='Test project to get acquainted with TravisCI', + url='https://github.com/AladdinPerzon/Algorithms-Collection-Python', +) From 8bd506dd37661beeff634f8dcc77f7b22d453613 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 16:05:23 +0200 Subject: [PATCH 36/60] try with setup.py --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5d79802..8c134e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ before_script: install: - pip3 install -r requirements.txt - #- pip3 install coveralls + - pip3 install coveralls script: pytest # - awesome_bot README.md --allow-dupe --allow-redirect @@ -54,4 +54,4 @@ script: pytest # - python Algorithm_tests/sorting_tests/test_sorting.py after_success: - #- coveralls + - coveralls From 810e6d80d689b1905eceec58a1e1a3ca3dcc382e Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 16:08:47 +0200 Subject: [PATCH 37/60] try with setup.py --- .travis.yml | 5 ++--- setup.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8c134e8..50d5752 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,10 +16,9 @@ before_install: before_script: - gem install awesome_bot - install: - pip3 install -r requirements.txt - - pip3 install coveralls + - pip3 install codecov script: pytest # - awesome_bot README.md --allow-dupe --allow-redirect @@ -54,4 +53,4 @@ script: pytest # - python Algorithm_tests/sorting_tests/test_sorting.py after_success: - - coveralls + - codecov diff --git a/setup.py b/setup.py index aa8bbb2..3a0453e 100644 --- a/setup.py +++ b/setup.py @@ -4,6 +4,6 @@ name='Algorithms', packages=['Algorithm_test'], version='0.0.7', - description='Test project to get acquainted with TravisCI', + description='Testing Algorithm Collection', url='https://github.com/AladdinPerzon/Algorithms-Collection-Python', ) From ed34afec74e454efe663d00ab36c4981322c46a9 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 16:14:15 +0200 Subject: [PATCH 38/60] try with setup.py --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 50d5752..0d40cf4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,9 +18,9 @@ before_script: install: - pip3 install -r requirements.txt - - pip3 install codecov + - pip3 install coveralls -script: pytest +script: pytest --cov=Algorithm_tests/ # - awesome_bot README.md --allow-dupe --allow-redirect # # Dynamic Programming Tests # - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py @@ -53,4 +53,4 @@ script: pytest # - python Algorithm_tests/sorting_tests/test_sorting.py after_success: - - codecov + - coveralls From ede44f8063933889551009dbbc1c889514e3b662 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 16:16:48 +0200 Subject: [PATCH 39/60] trying to fix pytest code coverage --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0d40cf4..1e205ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,8 @@ before_script: install: - pip3 install -r requirements.txt + - pip3 install pytest + - pip3 install pytest-cov - pip3 install coveralls script: pytest --cov=Algorithm_tests/ From 04e9d9ff3e927ffe25877126c9cc9b6f6672fb65 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 16:20:46 +0200 Subject: [PATCH 40/60] trying to fix pytest code coverage --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1e205ad..4b23eda 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ install: - pip3 install -r requirements.txt - pip3 install pytest - pip3 install pytest-cov - - pip3 install coveralls + - pip3 install codecov script: pytest --cov=Algorithm_tests/ # - awesome_bot README.md --allow-dupe --allow-redirect @@ -55,4 +55,4 @@ script: pytest --cov=Algorithm_tests/ # - python Algorithm_tests/sorting_tests/test_sorting.py after_success: - - coveralls + - codecov From c730e8cdbb29a414c6a0563eb278f66b9b0064fc Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 16:30:13 +0200 Subject: [PATCH 41/60] badge code cov --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 54e3c38..4db34b7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -[![Build Status](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Build Status](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) + + +[![codecov](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python/branch/master/graph/badge.svg)](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python) # Algorithms Collection Python Whenever I face an interesting problem I document the algorithm that I learned to solve it. The goals of this repository is to have clean, efficient and most importantly correct code. From 7a09b5e40f6c377b9fa26ee636bd3cb6d0825408 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 16:34:41 +0200 Subject: [PATCH 42/60] updated readme code coverage --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 4db34b7..5ffafe2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,4 @@ -[![Build Status](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) - - -[![codecov](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python/branch/master/graph/badge.svg)](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python) +[![Build Status](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![codecov](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python/branch/master/graph/badge.svg)](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python) # Algorithms Collection Python Whenever I face an interesting problem I document the algorithm that I learned to solve it. The goals of this repository is to have clean, efficient and most importantly correct code. From 61795d0524cc17390db068649bcba610f51e3518 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 16:38:17 +0200 Subject: [PATCH 43/60] update travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4b23eda..f6c8332 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ install: - pip3 install pytest-cov - pip3 install codecov -script: pytest --cov=Algorithm_tests/ +script: pytest --cov=Algorithms/ # - awesome_bot README.md --allow-dupe --allow-redirect # # Dynamic Programming Tests # - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py From c088e1ddb27b9e141da5cc5848c5123e630514ad Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 17:57:32 +0200 Subject: [PATCH 44/60] out commended parts of knapsack --- .../knapsack/knapsack_bottomup.py | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py b/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py index 423a187..41070c8 100644 --- a/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py +++ b/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py @@ -1,11 +1,13 @@ -# Bottom up implementation of Knapsack (using loops) +''' +Purpose is if having a bunch of items with a weight and corresponding value to each object. +Which collection of objects should we choose such that we maximize the value restricted to +a specific capacity of weight. Bottom up implementation of Knapsack (using loops) -# Purpose is if having a bunch of items with a weight and corresponding value to each object. -# Which collection of objects should we choose such that we maximize the value restricted to -# a specific capacity of weight +Time Complexity: O(nC), pseudo-polynomial -# Programmed by Aladdin Persson -# 2020-02-15 Initial programming +Programmed by Aladdin Persson + 2020-02-15 Initial programming +''' def find_opt(i, c, M, values, items, weights): if i <= 0 or c <= 0: @@ -46,12 +48,12 @@ def knapsack(n, C, weights, values): return M[n][C], items[::-1] -if __name__ == '__main__': - # Run small example - weights = [1,2,4,2,5] - values = [5,3,5,3,2] - n = len(weights) - capacity = 3 - total_value, items = knapsack(n, capacity, weights, values) - print('Items at the end: ' + str(items)) - print('With total value: ' + str(total_value)) +# if __name__ == '__main__': +# # Run small example +# weights = [1,2,4,2,5] +# values = [5,3,5,3,2] +# n = len(weights) +# capacity = 3 +# total_value, items = knapsack(n, capacity, weights, values) +# print('Items at the end: ' + str(items)) +# print('With total value: ' + str(total_value)) From cade5351b5d97037c67503a758a18e5457582410 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 18:05:12 +0200 Subject: [PATCH 45/60] changed small part of code and updated readme --- .../dynamic_programming/sequence_alignment.py | 45 +++++++++-------- .../weighted_interval_scheduling.py | 50 +++++++++---------- README.md | 12 ++--- 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/Algorithms/dynamic_programming/sequence_alignment.py b/Algorithms/dynamic_programming/sequence_alignment.py index 6441a8c..af5e6d7 100644 --- a/Algorithms/dynamic_programming/sequence_alignment.py +++ b/Algorithms/dynamic_programming/sequence_alignment.py @@ -1,17 +1,22 @@ -# Algorithm for solving sequence alignment -# Input strings x,y of len(x) = m, len(y) = n and find minimum number of -# edit steps and the specific steps to transform x into y. +''' +Algorithm for solving sequence alignment +Input strings x,y of len(x) = m, len(y) = n and find minimum number of +edit steps and the specific steps to transform x into y. -# Video of algorithm explanation: https://youtu.be/bQ7kRW6zo9Y -# Video of code explanation: https://youtu.be/XmyxiSc3LKg +Time Complexity: O(nm) -# Programmed by Aladdin Persson -# 2020-02-15 Initial coding -# 2020-02-16 Improved find_solution and made code cleaner -# 2020-03-13 There was an error in the code in function find_solution, -# I was working with list indexing as if it was a matrix. -# Should be working now. Extensive testing would be good. -# 2020-03-28 Cleaned up code by making SequenceAlignment into class +Video of algorithm explanation: https://youtu.be/bQ7kRW6zo9Y +Video of code explanation: https://youtu.be/XmyxiSc3LKg + +Programmed by Aladdin Persson + 2020-02-15 Initial coding + 2020-02-16 Improved find_solution and made code cleaner + 2020-03-13 There was an error in the code in function find_solution, + I was working with list indexing as if it was a matrix. + Should be working now. Extensive testing would be good. + + 2020-03-28 Cleaned up code by making SequenceAlignment into class +''' class SequenceAlignment(object): def __init__(self, x, y): @@ -63,11 +68,11 @@ def alignment(self): return (OPT[m][n], self.solution[::-1]) -if __name__ == '__main__': - x = 'TGACGTGC' - y = 'TCGACGTCA' - print('We we want to transform: ' + x + ' to: ' + y) - sqalign = SequenceAlignment(x, y) - min_edit, steps = sqalign.alignment() - print('Minimum amount of edit steps are: ' + str(min_edit)) - print('And the way to do it is: ' + str(steps)) \ No newline at end of file +# if __name__ == '__main__': +# x = 'TGACGTGC' +# y = 'TCGACGTCA' +# print('We we want to transform: ' + x + ' to: ' + y) +# sqalign = SequenceAlignment(x, y) +# min_edit, steps = sqalign.alignment() +# print('Minimum amount of edit steps are: ' + str(min_edit)) +# print('And the way to do it is: ' + str(steps)) \ No newline at end of file diff --git a/Algorithms/dynamic_programming/weighted_interval_scheduling.py b/Algorithms/dynamic_programming/weighted_interval_scheduling.py index f25b9ca..33be189 100644 --- a/Algorithms/dynamic_programming/weighted_interval_scheduling.py +++ b/Algorithms/dynamic_programming/weighted_interval_scheduling.py @@ -1,12 +1,14 @@ -# Weighted Interval Scheduling -# Explained YouTube video: https://www.youtube.com/watch?v=iIX1YvbLbvc -# Implementation walkthrough video: https://www.youtube.com/watch?v=dU-coYsd7zw +''' +Weighted Interval Scheduling +Explained YouTube video: https://www.youtube.com/watch?v=iIX1YvbLbvc +Implementation walkthrough video: https://www.youtube.com/watch?v=dU-coYsd7zw -# Programmed by Aladdin Persson -# 2020-02-13 Initial programming -# 2020-03-28 Cleaned up code by making WeightedIntervalScheduling class +Programmed by Aladdin Persson + 2020-02-13 Initial programming + 2020-03-28 Cleaned up code by making WeightedIntervalScheduling class -# Time complexity: O(nlogn) +Time complexity: O(nlogn) +''' import bisect @@ -64,21 +66,19 @@ def weighted_interval(self): return self.OPT[-1], self.solution[::-1] -if __name__ == '__main__': - # They are labeled as: (start, end, weight) - t1 = (0,3,3) - t2 = (1,4,2) - t3 = (0,5,4) - t4 = (3,6,1) - t5 = (4,7,2) - t6 = (3,9,5) - t7 = (5,10,2) - t8 = (8,10,1) - I = [t1,t2,t3,t4,t5,t6,t7,t8] - I = [(0, 50, 1), (0, 49, 1), (0, 48, 1), (15, 20, 10)] # --> [(15,20,10), (0,48,1), (0,49, 1), (0,50, 1)] - weightedinterval = WeightedIntervalScheduling(I) - max_weight, best_intervals = weightedinterval.weighted_interval() - - #max_weight = weighted_interval(I) - print('Maximum weight: ' + str(max_weight)) - print('The best items to take are: ' + str(best_intervals[::-1])) \ No newline at end of file +# Small Example +# if __name__ == '__main__': +# # They are labeled as: (start, end, weight) +# t1 = (0,3,3) +# t2 = (1,4,2) +# t3 = (0,5,4) +# t4 = (3,6,1) +# t5 = (4,7,2) +# t6 = (3,9,5) +# t7 = (5,10,2) +# t8 = (8,10,1) +# I = [t1,t2,t3,t4,t5,t6,t7,t8] +# weightedinterval = WeightedIntervalScheduling(I) +# max_weight, best_intervals = weightedinterval.weighted_interval() +# print('Maximum weight: ' + str(max_weight)) +# print('The best items to take are: ' + str(best_intervals)) \ No newline at end of file diff --git a/README.md b/README.md index 5ffafe2..aa6016b 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,14 @@ Whenever I face an interesting problem I document the algorithm that I learned t * :white_check_mark: [:movie_camera:](https://youtu.be/dU-coYsd7zw)[Weighted Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/weighted_interval_scheduling.py) **- O(nlog(n))** # Graph theory -* :white_check_mark: [Kahns Topological Sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kahns-toposort/kahns.py) **- O(n + m)** -* :white_check_mark: [Bellman-Ford Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/bellman-ford/bellman_ford.py) **-O(mn)** +* :white_check_mark: [Kahns Topological Sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py) **- O(n + m)** +* :white_check_mark: [Bellman-Ford Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/bellman-ford/bellman_ford.py) **- O(mn)** * :small_red_triangle: [Floyd-Warshall Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py) **- O(n3)** -* :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/djikstra.py) **- Naive implementation** -* :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/heapdijkstra.py) **O(mlog(n)) - Heap implementation** +* :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/dijkstra.py) **- Naive implementation** +* :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/heapdijkstra.py) **- O(mlog(n)) - Heap implementation** * :small_red_triangle: [Karger's Minimum cut](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kargers/kargermincut.py) -* :small_red_triangle: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prims_algorithm.py) **- O(mn) Naive implementation** -* :white_check_mark: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/primheap.py) **- O(mlog(n)) Heap implementation** +* :small_red_triangle: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prim_naive.py) **- O(mn) Naive implementation** +* :white_check_mark: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prim_heap.py) **- O(mlog(n)) Heap implementation** * :small_red_triangle: [Kruskal's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal.py) **- O(mn) implementation** * :white_check_mark: [Kruskal's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal_unionfind.py) **- O(mlog(n))** * :white_check_mark: [Breadth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py) **- O(n + m) - Queue Implementation** From a94e68b5745a3ed8fc25fcd39c57f631c0e917f3 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 18:07:15 +0200 Subject: [PATCH 46/60] updated readme and travis file --- .travis.yml | 6 ++++-- README.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f6c8332..4543c19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,8 +22,10 @@ install: - pip3 install pytest-cov - pip3 install codecov -script: pytest --cov=Algorithms/ - # - awesome_bot README.md --allow-dupe --allow-redirect +script: + #- awesome_bot README.md --allow-dupe --allow-redirect + - pytest --cov=Algorithms/ + # # Dynamic Programming Tests # - python Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py # - python Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py diff --git a/README.md b/README.md index aa6016b..f80c45f 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Whenever I face an interesting problem I document the algorithm that I learned t * :white_check_mark: [Maintaining Median](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/median_maintenance.py) **- O(nlog(n))** * :small_red_triangle: [Huffman Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/Huffman/Huffman.py) * :white_check_mark: [:movie_camera:](https://youtu.be/SmPxC8m0yIY)[Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/interval_scheduling.py) **- O(nlog(n))** -* :white_check_mark: [Binary Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/search/binarysearch.py) **- O(log(n))** +* :white_check_mark: [Binary Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/binarysearch.py) **- O(log(n))** # Sorting algorithms * :white_check_mark: [Bubble sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/bubblesort.py) **- O(n2)** From ec1795f433105de4435994e95ef131e5774d7ad2 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 18:09:13 +0200 Subject: [PATCH 47/60] changed travis file, made check deadlinks --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4543c19..74caa90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ install: - pip3 install codecov script: - #- awesome_bot README.md --allow-dupe --allow-redirect + - awesome_bot README.md --allow-dupe --allow-redirect - pytest --cov=Algorithms/ # # Dynamic Programming Tests From 7a55a4f7920fa07e569a43d00e438a248ca94f19 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 18:22:57 +0200 Subject: [PATCH 48/60] Updated and cleaned up code --- .../ceasar_shift_cipher.py | 20 +++---- .../graphtheory/bellman-ford/bellman_ford.py | 41 +++++--------- .../BFS_queue_iterative.py | 46 ++++++++-------- .../depth-first-search/DFS_recursive.py | 53 ++++++------------- .../depth-first-search/DFS_stack_iterative.py | 36 +++++-------- README.md | 2 +- 6 files changed, 77 insertions(+), 121 deletions(-) diff --git a/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py b/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py index 06efa87..69513ff 100644 --- a/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py +++ b/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py @@ -41,13 +41,13 @@ def decrypt(cipher, shift=3): return decrypted -def main(): - message = 'attackatnoon' - cipher = encrypt(message, shift=3) - decrypted = decrypt(cipher, shift=3) - - print('Original message: ' + message) - print('Encrypted message: ' + cipher) - print('Decrypted message: ' + decrypted) - -main() \ No newline at end of file +# def main(): +# message = 'attackatnoon' +# cipher = encrypt(message, shift=3) +# decrypted = decrypt(cipher, shift=3) +# +# print('Original message: ' + message) +# print('Encrypted message: ' + cipher) +# print('Decrypted message: ' + decrypted) +# +# main() \ No newline at end of file diff --git a/Algorithms/graphtheory/bellman-ford/bellman_ford.py b/Algorithms/graphtheory/bellman-ford/bellman_ford.py index c4ae5a9..0868eba 100644 --- a/Algorithms/graphtheory/bellman-ford/bellman_ford.py +++ b/Algorithms/graphtheory/bellman-ford/bellman_ford.py @@ -9,23 +9,12 @@ 2019-03-04 Initial programming ''' -def make_graph(file): - try: - f = open(file, 'r') - except IOError: - raise IOError("File does not exist!") - - line_list = f.readlines() - - G = {int(line.split()[0]): {(int(tup.split(',')[0])): int(tup.split(',')[1]) - for tup in line.split()[1:] if tup} for line in line_list if line} - - f.close() - - return G - - def bellman_ford(G, start): + ''' + :param G: {from_node1: {to_node1, cost1, to_node2, cost2}, from_node2: {etc}} + :param start: node to start from + ''' + if len(G) == 0: raise ValueError("There should be something in the graph") @@ -56,14 +45,12 @@ def bellman_ford(G, start): return shortest_distance, predecessor -if __name__ == '__main__': - # G = make_graph('data.txt') - - G = {1: {2: -10, 3: 20}, - 2: {4: 40}, - 3: {4: 5}, - 4: {}} - - print(f'Current graph is: {G}') - shortest, predecessor = bellman_ford(G, 1) - print(shortest) \ No newline at end of file +# if __name__ == '__main__': +# G = {1: {2: -10, 3: 20}, +# 2: {4: 40}, +# 3: {4: 5}, +# 4: {}} +# +# print(f'Current graph is: {G}') +# shortest, predecessor = bellman_ford(G, 1) +# print(shortest) \ No newline at end of file diff --git a/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py b/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py index c5344be..25c2c32 100644 --- a/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py +++ b/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py @@ -1,18 +1,18 @@ -from collections import deque - -def load_graph(file='exgraph.txt'): - data = open(file, 'r') - G = {} - - for line in data: - lst = [int(x) for x in line.split()] - G[lst[0]] = lst[1:] +''' +Programmed by Aladdin Persson + 2019-02-17 Initial programming + 2020-03-29 Cleaned up code, removed load graph, I think a small example is sufficient + and instead only have the BFS function. +''' - num_nodes = len(G) - - return G, num_nodes +from collections import deque def BFS(G, start_node=1): + ''' + :param G: Graph with G = {from_node1:[to_node1, to_node2], from_node2: [to_node,] etc} + :param start_node: starting node to run BFS from + :return: returns visited boolean array and path in which order it visited them + ''' visited = [False for i in range(1,len(G)+1)] Q = deque() @@ -33,17 +33,13 @@ def BFS(G, start_node=1): return visited, path +# Small Example Run +# if __name__ == '__main__': +# G = {1:[2,3], 2:[1,4], 3:[1,4],4:[]} +# visited, path = BFS(G) +# +# if all(visited) == True: +# print("Return: This graph is connected!") - -if __name__ == '__main__': - G, num_nodes = load_graph() - # G = {1:[2,3], 2:[1,4], 3:[1,4],4:[]} - - visited, path = BFS(G) - - if all(visited) == True: - print("Return: This graph is connected!") - else: - print("Not all nodes were reachable, i.e the graph is not connected.") - - +# else: +# print("Not all nodes were reachable, i.e the graph is not connected.") \ No newline at end of file diff --git a/Algorithms/graphtheory/depth-first-search/DFS_recursive.py b/Algorithms/graphtheory/depth-first-search/DFS_recursive.py index a04116c..2babc14 100644 --- a/Algorithms/graphtheory/depth-first-search/DFS_recursive.py +++ b/Algorithms/graphtheory/depth-first-search/DFS_recursive.py @@ -4,50 +4,31 @@ # Programmed by Aladdin Persson # 2019-02-16 Initial programming -# Improvements: -# * Check implementation with stack/queue - -def load_graph(file='exgraph.txt'): - data = open(file, 'r') - G = {} - - for line in data: - lst = [int(x) for x in line.split()] - G[lst[0]] = lst[1:] - - num_nodes = len(G) - - return G, num_nodes - - def DFS(G, curr_node, visited): + ''' + :param G: G = {from_node1:[to_node1, to_node2], from_node2: [to_node,] etc} + :param curr_node: Node currently at, run from beginning this is the starting node + :param visited: since it is recursive, visited is updated and needs to be sent in on recursive call + :return: visited is initialized outside of DFS and updates this boolean array with which nodes has been visited + ''' if visited[curr_node - 1]: return visited[curr_node-1] = True - # G is a dictionary neighbours = G[curr_node] for next_node in neighbours: DFS(G, next_node, visited) -if __name__ == '__main__': - print('Loading graph and print:') - - try: - G, num_nodes = load_graph() - print(G) - - except TypeError: - raise("Error loading graph.") - - # G = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2, 5], 5: [4]} - - visited = [False for i in range(1, len(G) + 1)] - start_node = 1 - - DFS(G, start_node, visited) - - if any(visited) == False: - print("Result: This graph is connected!") \ No newline at end of file +# Small Eaxmple +# if __name__ == '__main__': +# G = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2, 5], 5: [4]} +# +# visited = [False for i in range(1, len(G) + 1)] +# start_node = 1 +# +# DFS(G, start_node, visited) +# +# if any(visited) == False: +# print("Result: This graph is connected!") \ No newline at end of file diff --git a/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py b/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py index bc226ee..b642772 100644 --- a/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py +++ b/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py @@ -7,20 +7,12 @@ 2020-03-29 Cleaned up code, made test cases ''' - -def load_graph(file='exgraph.txt'): - data = open(file, 'r') - G = {} - - for line in data: - lst = [int(x) for x in line.split()] - G[lst[0]] = lst[1:] - - num_nodes = len(G) - - return G, num_nodes - def DFS(G, start_node): + ''' + :param G: Graph with G = {from_node1:[to_node1, to_node2], from_node2: [to_node,] etc} + :param start_node: starting node to run BFS from + :return: returns visited boolean array and path in which order it visited them + ''' visited = [False for i in range(1, len(G) + 1)] path = [start_node] stack = [] @@ -38,12 +30,12 @@ def DFS(G, start_node): return visited, path -if __name__ == '__main__': - G, num_nodes = load_graph() - start_node = 1 - visited = DFS(G, start_node) - - if all(visited) == True: - print("Return: This graph is connected!") - else: - print("Not all nodes were reachable, i.e the graph is not connected.") \ No newline at end of file +# if __name__ == '__main__': +# G = {1: [2, 3], 2: [1, 4], 3: [1, 4], 4: []} +# start_node = 1 +# visited = DFS(G, start_node) +# +# if all(visited) == True: +# print("Return: This graph is connected!") +# else: +# print("Not all nodes were reachable, i.e the graph is not connected.") \ No newline at end of file diff --git a/README.md b/README.md index f80c45f..872334c 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Whenever I face an interesting problem I document the algorithm that I learned t # Sorting algorithms * :white_check_mark: [Bubble sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/bubblesort.py) **- O(n2)** -* :small_red_triangle: [Hope sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/hopesort.py) **- O(1), hopefully ** +* :small_red_triangle: [Hope sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/hopesort.py) **- O(1), hopefully** * :white_check_mark: [Insertion sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/insertionsort.py) **- O(n2)** * :white_check_mark: [Selection sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/selectionsort.py) **- O(n2)** * :white_check_mark: [Merge sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/mergesort.py) **- O(nlog(n))** From 3ba27efad3526ef5e36736f35250f83e459ca225 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 18:23:30 +0200 Subject: [PATCH 49/60] updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 872334c..6ed6c6b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![codecov](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python/branch/master/graph/badge.svg)](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python) +[![Build Status](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![codecov](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python/branch/master/graph/badge.svg)](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python) # Algorithms Collection Python Whenever I face an interesting problem I document the algorithm that I learned to solve it. The goals of this repository is to have clean, efficient and most importantly correct code. From bd1b468e0536b4dde3d8d72d0dac1247e9e69b89 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 18:27:57 +0200 Subject: [PATCH 50/60] updated tests --- .../graphtheory_tests/bellman_ford_test.py | 9 +------ Algorithms/graphtheory/dijkstra/dijkstra.py | 26 +++++++------------ 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/Algorithm_tests/graphtheory_tests/bellman_ford_test.py b/Algorithm_tests/graphtheory_tests/bellman_ford_test.py index fcec78c..a6d8358 100644 --- a/Algorithm_tests/graphtheory_tests/bellman_ford_test.py +++ b/Algorithm_tests/graphtheory_tests/bellman_ford_test.py @@ -9,16 +9,9 @@ # If run from local: #sys.path.append('../../Algorithms/graphtheory/bellman-ford') -from bellman_ford import bellman_ford, make_graph +from bellman_ford import bellman_ford class test_BellmanFord(unittest.TestCase): - - def test_loadgraph(self): - correct_graph = {1: {2: 5, 3: 10}, 2: {4: -5}, 3: {4: 15}} - graph = make_graph('Algorithm_tests/graphtheory_tests/test_graph.txt') - - self.assertEqual(graph, correct_graph) - def test_loadmissingfile(self): with self.assertRaises(IOError): graph = make_graph('this_file_doesnt_exist.txt') diff --git a/Algorithms/graphtheory/dijkstra/dijkstra.py b/Algorithms/graphtheory/dijkstra/dijkstra.py index c778bfa..ad2f0e8 100644 --- a/Algorithms/graphtheory/dijkstra/dijkstra.py +++ b/Algorithms/graphtheory/dijkstra/dijkstra.py @@ -1,26 +1,20 @@ ''' -Dijkstra's algorithm for finding the shortest path in a graph +Dijkstra's algorithm for finding the shortest path in a graph, this implementation +is a naive implementation, check my Heap implementation for a more efficient algorithm Programmed by Aladdin Persson 2019-01-28 Initial programming 2020-03-28 Cleaned up code ''' -def make_graph(file): - try: - f = open(file, 'r') - except IOError: - raise("File does not exist!") - - line_list = f.readlines() - - G = {int(line.split()[0]): {(int(tup.split(',')[0])): int(tup.split(',')[1]) - for tup in line.split()[1:] if tup} for line in line_list if line} - - f.close() - return G - def dijkstra(G, start, end): + ''' + :param G: {from_node1: {to_node1:cost1, to_node2:cost2}, from_node2 : {.., etc.}, ...} + :param start: starting node + :param end: ending node where we want to find path to + :return: path from starting node to end node and the cost to get between them + ''' + if start not in G or end not in G: return [], float('inf') @@ -70,8 +64,6 @@ def dijkstra(G, start, end): if __name__ == '__main__': - #G = make_graph('dijkstraData.txt') - G = {1:{2:10, 3:20}, 2:{4:40}, 3:{4:5}, From c72b5e8c759eccbf75903126cd5ca3b63d9be649 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 18:30:36 +0200 Subject: [PATCH 51/60] fixed bellman ford test --- Algorithm_tests/graphtheory_tests/bellman_ford_test.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Algorithm_tests/graphtheory_tests/bellman_ford_test.py b/Algorithm_tests/graphtheory_tests/bellman_ford_test.py index a6d8358..36b1a4b 100644 --- a/Algorithm_tests/graphtheory_tests/bellman_ford_test.py +++ b/Algorithm_tests/graphtheory_tests/bellman_ford_test.py @@ -12,10 +12,6 @@ from bellman_ford import bellman_ford class test_BellmanFord(unittest.TestCase): - def test_loadmissingfile(self): - with self.assertRaises(IOError): - graph = make_graph('this_file_doesnt_exist.txt') - def test_negativecycle(self): # Because of negative cycles, we shall denote the shortest path for these # as -infinity. From 3356a727e209b14322c3ae7e20431c76bf9c9f1c Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 18:33:06 +0200 Subject: [PATCH 52/60] commented mergesort --- Algorithms/sorting/mergesort.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Algorithms/sorting/mergesort.py b/Algorithms/sorting/mergesort.py index 3387701..4989f6d 100644 --- a/Algorithms/sorting/mergesort.py +++ b/Algorithms/sorting/mergesort.py @@ -9,7 +9,6 @@ def merge_sort(array): return merge(left, right) - def merge(left, right): result = [] left_pointer = right_pointer = 0 @@ -28,9 +27,9 @@ def merge(left, right): return result -if __name__ == "__main__": - array = [5, 4, 3, 2, 1] - print(array) - - result = merge_sort(array) - print(result) +# if __name__ == "__main__": +# array = [5, 4, 3, 2, 1] +# print(array) +# +# result = merge_sort(array) +# print(result) From d8d297ae4b2b0a2c89b41c2a004a9bb9d0fb2fb9 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 19:55:25 +0200 Subject: [PATCH 53/60] fixed sorting tests --- Algorithm_tests/sorting_tests/test_sorting.py | 12 +++- Algorithms/sorting/quicksort.py | 57 +------------------ 2 files changed, 12 insertions(+), 57 deletions(-) diff --git a/Algorithm_tests/sorting_tests/test_sorting.py b/Algorithm_tests/sorting_tests/test_sorting.py index 8d2fccf..8495b93 100644 --- a/Algorithm_tests/sorting_tests/test_sorting.py +++ b/Algorithm_tests/sorting_tests/test_sorting.py @@ -12,7 +12,7 @@ from bubblesort import bubblesort from insertionsort import insertionsort from mergesort import merge_sort, merge -from quicksort import quicksort_firstpivot +from quicksort import quicksort_firstpivot, quicksort_lastpivot from randomized_quicksort import quicksort_randomized from selectionsort import selectionsort @@ -77,6 +77,16 @@ def test_quicksort(self): self.assertEqual(quicksort_firstpivot(L6), L6_sorted) self.assertEqual(quicksort_firstpivot(L7), L7_sorted) + self.assertEqual(quicksort_lastpivot(L1), L1_sorted) + self.assertEqual(quicksort_lastpivot(L2), L2_sorted) + self.assertEqual(quicksort_lastpivot(L3), L3_sorted) + self.assertEqual(quicksort_lastpivot(L4), L4_sorted) + self.assertEqual(quicksort_lastpivot(L5), L5_sorted) + self.assertEqual(quicksort_lastpivot(L6), L6_sorted) + self.assertEqual(quicksort_lastpivot(L7), L7_sorted) + + + def test_selectionsort(self): self.assertEqual(selectionsort(L1), L1_sorted) self.assertEqual(selectionsort(L2), L2_sorted) diff --git a/Algorithms/sorting/quicksort.py b/Algorithms/sorting/quicksort.py index 722d18e..8fd3110 100644 --- a/Algorithms/sorting/quicksort.py +++ b/Algorithms/sorting/quicksort.py @@ -51,59 +51,4 @@ def quicksort_lastpivot(x): left.append(x[i]) result = left + right - return result - -def find_median(x): - # this is horrible. - - if len(x) % 2 == 0: - middle_idx = len(x) // 2 - 1 - if len(x) % 2 != 0: - middle_idx = len(x) // 2 - - a = x[0] - b = x[middle_idx] - c = x[-1] - - if a > b: - if a < c: - median = 0 - elif b > c: - median = middle_idx - else: - median = len(x) - 1 - else: - if a > c: - median = 0 - elif b < c: - median = middle_idx - else: - median = len(x) - 1 - - return median - -def quicksort_median(x): - global count_comparisons - - if len(x) <= 1: - return x - - k = find_median(x) - x[0], x[k] = x[k], x[0] - pivot = x[0] - - count_comparisons += len(x) - 1 - - i = 0 - - for j in range(1, len(x)): - if x[j] < pivot: - x[j], x[i+1] = x[i+1], x[j] - i += 1 - - x[0], x[i] = x[i], x[0] - left = quicksort_median(x[:i]) - right = quicksort_median(x[i+1:]) - left.append(x[i]) - result = left + right - return result + return result \ No newline at end of file From 192209a22d8fc5406c8b6c3d3a8f5615ec4d7b3e Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sun, 29 Mar 2020 19:58:20 +0200 Subject: [PATCH 54/60] fixed quicksort --- Algorithms/sorting/quicksort.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Algorithms/sorting/quicksort.py b/Algorithms/sorting/quicksort.py index 8fd3110..c966db9 100644 --- a/Algorithms/sorting/quicksort.py +++ b/Algorithms/sorting/quicksort.py @@ -1,15 +1,11 @@ # Quicksort with pivot always using first index as pivot def quicksort_firstpivot(L): - # global count_comparisons - if len(L) <= 1: return L pivot = L[0] - # count_comparisons += len(x) - 1 - i = 0 for j in range(1, len(L)): @@ -27,16 +23,12 @@ def quicksort_firstpivot(L): # Quicksort with pivot always using last index as pivot def quicksort_lastpivot(x): - global count_comparisons - if len(x) <= 1: return x x[0], x[-1] = x[-1], x[0] pivot = x[0] - count_comparisons += len(x) - 1 - i = 0 for j in range(1, len(x)): From 94f21ffc898bba54627b7124c5a90c1500723ab0 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 30 May 2020 09:49:21 +0200 Subject: [PATCH 55/60] rerun tests --- Algorithm_tests/graphtheory_tests/bellman_ford_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Algorithm_tests/graphtheory_tests/bellman_ford_test.py b/Algorithm_tests/graphtheory_tests/bellman_ford_test.py index 36b1a4b..c9aea86 100644 --- a/Algorithm_tests/graphtheory_tests/bellman_ford_test.py +++ b/Algorithm_tests/graphtheory_tests/bellman_ford_test.py @@ -36,7 +36,7 @@ def test_shortestdist(self): self.assertEqual(shortest_dist[3], 5) self.assertEqual(shortest_dist[4], 35) - def test_emptygraph(self): + def test_run_emptygraph(self): G = {} start_node = 1 From 61ec61063981196b825793ff4094b3d368224145 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Mon, 8 Jun 2020 12:28:26 +0200 Subject: [PATCH 56/60] format code using black --- .../cryptology_tests/ceasar_test.py | 19 +++-- .../knapsack_tests/knapsack_bottomup_test.py | 36 +++++++--- .../sequence_alignment_test.py | 60 ++++++++-------- .../weighted_interval_scheduling_test.py | 22 +++--- Algorithm_tests/graphtheory_tests/BFS_test.py | 36 ++++++---- Algorithm_tests/graphtheory_tests/DFS_test.py | 28 ++++---- .../Djikstra/djikstra_heap_test.py | 16 +++-- .../Djikstra/djikstra_naive_test.py | 15 ++-- .../graphtheory_tests/bellman_ford_test.py | 24 ++++--- .../kahn_topological_ordering_test.py | 37 ++++++---- .../kruskal_unionfind_test.py | 51 ++++++++----- .../graphtheory_tests/prims_algorithm_test.py | 41 +++++++---- .../math_tests/intersection_test.py | 27 ++++--- Algorithm_tests/math_tests/union_test.py | 34 ++++----- .../other_tests/test_binarysearch.py | 46 +++++++----- .../other_tests/test_intervalscheduling.py | 24 +++---- .../other_tests/test_medianmaintenance.py | 9 ++- Algorithm_tests/sorting_tests/test_sorting.py | 34 +++++---- Algorithms/cryptology/RSA_algorithm/RSA.py | 71 +++++++++++-------- .../cryptology/RSA_algorithm/euclid_gcd.py | 16 +++-- .../ceasar_shift_cipher.py | 15 ++-- .../cryptology/hill_cipher/hill_cipher.py | 61 +++++++++------- .../cryptology/one_time_pad/one_time_pad.py | 49 +++++++------ .../cryptology/vigenere_cipher/vigenere.py | 33 +++++---- .../knapsack/knapsack_bottomup.py | 33 +++++---- .../knapsack_memoization_recursive_topdown.py | 22 +++--- .../knapsack/knapsack_naive_recursive.py | 21 +++--- .../longest_increasing_subsequence.py | 16 ++--- .../dynamic_programming/sequence_alignment.py | 46 +++++++----- .../weighted_interval_scheduling.py | 14 ++-- .../graphtheory/bellman-ford/bellman_ford.py | 16 +++-- .../BFS_queue_iterative.py | 18 ++--- .../depth-first-search/DFS_recursive.py | 10 +-- .../depth-first-search/DFS_stack_iterative.py | 18 ++--- Algorithms/graphtheory/dijkstra/dijkstra.py | 31 ++++---- .../graphtheory/dijkstra/heapdijkstra.py | 40 ++++++----- .../floyd-warshall/floyd-warshall.py | 42 ++++++++--- .../kahn_topological_ordering.py | 25 ++++--- .../graphtheory/kargers/kargermincut.py | 6 +- Algorithms/graphtheory/kruskal/kruskal.py | 27 +++---- .../graphtheory/kruskal/kruskal_unionfind.py | 24 ++++--- Algorithms/graphtheory/prims/prim_heap.py | 32 +++++---- Algorithms/graphtheory/prims/prim_naive.py | 16 ++--- Algorithms/math/euclid_gcd/euclid_gcd.py | 10 +-- .../euclid_gcd.py | 17 +++-- .../intersection_of_two_sets.py | 26 +++---- Algorithms/math/karatsuba/karatsuba.py | 32 +++++---- Algorithms/math/pollard_p1/pollard_p1.py | 20 +++--- .../prime_factorization/primefactorization.py | 24 ++++--- .../sieve_eratosthenes.py | 14 ++-- .../union_of_two_sets/union_of_two_sets.py | 26 +++---- Algorithms/numerical_methods/bisection.py | 36 +++++----- Algorithms/numerical_methods/fixpoint.py | 8 ++- Algorithms/other/Huffman/Huffman.py | 48 +++++++------ Algorithms/other/Kadanes_algorithm.py | 15 ++-- Algorithms/other/binarysearch.py | 25 ++++--- Algorithms/other/counting_inversions.py | 8 ++- Algorithms/other/interval_scheduling.py | 8 ++- Algorithms/other/median_maintenance.py | 15 ++-- Algorithms/sorting/bubblesort.py | 16 +++-- Algorithms/sorting/hopesort.py | 12 ++-- Algorithms/sorting/insertionsort.py | 13 ++-- Algorithms/sorting/mergesort.py | 4 +- Algorithms/sorting/quicksort.py | 12 ++-- Algorithms/sorting/randomized_quicksort.py | 18 ++--- Algorithms/sorting/selectionsort.py | 17 ++--- setup.py | 10 +-- 67 files changed, 972 insertions(+), 723 deletions(-) diff --git a/Algorithm_tests/cryptology_tests/ceasar_test.py b/Algorithm_tests/cryptology_tests/ceasar_test.py index 0956a50..bffff78 100644 --- a/Algorithm_tests/cryptology_tests/ceasar_test.py +++ b/Algorithm_tests/cryptology_tests/ceasar_test.py @@ -4,27 +4,25 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/cryptology/ceasar_shifting_cipher') +sys.path.append("Algorithms/cryptology/ceasar_shifting_cipher") # If run from local: -#sys.path.append('../../Algorithms/cryptology/ceasar_shifting_cipher') +# sys.path.append('../../Algorithms/cryptology/ceasar_shifting_cipher') from ceasar_shift_cipher import encrypt, decrypt # Note this is not robust.. but im trying to make it a habit to make some tests. # Some are better than nothing. But these are not complete at all. class test_ceasar_cipher(unittest.TestCase): - def setUp(self): # test cases we wish to run - self.message1 = 'abc' + self.message1 = "abc" self.shift1 = 3 - self.correct_encrypt1 = 'def' + self.correct_encrypt1 = "def" - self.message2 = 'xyz ' + self.message2 = "xyz " self.shift2 = 1 - self.correct_encrypt2 = 'yz a' - + self.correct_encrypt2 = "yz a" def test_encryption_message1(self): encrypted_message1 = encrypt(self.message1, self.shift1) @@ -42,6 +40,7 @@ def test_decryption_message2(self): decrypted_message2 = decrypt(self.correct_encrypt2, self.shift2) self.assertEqual(decrypted_message2, self.message2) -if __name__ == '__main__': + +if __name__ == "__main__": print("Running ceasar cipher tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py b/Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py index f286196..79a415e 100644 --- a/Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py +++ b/Algorithm_tests/dynamic_programming_tests/knapsack_tests/knapsack_bottomup_test.py @@ -3,12 +3,13 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/dynamic_programming/knapsack') +sys.path.append("Algorithms/dynamic_programming/knapsack") # If run from local: -#sys.path.append('../../../Algorithms/dynamic_programming/knapsack/') +# sys.path.append('../../../Algorithms/dynamic_programming/knapsack/') from knapsack_bottomup import knapsack + class test_KnapSack(unittest.TestCase): def setUp(self): self.weights1, self.values1, self.capacity1 = [], [], 100 @@ -23,7 +24,11 @@ def setUp(self): self.n3 = len(self.weights2) self.correctvalue3, self.correctitems3 = 0, [] - self.weights4, self.values4, self.capacity4 = [1, 2, 4, 2, 5], [5, 3, 5, 3, 2], 5 + self.weights4, self.values4, self.capacity4 = ( + [1, 2, 4, 2, 5], + [5, 3, 5, 3, 2], + 5, + ) self.n4 = len(self.weights4) self.correctvalue4, self.correctitems4 = 11, [0, 1, 3] @@ -32,30 +37,41 @@ def setUp(self): self.correctvalue5, self.correctitems5 = 0, [] def test_noitems(self): - total_value, items = knapsack(self.n1, self.capacity1, self.weights1, self.values1) + total_value, items = knapsack( + self.n1, self.capacity1, self.weights1, self.values1 + ) self.assertEqual(self.correctvalue1, total_value) self.assertEqual(self.correctitems1, items) def test_singleitem_value(self): - total_value, items = knapsack(self.n2, self.capacity2, self.weights2, self.values2) + total_value, items = knapsack( + self.n2, self.capacity2, self.weights2, self.values2 + ) self.assertEqual(self.correctvalue2, total_value) self.assertEqual(self.correctitems2, items) def test_negativevalues(self): - total_value, items = knapsack(self.n3, self.capacity3, self.weights3, self.values3) + total_value, items = knapsack( + self.n3, self.capacity3, self.weights3, self.values3 + ) self.assertEqual(self.correctvalue3, total_value) self.assertEqual(self.correctitems3, items) def test_simpleexample(self): - total_value, items = knapsack(self.n4, self.capacity4, self.weights4, self.values4) + total_value, items = knapsack( + self.n4, self.capacity4, self.weights4, self.values4 + ) self.assertEqual(self.correctvalue4, total_value) self.assertEqual(self.correctitems4, items) def test_weight_too_heavy(self): - total_value, items = knapsack(self.n5, self.capacity5, self.weights5, self.values5) + total_value, items = knapsack( + self.n5, self.capacity5, self.weights5, self.values5 + ) self.assertEqual(self.correctvalue5, total_value) self.assertEqual(self.correctitems5, items) -if __name__ == '__main__': + +if __name__ == "__main__": print("Running Knapsack tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py b/Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py index 6e0165b..7e58b5b 100644 --- a/Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py +++ b/Algorithm_tests/dynamic_programming_tests/sequence_alignment/sequence_alignment_test.py @@ -3,57 +3,58 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/dynamic_programming/') +sys.path.append("Algorithms/dynamic_programming/") # If run from local: -#sys.path.append('../../../Algorithms/dynamic_programming/') +# sys.path.append('../../../Algorithms/dynamic_programming/') from sequence_alignment import SequenceAlignment + class test_sequence_alignment(unittest.TestCase): def setUp(self): - self.x1 = 'ABC' - self.y1 = 'ADC' + self.x1 = "ABC" + self.y1 = "ADC" self.correct_editstep1 = 1 - self.x2 = 'AB' - self.y2 = 'A' + self.x2 = "AB" + self.y2 = "A" self.correct_editstep2 = 1 - self.x3 = 'A' - self.y3 = '' + self.x3 = "A" + self.y3 = "" self.correct_editstep3 = 1 - self.x4 = 'ABC' - self.y4 = 'ABCDE' + self.x4 = "ABC" + self.y4 = "ABCDE" self.correct_editstep4 = 2 - self.x5 = 'ABCKL' - self.y5 = 'ADCE' + self.x5 = "ABCKL" + self.y5 = "ADCE" self.correct_editstep5 = 3 - self.x6 = 'A'*10 - self.y6 = '' + self.x6 = "A" * 10 + self.y6 = "" self.correct_editstep6 = 10 - self.x7 = '' - self.y7 = 'A' * 10 + self.x7 = "" + self.y7 = "A" * 10 self.correct_editstep7 = 10 - self.x8 = 'TGACGTGC' - self.y8 = 'TCGACGTCA' + self.x8 = "TGACGTGC" + self.y8 = "TCGACGTCA" self.correct_editstep8 = 3 - self.x9 = 'XYZ' - self.y9 = 'XKZ' - self.correct_solution9 = ['align_X', 'align_K', 'align_Z'] + self.x9 = "XYZ" + self.y9 = "XKZ" + self.correct_solution9 = ["align_X", "align_K", "align_Z"] - self.x10 = 'XX' - self.y10 = '' - self.correct_solution10 = ['remove_X', 'remove_X'] + self.x10 = "XX" + self.y10 = "" + self.correct_solution10 = ["remove_X", "remove_X"] - self.x11 = '' - self.y11 = 'XX' - self.correct_solution11 = ['insert_X', 'insert_X'] + self.x11 = "" + self.y11 = "XX" + self.correct_solution11 = ["insert_X", "insert_X"] def test_simplecase(self): sequence_align = SequenceAlignment(self.x1, self.y1) @@ -110,6 +111,7 @@ def test_findsolution_empty_x(self): _, solution = sequence_align.alignment() self.assertEqual(self.correct_solution11, solution) -if __name__ == '__main__': + +if __name__ == "__main__": print("Running Sequence Alignment tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py b/Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py index d413cc1..d384097 100644 --- a/Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py +++ b/Algorithm_tests/dynamic_programming_tests/weighted_interval_scheduling/weighted_interval_scheduling_test.py @@ -3,25 +3,26 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/dynamic_programming/') +sys.path.append("Algorithms/dynamic_programming/") # If run from local: -#sys.path.append('../../../Algorithms/dynamic_programming/') +# sys.path.append('../../../Algorithms/dynamic_programming/') from weighted_interval_scheduling import WeightedIntervalScheduling + class test_weighted_interval_scheduling(unittest.TestCase): def setUp(self): self.I1 = [] self.correct_maxweight1 = 0 self.correct_intervals1 = [] - self.I2 = [(0,3,10)] + self.I2 = [(0, 3, 10)] self.correct_maxweight2 = 10 - self.correct_intervals2 = [(0,3,10)] + self.correct_intervals2 = [(0, 3, 10)] - self.I3 = [(0,3,5), (2,5,15), (4, 6, 5)] + self.I3 = [(0, 3, 5), (2, 5, 15), (4, 6, 5)] self.correct_maxweight3 = 15 - self.correct_intervals3 = [(2,5,15)] + self.correct_intervals3 = [(2, 5, 15)] self.I4 = [(0, 3, 5), (3, 5, 15), (5, 7, 5)] self.correct_maxweight4 = 25 @@ -29,9 +30,9 @@ def setUp(self): self.I5 = [(0, 3, 5), (3, 5, -100), (5, 7, -50)] self.correct_maxweight5 = 5 - self.correct_intervals5 = [(0,3,5)] + self.correct_intervals5 = [(0, 3, 5)] - self.I6 = [(0, 50, 1), (0, 49, 1), (0, 48, 1), (15,20,10)] + self.I6 = [(0, 50, 1), (0, 49, 1), (0, 48, 1), (15, 20, 10)] self.correct_maxweight6 = 10 self.correct_intervals6 = [(15, 20, 10)] @@ -101,6 +102,7 @@ def test_earliest_finish_time_not_best(self): self.assertEqual(self.correct_maxweight9, max_weight) self.assertEqual(self.correct_intervals9, best_intervals) -if __name__ == '__main__': + +if __name__ == "__main__": print("Running Weighted Interval Scheduling tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/graphtheory_tests/BFS_test.py b/Algorithm_tests/graphtheory_tests/BFS_test.py index 09f4aff..3495a97 100644 --- a/Algorithm_tests/graphtheory_tests/BFS_test.py +++ b/Algorithm_tests/graphtheory_tests/BFS_test.py @@ -5,30 +5,38 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/graphtheory/breadth-first-search/') +sys.path.append("Algorithms/graphtheory/breadth-first-search/") # If run from local: -#sys.path.append('../../Algorithms/graphtheory/breadth-first-search/') +# sys.path.append('../../Algorithms/graphtheory/breadth-first-search/') from BFS_queue_iterative import BFS -class test_BFS(unittest.TestCase): +class test_BFS(unittest.TestCase): def setUp(self): - self.G1 = {1:[2],2:[1,3],3:[2]} + self.G1 = {1: [2], 2: [1, 3], 3: [2]} self.correct_visited1 = [True] * 3 - self.correct_path1 = [1,2,3] + self.correct_path1 = [1, 2, 3] - self.G2 = {1:[2], 2:[1,3,4], 3:[2], 4:[2,5], 5:[4]} + self.G2 = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2, 5], 5: [4]} self.correct_visited2 = [True] * 5 - self.G3 = {1:[2], 2:[1,3,4], 3:[2], 4:[2], 5:[]} - self.correct_visited3 = [True]*4 + [False] + self.G3 = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2], 5: []} + self.correct_visited3 = [True] * 4 + [False] - self.G4 = {1:[2,3,4], 2:[1,3,4], 3:[1,2,4], 4:[1,2,3]} - self.correct_visited4 = [True]*4 + self.G4 = {1: [2, 3, 4], 2: [1, 3, 4], 3: [1, 2, 4], 4: [1, 2, 3]} + self.correct_visited4 = [True] * 4 - self.G5 = {1:[2,3,4], 2:[1,5], 3:[1,7], 4:[1,6], 5:[2], 6:[4], 7:[3]} - self.correct_visited5 = [True]*7 + self.G5 = { + 1: [2, 3, 4], + 2: [1, 5], + 3: [1, 7], + 4: [1, 6], + 5: [2], + 6: [4], + 7: [3], + } + self.correct_visited5 = [True] * 7 def test_linear_graph(self): visited, path = BFS(self.G1, start_node=1) @@ -64,6 +72,6 @@ def test_breadth_before_depth(self): self.assertTrue(path.index(4) < path.index(7)) -if __name__ == '__main__': +if __name__ == "__main__": print("Running BFS/DFS tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/graphtheory_tests/DFS_test.py b/Algorithm_tests/graphtheory_tests/DFS_test.py index 25ed177..00518ca 100644 --- a/Algorithm_tests/graphtheory_tests/DFS_test.py +++ b/Algorithm_tests/graphtheory_tests/DFS_test.py @@ -5,34 +5,33 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/graphtheory/depth-first-search/') +sys.path.append("Algorithms/graphtheory/depth-first-search/") # If run from local: -#sys.path.append('../../Algorithms/graphtheory/depth-first-search/') +# sys.path.append('../../Algorithms/graphtheory/depth-first-search/') from DFS_recursive import DFS as DFS_rec from DFS_stack_iterative import DFS as DFS_stack -class test_DFS(unittest.TestCase): +class test_DFS(unittest.TestCase): def setUp(self): - self.G1 = {1:[2],2:[1,3],3:[2]} + self.G1 = {1: [2], 2: [1, 3], 3: [2]} self.correct_visited1 = [True] * 3 - self.correct_path1 = [1,2,3] + self.correct_path1 = [1, 2, 3] self.DFS_recursive_visited1 = [False for i in range(1, len(self.G1) + 1)] - self.G2 = {1:[2], 2:[1,3,4], 3:[2], 4:[2,5], 5:[4]} + self.G2 = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2, 5], 5: [4]} self.correct_visited2 = [True] * 5 self.DFS_recursive_visited2 = [False for i in range(1, len(self.G2) + 1)] - self.G3 = {1:[2], 2:[1,3,4], 3:[2], 4:[2], 5:[]} - self.correct_visited3 = [True]*4 + [False] - self.DFS_recursive_visited3= [False for i in range(1, len(self.G3) + 1)] + self.G3 = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2], 5: []} + self.correct_visited3 = [True] * 4 + [False] + self.DFS_recursive_visited3 = [False for i in range(1, len(self.G3) + 1)] - self.G4 = {1:[2,3,4], 2:[1,3,4], 3:[1,2,4], 4:[1,2,3]} - self.correct_visited4 = [True]*4 + self.G4 = {1: [2, 3, 4], 2: [1, 3, 4], 3: [1, 2, 4], 4: [1, 2, 3]} + self.correct_visited4 = [True] * 4 self.DFS_recursive_visited4 = [False for i in range(1, len(self.G4) + 1)] - def test_linear_graph(self): visited, path = DFS_stack(self.G1, start_node=1) self.assertEqual(visited, self.correct_visited1) @@ -62,6 +61,7 @@ def test_complete_graph(self): DFS_rec(self.G4, 1, self.DFS_recursive_visited4) self.assertEqual(self.DFS_recursive_visited4, self.correct_visited4) -if __name__ == '__main__': + +if __name__ == "__main__": print("Running BFS/DFS tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py b/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py index 95e481f..417e8f7 100644 --- a/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py +++ b/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_heap_test.py @@ -4,24 +4,25 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/graphtheory/dijkstra/') +sys.path.append("Algorithms/graphtheory/dijkstra/") # If run from local: -#sys.path.append('../../../Algorithms/graphtheory/dijkstra/') +# sys.path.append('../../../Algorithms/graphtheory/dijkstra/') from heapdijkstra import dijkstra + class test_Dijkstra(unittest.TestCase): def setUp(self): self.G1 = {} self.correct_path1 = [] self.correct_dist1 = float("inf") - self.G2 = {1:{2:1, 4:10}, 2:{3:15}, 3:{6:5}, 4:{5:1}, 5:{6:1}, 6: {}} - self.correct_path2 = [1,4,5,6] + self.G2 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {6: 5}, 4: {5: 1}, 5: {6: 1}, 6: {}} + self.correct_path2 = [1, 4, 5, 6] self.correct_dist2 = 12 - self.G3 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {}, 4: {5:1}, 5: {}, 6: {}} + self.G3 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {}, 4: {5: 1}, 5: {}, 6: {}} self.correct_path3 = [] self.correct_dist3 = float("inf") @@ -49,6 +50,7 @@ def test_not_endpoint(self): self.assertEqual(distances[5], self.correct_dist4) self.assertEqual(path_to_take, self.correct_path4) -if __name__ == '__main__': + +if __name__ == "__main__": print("Running Djikstra tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py b/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py index 60dcdb6..557aeeb 100644 --- a/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py +++ b/Algorithm_tests/graphtheory_tests/Djikstra/djikstra_naive_test.py @@ -4,24 +4,25 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/graphtheory/dijkstra/') +sys.path.append("Algorithms/graphtheory/dijkstra/") # If run from local: -#sys.path.append('../../../Algorithms/graphtheory/dijkstra/') +# sys.path.append('../../../Algorithms/graphtheory/dijkstra/') from dijkstra import dijkstra + class test_Dijkstra(unittest.TestCase): def setUp(self): self.G1 = {} self.correct_path1 = [] self.correct_dist1 = float("inf") - self.G2 = {1:{2:1, 4:10}, 2:{3:15}, 3:{6:5}, 4:{5:1}, 5:{6:1}, 6: {}} - self.correct_path2 = [1,4,5,6] + self.G2 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {6: 5}, 4: {5: 1}, 5: {6: 1}, 6: {}} + self.correct_path2 = [1, 4, 5, 6] self.correct_dist2 = 12 - self.G3 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {}, 4: {5:1}, 5: {}, 6: {}} + self.G3 = {1: {2: 1, 4: 10}, 2: {3: 15}, 3: {}, 4: {5: 1}, 5: {}, 6: {}} self.correct_path3 = [] self.correct_dist3 = float("inf") @@ -50,6 +51,6 @@ def test_not_endpoint(self): self.assertEqual(path_to_take, self.correct_path4) -if __name__ == '__main__': +if __name__ == "__main__": print("Running Djikstra tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/graphtheory_tests/bellman_ford_test.py b/Algorithm_tests/graphtheory_tests/bellman_ford_test.py index c9aea86..ce27f8d 100644 --- a/Algorithm_tests/graphtheory_tests/bellman_ford_test.py +++ b/Algorithm_tests/graphtheory_tests/bellman_ford_test.py @@ -4,26 +4,34 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/graphtheory/bellman-ford') +sys.path.append("Algorithms/graphtheory/bellman-ford") # If run from local: -#sys.path.append('../../Algorithms/graphtheory/bellman-ford') +# sys.path.append('../../Algorithms/graphtheory/bellman-ford') from bellman_ford import bellman_ford + class test_BellmanFord(unittest.TestCase): def test_negativecycle(self): # Because of negative cycles, we shall denote the shortest path for these # as -infinity. - G = {1: {2: 5, 3: 20}, 2: {4: 10}, 3: {5: 10}, 4:{}, 5: {6: 5}, 6: {3: -20}} - - correct_shortest_dist = {1: 0, 2: 5, 3: -float('inf'), 4: 15, 5: -float('inf'), 6: -float('inf')} + G = {1: {2: 5, 3: 20}, 2: {4: 10}, 3: {5: 10}, 4: {}, 5: {6: 5}, 6: {3: -20}} + + correct_shortest_dist = { + 1: 0, + 2: 5, + 3: -float("inf"), + 4: 15, + 5: -float("inf"), + 6: -float("inf"), + } shortest_dist, _ = bellman_ford(G, 1) self.assertEqual(shortest_dist, correct_shortest_dist) def test_shortestdist(self): - G = {1:{2:100, 3:5}, 2: {4:20}, 3:{2:10}, 4:{}} + G = {1: {2: 100, 3: 5}, 2: {4: 20}, 3: {2: 10}, 4: {}} start_node = 1 shortest_dist, _ = bellman_ford(G, start_node) @@ -45,6 +53,6 @@ def test_run_emptygraph(self): shortest_dist, _ = bellman_ford(G, start_node) -if __name__ == '__main__': +if __name__ == "__main__": print("Running bellman ford tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py b/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py index d7c6a73..70b2279 100644 --- a/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py +++ b/Algorithm_tests/graphtheory_tests/kahn_topological_ordering_test.py @@ -4,14 +4,15 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/graphtheory/kahns-toposort/') +sys.path.append("Algorithms/graphtheory/kahns-toposort/") # If run from local: -#sys.path.append('../../Algorithms/graphtheory/kahns-toposort') +# sys.path.append('../../Algorithms/graphtheory/kahns-toposort') from kahn_topological_ordering import topological_ordering from collections import defaultdict + class test_TopologicalOrdering(unittest.TestCase): def setUp(self): self.G1 = {} @@ -19,18 +20,30 @@ def setUp(self): self.correct_isDAG1 = False self.correct_path1 = [] - self.G2 = {'1': ['2'], '2':['3'], '3':['4'], '4':['5'], '5' : []} - self.degree_incoming2 = defaultdict(int, {'2':1, '3':1, '4':1, '5':1}) + self.G2 = {"1": ["2"], "2": ["3"], "3": ["4"], "4": ["5"], "5": []} + self.degree_incoming2 = defaultdict(int, {"2": 1, "3": 1, "4": 1, "5": 1}) self.correct_isDAG2 = True - self.correct_path2 = ['1', '2', '3', '4', '5'] + self.correct_path2 = ["1", "2", "3", "4", "5"] - self.G3 = {'1': ['2', '3', '4', '5'], '2': ['3', '4', '5'], '3': ['4','5'], '4': ['5'], '5': []} - self.degree_incoming3 = defaultdict(int, {'2': 1, '3': 2, '4': 3, '5': 4}) + self.G3 = { + "1": ["2", "3", "4", "5"], + "2": ["3", "4", "5"], + "3": ["4", "5"], + "4": ["5"], + "5": [], + } + self.degree_incoming3 = defaultdict(int, {"2": 1, "3": 2, "4": 3, "5": 4}) self.correct_isDAG3 = True - self.correct_path3 = ['1', '2', '3', '4', '5'] + self.correct_path3 = ["1", "2", "3", "4", "5"] - self.G4 = {'1': ['2', '3', '4', '5'], '2': ['3', '4', '5'], '3': ['2', '4', '5'], '4': ['5'], '5': []} - self.degree_incoming4 = defaultdict(int, {'2': 2, '3': 2, '4': 3, '5': 4}) + self.G4 = { + "1": ["2", "3", "4", "5"], + "2": ["3", "4", "5"], + "3": ["2", "4", "5"], + "4": ["5"], + "5": [], + } + self.degree_incoming4 = defaultdict(int, {"2": 2, "3": 2, "4": 3, "5": 4}) self.correct_isDAG4 = False self.correct_path4 = [] @@ -55,6 +68,6 @@ def test_no_topological_ordering(self): self.assertEqual(is_DAG, self.correct_isDAG4) -if __name__ == '__main__': +if __name__ == "__main__": print("Running Topological Ordering tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py b/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py index afd64e5..0aec006 100644 --- a/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py +++ b/Algorithm_tests/graphtheory_tests/kruskal_unionfind_test.py @@ -5,35 +5,52 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/graphtheory/kruskal/') +sys.path.append("Algorithms/graphtheory/kruskal/") # If run from local: -#sys.path.append('../../Algorithms/graphtheory/kruskal/') +# sys.path.append('../../Algorithms/graphtheory/kruskal/') from kruskal_unionfind import kruskal -class test_Kruskal(unittest.TestCase): +class test_Kruskal(unittest.TestCase): def setUp(self): - #self.G1 = {1:[(10, 2, 1)], 2:[(10, 1, 2), (10, 3, 2)], 3:[(10, 2, 3)]} + # self.G1 = {1:[(10, 2, 1)], 2:[(10, 1, 2), (10, 3, 2)], 3:[(10, 2, 3)]} self.G1 = [(10, 2, 1), (10, 1, 2), (10, 3, 2), (10, 2, 3)] self.num_nodes1 = 3 self.correct_cost1 = 20 - self.correct_MST1 = [(1,2,10),(2,3,10)] + self.correct_MST1 = [(1, 2, 10), (2, 3, 10)] - self.G2 = [(10,2,1),(10,3,1),(10,1,2),(100,3,2),(10,1,3),(100,2,3)] + self.G2 = [ + (10, 2, 1), + (10, 3, 1), + (10, 1, 2), + (100, 3, 2), + (10, 1, 3), + (100, 2, 3), + ] self.num_nodes2 = 3 self.correct_cost2 = 20 self.correct_MST2 = [(1, 2, 10), (1, 3, 10)] - self.G3 = [(1,2,1),(1,1,2),(1,3,2),(1,4,3),(5,5,3),(1,3,4),(1,5,4),(5,3,5),(1,4,5)] + self.G3 = [ + (1, 2, 1), + (1, 1, 2), + (1, 3, 2), + (1, 4, 3), + (5, 5, 3), + (1, 3, 4), + (1, 5, 4), + (5, 3, 5), + (1, 4, 5), + ] self.num_nodes3 = 5 self.correct_cost3 = 4 - self.correct_MST3 = [(1, 2, 1), (2,3,1), (3,4,1), (4,5,1)] + self.correct_MST3 = [(1, 2, 1), (2, 3, 1), (3, 4, 1), (4, 5, 1)] - self.G4 = [(1,2,1),(1,1,2),(1,4,3),(1,3,4)] + self.G4 = [(1, 2, 1), (1, 1, 2), (1, 4, 3), (1, 3, 4)] self.num_nodes4 = 4 self.correct_cost4 = 2 - self.correct_MST4 = [(1,2,1), (3,4,1)] + self.correct_MST4 = [(1, 2, 1), (3, 4, 1)] self.G5 = {} self.num_nodes5 = 0 @@ -41,23 +58,24 @@ def setUp(self): self.correct_MST5 = [] # Takes as input G which will have {node1: [(cost, to_node, node1), ...], node2:[(...)] } + def test_linear_graph(self): - MST, cost = kruskal(sorted(self.G1, key=lambda tup:tup[0]), self.num_nodes1) + MST, cost = kruskal(sorted(self.G1, key=lambda tup: tup[0]), self.num_nodes1) self.assertEqual(MST, self.correct_MST1) self.assertEqual(cost, self.correct_cost1) def test_triangle_graph(self): - MST, cost = kruskal(sorted(self.G2, key=lambda tup:tup[0]),self.num_nodes2) + MST, cost = kruskal(sorted(self.G2, key=lambda tup: tup[0]), self.num_nodes2) self.assertEqual(MST, self.correct_MST2) self.assertEqual(cost, self.correct_cost2) def test_trickier_mst(self): - MST, cost = kruskal(sorted(self.G3, key=lambda tup:tup[0]),self.num_nodes3) + MST, cost = kruskal(sorted(self.G3, key=lambda tup: tup[0]), self.num_nodes3) self.assertEqual(MST, self.correct_MST3) self.assertEqual(cost, self.correct_cost3) def test_disconnected_graph(self): - MST, cost = kruskal(sorted(self.G4, key=lambda tup:tup[0]), self.num_nodes4) + MST, cost = kruskal(sorted(self.G4, key=lambda tup: tup[0]), self.num_nodes4) self.assertEqual(MST, self.correct_MST4) self.assertEqual(cost, self.correct_cost4) @@ -66,6 +84,7 @@ def test_empty_graph(self): self.assertEqual(MST, self.correct_MST5) self.assertEqual(cost, self.correct_cost5) -if __name__ == '__main__': + +if __name__ == "__main__": print("Running Kruskal tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/graphtheory_tests/prims_algorithm_test.py b/Algorithm_tests/graphtheory_tests/prims_algorithm_test.py index 8122085..8ffebdb 100644 --- a/Algorithm_tests/graphtheory_tests/prims_algorithm_test.py +++ b/Algorithm_tests/graphtheory_tests/prims_algorithm_test.py @@ -4,52 +4,63 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/graphtheory/prims/') +sys.path.append("Algorithms/graphtheory/prims/") # If run from local: -#sys.path.append('../../Algorithms/graphtheory/prims/') +# sys.path.append('../../Algorithms/graphtheory/prims/') from prim_heap import prims_algo -class test_primsHeap(unittest.TestCase): +class test_primsHeap(unittest.TestCase): def setUp(self): # How I've decided to construct the graph is confusing, but the reason is because we're using a min heap and # want first element in the tuple to be the cost of the edge. However when I return the MST, we want it to be # returned as: from_node, to_node, edge_cost, rather than the reverse for constructing the graph. - self.G1 = {1:[(10, 2, 1)], 2:[(10, 1, 2), (10, 3, 2)], 3:[(10, 2, 3)]} + self.G1 = {1: [(10, 2, 1)], 2: [(10, 1, 2), (10, 3, 2)], 3: [(10, 2, 3)]} self.correct_cost1 = 20 - self.correct_MST1 = [(1,2,10),(2,3,10)] + self.correct_MST1 = [(1, 2, 10), (2, 3, 10)] - self.G2 = {1:[(10, 2, 1), (10, 3, 1)], 2 :[(10, 1, 2), (100, 3, 2)], 3: [(10, 1, 3), (100, 2, 3)]} + self.G2 = { + 1: [(10, 2, 1), (10, 3, 1)], + 2: [(10, 1, 2), (100, 3, 2)], + 3: [(10, 1, 3), (100, 2, 3)], + } self.correct_cost2 = 20 self.correct_MST2 = [(1, 2, 10), (1, 3, 10)] - self.G3 = {1:[(1, 2, 1)], 2:[(1, 1, 2), (1, 3, 2)], 3:[(1, 4, 3), (5, 5, 3)], 4:[(1,3,4),(1,5,4)], 5:[(5,3,5),(1,4,5)]} + self.G3 = { + 1: [(1, 2, 1)], + 2: [(1, 1, 2), (1, 3, 2)], + 3: [(1, 4, 3), (5, 5, 3)], + 4: [(1, 3, 4), (1, 5, 4)], + 5: [(5, 3, 5), (1, 4, 5)], + } self.correct_cost3 = 4 - self.correct_MST3 = [(1, 2, 1), (2,3,1), (3,4,1), (4,5,1)] + self.correct_MST3 = [(1, 2, 1), (2, 3, 1), (3, 4, 1), (4, 5, 1)] - self.G4 = {1:[(1, 2, 1)], 2:[(1,1,2)], 3:[(1,4,3)], 4:[(1, 3, 4)]} + self.G4 = {1: [(1, 2, 1)], 2: [(1, 1, 2)], 3: [(1, 4, 3)], 4: [(1, 3, 4)]} self.correct_cost4 = 1 - self.correct_MST4 = [(1,2,1)] + self.correct_MST4 = [(1, 2, 1)] self.G5 = {} self.correct_cost5 = 0 self.correct_MST5 = [] # Takes as input G which will have {node1: [(cost, to_node, node1), ...], node2:[(...)] } + def test_linear_graph(self): - MST, cost = prims_algo(self.G1,start=1) + MST, cost = prims_algo(self.G1, start=1) self.assertEqual(MST, self.correct_MST1) self.assertEqual(cost, self.correct_cost1) def test_triangle_graph(self): - MST, cost = prims_algo(self.G2,start=1) + MST, cost = prims_algo(self.G2, start=1) self.assertEqual(MST, self.correct_MST2) self.assertEqual(cost, self.correct_cost2) def test_trickier_mst(self): - MST, cost = prims_algo(self.G3,start=1) + MST, cost = prims_algo(self.G3, start=1) self.assertEqual(MST, self.correct_MST3) self.assertEqual(cost, self.correct_cost3) @@ -64,6 +75,6 @@ def test_empty_graph(self): self.assertEqual(cost, self.correct_cost5) -if __name__ == '__main__': +if __name__ == "__main__": print("Running Prims Heap tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/math_tests/intersection_test.py b/Algorithm_tests/math_tests/intersection_test.py index 9ad27ee..43efa50 100644 --- a/Algorithm_tests/math_tests/intersection_test.py +++ b/Algorithm_tests/math_tests/intersection_test.py @@ -4,7 +4,7 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/math/intersection_of_two_sets') +sys.path.append("Algorithms/math/intersection_of_two_sets") # If run from local: # sys.path.append('../../Algorithms/math/intersection_of_two_sets') @@ -13,30 +13,28 @@ class test_intersection(unittest.TestCase): - def setUp(self): # test cases we wish to run - self.L1 = [1,3,5,7,9,10] - self.L2 = [2,4,6,11,12] + self.L1 = [1, 3, 5, 7, 9, 10] + self.L2 = [2, 4, 6, 11, 12] self.L1L2_correct = [] - self.L3 = [1,3,5,10] - self.L4 = [2,4,6,10] + self.L3 = [1, 3, 5, 10] + self.L4 = [2, 4, 6, 10] self.L3L4_correct = [10] - self.L5 = [1,3,5,10] - self.L6 = [1,4,6,11] + self.L5 = [1, 3, 5, 10] + self.L6 = [1, 4, 6, 11] self.L5L6_correct = [1] - self.L7 = [1,2,3,4,5,6,7] - self.L8 = [1,2,3,4,5,6,7] - self.L7L8_correct = [1,2,3,4,5,6,7] + self.L7 = [1, 2, 3, 4, 5, 6, 7] + self.L8 = [1, 2, 3, 4, 5, 6, 7] + self.L7L8_correct = [1, 2, 3, 4, 5, 6, 7] self.L9 = [] self.L10 = [] self.L9L10_correct = [] - def test_intersection_none(self): L1L2_output = intersection(self.L1, self.L2) self.assertEqual(L1L2_output, self.L1L2_correct) @@ -57,6 +55,7 @@ def test_intersection_both_empty(self): L9L10_output = intersection(self.L9, self.L10) self.assertEqual(L9L10_output, self.L9L10_correct) -if __name__ == '__main__': + +if __name__ == "__main__": print("Running sorting tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/math_tests/union_test.py b/Algorithm_tests/math_tests/union_test.py index 867f658..7d2d612 100644 --- a/Algorithm_tests/math_tests/union_test.py +++ b/Algorithm_tests/math_tests/union_test.py @@ -4,38 +4,37 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/math/union_of_two_sets') +sys.path.append("Algorithms/math/union_of_two_sets") # If run from local: # sys.path.append('../../Algorithms/math/union_of_two_sets') from union_of_two_sets import union -class test_union(unittest.TestCase): +class test_union(unittest.TestCase): def setUp(self): # test cases we wish to run - self.L1 = [1,3,5,7,9,10] - self.L2 = [2,4,6,11,12] - self.L1L2_correct = [1,2,3,4,5,6,7,9,10,11,12] + self.L1 = [1, 3, 5, 7, 9, 10] + self.L2 = [2, 4, 6, 11, 12] + self.L1L2_correct = [1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12] - self.L3 = [1,3,5,10] - self.L4 = [2,4,6,10] - self.L3L4_correct = [1,2,3,4,5,6,10] + self.L3 = [1, 3, 5, 10] + self.L4 = [2, 4, 6, 10] + self.L3L4_correct = [1, 2, 3, 4, 5, 6, 10] - self.L5 = [1,3,5,10] - self.L6 = [1,4,6,11] - self.L5L6_correct = [1,3,4,5,6,10,11] + self.L5 = [1, 3, 5, 10] + self.L6 = [1, 4, 6, 11] + self.L5L6_correct = [1, 3, 4, 5, 6, 10, 11] - self.L7 = [1,2,3,4,5,6,7] - self.L8 = [1,2,3,4,5,6,7] - self.L7L8_correct = [1,2,3,4,5,6,7] + self.L7 = [1, 2, 3, 4, 5, 6, 7] + self.L8 = [1, 2, 3, 4, 5, 6, 7] + self.L7L8_correct = [1, 2, 3, 4, 5, 6, 7] self.L9 = [] self.L10 = [] self.L9L10_correct = [] - def test_union_all(self): L1L2_output = union(self.L1, self.L2) self.assertEqual(L1L2_output, self.L1L2_correct) @@ -56,6 +55,7 @@ def test_union_both_empty(self): L9L10_output = union(self.L9, self.L10) self.assertEqual(L9L10_output, self.L9L10_correct) -if __name__ == '__main__': + +if __name__ == "__main__": print("Running sorting tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/other_tests/test_binarysearch.py b/Algorithm_tests/other_tests/test_binarysearch.py index cfc376d..44f3ffe 100644 --- a/Algorithm_tests/other_tests/test_binarysearch.py +++ b/Algorithm_tests/other_tests/test_binarysearch.py @@ -4,16 +4,15 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/other') +sys.path.append("Algorithms/other") # If run from local: -#sys.path.append('../../Algorithms/other') +# sys.path.append('../../Algorithms/other') from binarysearch import binarysearch_iterative, binarysearch_recursive class test_binarysearch(unittest.TestCase): - def setUp(self): # test cases we wish to run self.L1 = [1, 3, 5, 8, 10, 12] @@ -24,13 +23,13 @@ def setUp(self): self.L2_target = 6 self.L2_correct = False, None - self.L3 = [1,1,1,1,1,1,1,1] + self.L3 = [1, 1, 1, 1, 1, 1, 1, 1] self.L3_target = 1 - self.L3_correct = True, (0+len(self.L3)-1)//2 + self.L3_correct = True, (0 + len(self.L3) - 1) // 2 self.L4 = [1, 3, 6, 11, 16, 21, 25, 27] self.L4_target = 27 - self.L4_correct = True, len(self.L4)-1 + self.L4_correct = True, len(self.L4) - 1 self.L5 = [1, 3, 6, 11, 16, 21, 27] self.L5_target = 1 @@ -40,61 +39,74 @@ def setUp(self): self.L6_target = 10 self.L6_correct = False, None - self.L7 = [11,12,15,19,23,41,173,298] + self.L7 = [11, 12, 15, 19, 23, 41, 173, 298] self.L7_target = 12 self.L7_correct = True, 1 - def test_binarysearch_basic(self): L1_result_iterative = binarysearch_iterative(self.L1, self.L1_target) - L1_result_recursive = binarysearch_recursive(self.L1, self.L1_target, 0, len(self.L1)-1) + L1_result_recursive = binarysearch_recursive( + self.L1, self.L1_target, 0, len(self.L1) - 1 + ) self.assertEqual(L1_result_iterative, self.L1_correct) self.assertEqual(L1_result_recursive, self.L1_correct) def test_binarysearch_nonexistant(self): L2_result_iterative = binarysearch_iterative(self.L2, self.L2_target) - L2_result_recursive = binarysearch_recursive(self.L2, self.L2_target, 0, len(self.L1)-1) + L2_result_recursive = binarysearch_recursive( + self.L2, self.L2_target, 0, len(self.L1) - 1 + ) self.assertEqual(L2_result_iterative, self.L2_correct) self.assertEqual(L2_result_recursive, self.L2_correct) def test_binarysearch_identical(self): L3_result_iterative = binarysearch_iterative(self.L3, self.L3_target) - L3_result_recursive = binarysearch_recursive(self.L3, self.L3_target, 0, len(self.L3) - 1) + L3_result_recursive = binarysearch_recursive( + self.L3, self.L3_target, 0, len(self.L3) - 1 + ) self.assertEqual(L3_result_iterative, self.L3_correct) self.assertEqual(L3_result_recursive, self.L3_correct) def test_binarysearch_lastvalue(self): L4_result_iterative = binarysearch_iterative(self.L4, self.L4_target) - L4_result_recursive = binarysearch_recursive(self.L4, self.L4_target, 0, len(self.L4) - 1) + L4_result_recursive = binarysearch_recursive( + self.L4, self.L4_target, 0, len(self.L4) - 1 + ) self.assertEqual(L4_result_iterative, self.L4_correct) self.assertEqual(L4_result_recursive, self.L4_correct) def test_binarysearch_firstvalue(self): L5_result_iterative = binarysearch_iterative(self.L5, self.L5_target) - L5_result_recursive = binarysearch_recursive(self.L5, self.L5_target, 0, len(self.L5) - 1) + L5_result_recursive = binarysearch_recursive( + self.L5, self.L5_target, 0, len(self.L5) - 1 + ) self.assertEqual(L5_result_iterative, self.L5_correct) self.assertEqual(L5_result_recursive, self.L5_correct) def test_binarysearch_empty(self): L6_result_iterative = binarysearch_iterative(self.L6, self.L6_target) - L6_result_recursive = binarysearch_recursive(self.L6, self.L6_target, 0, len(self.L6) - 1) + L6_result_recursive = binarysearch_recursive( + self.L6, self.L6_target, 0, len(self.L6) - 1 + ) self.assertEqual(L6_result_iterative, self.L6_correct) self.assertEqual(L6_result_recursive, self.L6_correct) def test_binarysearch_standard(self): L7_result_iterative = binarysearch_iterative(self.L7, self.L7_target) - L7_result_recursive = binarysearch_recursive(self.L7, self.L7_target, 0, len(self.L7) - 1) + L7_result_recursive = binarysearch_recursive( + self.L7, self.L7_target, 0, len(self.L7) - 1 + ) self.assertEqual(L7_result_iterative, self.L7_correct) self.assertEqual(L7_result_recursive, self.L7_correct) -if __name__ == '__main__': +if __name__ == "__main__": print("Running sorting tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/other_tests/test_intervalscheduling.py b/Algorithm_tests/other_tests/test_intervalscheduling.py index a23d7e3..e24843a 100644 --- a/Algorithm_tests/other_tests/test_intervalscheduling.py +++ b/Algorithm_tests/other_tests/test_intervalscheduling.py @@ -4,33 +4,31 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/other') +sys.path.append("Algorithms/other") # If run from local: -#sys.path.append('../../Algorithms/other') +# sys.path.append('../../Algorithms/other') from interval_scheduling import interval_scheduling class test_intervalscheduling(unittest.TestCase): - def setUp(self): # test cases we wish to run - self.R1 = [(0, 5), (3, 6),(5, 10)] - self.R1_correct = [(0,5), (5,10)] + self.R1 = [(0, 5), (3, 6), (5, 10)] + self.R1_correct = [(0, 5), (5, 10)] self.R2 = [] self.R2_correct = [] - self.R3 = [(0, 3), (3,6), (6,9), (9, 10)] - self.R3_correct = [(0, 3), (3,6), (6,9), (9, 10)] + self.R3 = [(0, 3), (3, 6), (6, 9), (9, 10)] + self.R3_correct = [(0, 3), (3, 6), (6, 9), (9, 10)] self.R4 = [(1, 3), (0, 2), (1, 4), (2, 5)] - self.R4_correct = [(0,2), (2,5)] - - self.R5 = [(0,3)] - self.R5_correct = [(0,3)] + self.R4_correct = [(0, 2), (2, 5)] + self.R5 = [(0, 3)] + self.R5_correct = [(0, 3)] def test_intervalscheduling_basic(self): O = [] @@ -58,6 +56,6 @@ def test_intervalscheduling_one_element(self): self.assertEqual(O, self.R5_correct) -if __name__ == '__main__': +if __name__ == "__main__": print("Running Interval Scheduling tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithm_tests/other_tests/test_medianmaintenance.py b/Algorithm_tests/other_tests/test_medianmaintenance.py index 01c1e40..47e1f6c 100644 --- a/Algorithm_tests/other_tests/test_medianmaintenance.py +++ b/Algorithm_tests/other_tests/test_medianmaintenance.py @@ -1,12 +1,13 @@ # Import packages import sys import unittest + # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/other') +sys.path.append("Algorithms/other") # If run from local: -#sys.path.append('../../Algorithms/other') +# sys.path.append('../../Algorithms/other') from median_maintenance import Maintain_Median @@ -28,7 +29,6 @@ def setUp(self): self.data5 = [1, 10, 2, 9, 11, 4, 6, 5, 3, 8, 7] self.correct5 = 6 - def test_basic(self): maintain_median = Maintain_Median() median = maintain_median.main(self.data1) @@ -55,6 +55,5 @@ def test_longer_example(self): self.assertEqual(median, self.correct5) - -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/Algorithm_tests/sorting_tests/test_sorting.py b/Algorithm_tests/sorting_tests/test_sorting.py index 8495b93..1ebf09a 100644 --- a/Algorithm_tests/sorting_tests/test_sorting.py +++ b/Algorithm_tests/sorting_tests/test_sorting.py @@ -4,7 +4,7 @@ # For importing from different folders # OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from -sys.path.append('Algorithms/sorting') +sys.path.append("Algorithms/sorting") # If run from local: # sys.path.append('../../Algorithms/sorting') @@ -17,29 +17,29 @@ from selectionsort import selectionsort # Test cases we wish to run -L1 = [1,2,3,4,5,6,7,8,9] -L1_sorted = [1,2,3,4,5,6,7,8,9] +L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9] +L1_sorted = [1, 2, 3, 4, 5, 6, 7, 8, 9] -L2 = [9,8,7,6,5,4,3,2,1] -L2_sorted = [1,2,3,4,5,6,7,8,9] +L2 = [9, 8, 7, 6, 5, 4, 3, 2, 1] +L2_sorted = [1, 2, 3, 4, 5, 6, 7, 8, 9] -L3 = [1,1,1,1,1,1,1,1,1] -L3_sorted = [1,1,1,1,1,1,1,1,1] +L3 = [1, 1, 1, 1, 1, 1, 1, 1, 1] +L3_sorted = [1, 1, 1, 1, 1, 1, 1, 1, 1] -L4 = [6,7,3,5,1,3] -L4_sorted = [1,3,3,5,6,7] +L4 = [6, 7, 3, 5, 1, 3] +L4_sorted = [1, 3, 3, 5, 6, 7] L5 = [] L5_sorted = [] -L6 = [-1,-2,-3] -L6_sorted = [-3,-2,-1] +L6 = [-1, -2, -3] +L6_sorted = [-3, -2, -1] -L7 = [-5,-7,-1,-3,-4] -L7_sorted = [-7,-5,-4,-3,-1] +L7 = [-5, -7, -1, -3, -4] +L7_sorted = [-7, -5, -4, -3, -1] -class test_sorting(unittest.TestCase): +class test_sorting(unittest.TestCase): def test_bubblesort(self): self.assertEqual(bubblesort(L1), L1_sorted) self.assertEqual(bubblesort(L2), L2_sorted) @@ -85,8 +85,6 @@ def test_quicksort(self): self.assertEqual(quicksort_lastpivot(L6), L6_sorted) self.assertEqual(quicksort_lastpivot(L7), L7_sorted) - - def test_selectionsort(self): self.assertEqual(selectionsort(L1), L1_sorted) self.assertEqual(selectionsort(L2), L2_sorted) @@ -106,6 +104,6 @@ def test_quicksort_randomized(self): self.assertEqual(quicksort_randomized(L7), L7_sorted) -if __name__ == '__main__': +if __name__ == "__main__": print("Running sorting tests:") - unittest.main() \ No newline at end of file + unittest.main() diff --git a/Algorithms/cryptology/RSA_algorithm/RSA.py b/Algorithms/cryptology/RSA_algorithm/RSA.py index 04e3891..8231bde 100644 --- a/Algorithms/cryptology/RSA_algorithm/RSA.py +++ b/Algorithms/cryptology/RSA_algorithm/RSA.py @@ -1,16 +1,17 @@ -''' +""" Purpose of the RSA cryptosystem is to have a secure way of transmitting data Programmed by Aladdin Persson * 2019-08-26 Initial programming -''' +""" from math import gcd from sympy import isprime import random from euclid_gcd import extended_euclidean + def generate_pq(bits): # Randomly generate two primes p,q p = random.getrandbits(bits) @@ -21,10 +22,10 @@ def generate_pq(bits): q_isprime = isprime(q) # Keep generating until both are primes - while (not (p_isprime and q_isprime)): - if (not p_isprime): + while not (p_isprime and q_isprime): + if not p_isprime: p = random.getrandbits(bits) - if (not q_isprime): + if not q_isprime: q = random.getrandbits(bits) p_isprime = isprime(p) @@ -32,6 +33,7 @@ def generate_pq(bits): return p, q + def generate_e(totient): # Generate e such that 1 < e < phi(n) # phi(n) in this case is totient @@ -39,36 +41,39 @@ def generate_e(totient): while True: # Should be (2,totient) so if it is stuck in infinite loop then restart or replace 80000 -> totient # Reason why I want e to be a low value is to make encryption faster - e = random.randint(2,50000) + e = random.randint(2, 50000) if gcd(e, totient) == 1: return e + def generate_d(e, totient): _, e_inverse, _ = extended_euclidean(e, totient) - d = (e_inverse % totient) + d = e_inverse % totient return d + def generate_all_values(): num_bits = 1024 - p,q = generate_pq(num_bits) - totient = (p-1) * (q-1) + p, q = generate_pq(num_bits) + totient = (p - 1) * (q - 1) e = generate_e(totient) - d = generate_d(e,totient) + d = generate_d(e, totient) + + print("Generated value n: " + str(p * q)) + print("Generated e and d: " + str(e) + " and " + str(d)) - print('Generated value n: ' + str(p*q)) - print('Generated e and d: ' + str(e) + ' and ' + str(d)) + return p * q, e, d - return p*q,e,d def encrypt(message, n, e): - encrypted = '' + encrypted = "" for letter in message: pad = 3 - len(str(ord(letter))) if pad > 0: - new_letter = '0' * pad + str(ord(letter)) + new_letter = "0" * pad + str(ord(letter)) else: new_letter = ord(letter) @@ -77,12 +82,13 @@ def encrypt(message, n, e): encrypted = pow(int(encrypted), e, n) return encrypted + def decrypt(encrypted, n, d): - decrypted_message = '' + decrypted_message = "" decrypted_code = str(pow(encrypted, d, n)) if len(decrypted_code) % 3 != 0: - decrypted_code = '0' + decrypted_code + decrypted_code = "0" + decrypted_code while len(decrypted_code): decrypted_message += chr(int(decrypted_code[0:3])) @@ -90,37 +96,42 @@ def decrypt(encrypted, n, d): return decrypted_message + def example(): # An example of a test case where we generate all necessary primes, encrypt and then decrypt the message. # Only to show how all parts of the code is working. This is not how it's going to be used in practice. hidden_message = "i really love peanuts" - n,e,d = generate_all_values() + n, e, d = generate_all_values() encrypted_message = encrypt(hidden_message, n, e) decrypted_message = decrypt(encrypted_message, n, d) - print('\n') - print('Original message: ' + hidden_message) - print('Encrypted message: ' + str(encrypted_message)) - print('Decrypted message: ' + decrypted_message) + print("\n") + print("Original message: " + hidden_message) + print("Encrypted message: " + str(encrypted_message)) + print("Decrypted message: " + decrypted_message) + def main(): # Write the values of your RSA encryption (Note: Never give the 'd' to someone that doesn't want it) n = 354089397494626050014776605732143027269473328409397973403863001639624332101789181044818951483060155060788030618162673282176493895463414816015601230408140046833172059490430968956729878861381343553446553025440156523477822105773362480000716985478565013956749662865189691539813391686696182702224364834273144673717742246537383454469146642154754778836797926780437490677663302034284308892191362266103193070200405420180296005388479418941723827243187899338980201782128797489464650981164232057548015010630986959083998487019465357524040595865260220030689502065850060761344148196291328192760801074939658292752592564874822996765430361631210613041006858858506787439506504448316606509551260553919757840169593791152166515571202450662850988377002989153080277915454500432640601643512909764636398157415600050468972065216354878984114648007494687081718749734915103155014825420081658864982423629447913147575382146725524407739875786801876011026010419782863232303861065841801863420557617962438178979549855959377311548527613240676904989886382444381261628076009466895878852398923237601309285642954207693266358989851324012643315688180744573155217352955083176785543099571257338683938756048920161738393295253775030232399282686809347027784971441882883201432807953 e = 9361 - #d = + # d = - enc_or_dec = input("Would you like to encrypt or decrypt a message (input: 'enc' or 'dec'): ") + enc_or_dec = input( + "Would you like to encrypt or decrypt a message (input: 'enc' or 'dec'): " + ) - if enc_or_dec.lower() == 'enc': + if enc_or_dec.lower() == "enc": hidden_message = input("What is your hidden message?: ") - print('Encrypted message: ' + str(encrypt(hidden_message, n, e))) + print("Encrypted message: " + str(encrypt(hidden_message, n, e))) - elif enc_or_dec.lower() == 'dec': - encrypted = input('What is your encrypted message?: ') + elif enc_or_dec.lower() == "dec": + encrypted = input("What is your encrypted message?: ") print(encrypted) - print('Decrypted message: ' + str(decrypt(int(encrypted), n, d))) + print("Decrypted message: " + str(decrypt(int(encrypted), n, d))) else: print("Not sure what you typed") -main() \ No newline at end of file + +main() diff --git a/Algorithms/cryptology/RSA_algorithm/euclid_gcd.py b/Algorithms/cryptology/RSA_algorithm/euclid_gcd.py index 769353d..ec153c7 100644 --- a/Algorithms/cryptology/RSA_algorithm/euclid_gcd.py +++ b/Algorithms/cryptology/RSA_algorithm/euclid_gcd.py @@ -1,20 +1,22 @@ -''' +""" -''' +""" import sys + sys.setrecursionlimit(100000) + def extended_euclidean(a, b): if a == 0: return (b, 0, 1) else: - gcd, x, y = extended_euclidean(b % a, a) - return (gcd, y - (b//a) * x, x) + gcd, x, y = extended_euclidean(b % a, a) + return (gcd, y - (b // a) * x, x) -if __name__ == '__main__': - print(extended_euclidean(5,-2772)) - #print(extended_euclidean(13, 2640)) +if __name__ == "__main__": + print(extended_euclidean(5, -2772)) + # print(extended_euclidean(13, 2640)) diff --git a/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py b/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py index 69513ff..c9f0623 100644 --- a/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py +++ b/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py @@ -1,4 +1,4 @@ -''' +""" The Ceasar cipher is one of the simplest and one of the earliest known ciphers. It is a type of substitution cipher that 'shifts' a letter by a fixed amount in the alphabet. @@ -13,16 +13,17 @@ Programmed by Aladdin Persson * 2019-11-07 Initial programming -''' +""" # This alphabet is of 27 letters since I included a space, but normally it is of 26 letters. # If you wish to include more letters you need to expand the alphabet used. For example you cannot use '!', '@' now. -alphabet = 'abcdefghijklmnopqrstuvwxyz ' +alphabet = "abcdefghijklmnopqrstuvwxyz " letter_to_index = dict(zip(alphabet, range(len(alphabet)))) index_to_letter = dict(zip(range(len(alphabet)), alphabet)) + def encrypt(message, shift=3): - cipher = '' + cipher = "" for letter in message: number = (letter_to_index[letter] + shift) % len(letter_to_index) @@ -31,8 +32,9 @@ def encrypt(message, shift=3): return cipher + def decrypt(cipher, shift=3): - decrypted = '' + decrypted = "" for letter in cipher: number = (letter_to_index[letter] - shift) % len(letter_to_index) @@ -41,6 +43,7 @@ def decrypt(cipher, shift=3): return decrypted + # def main(): # message = 'attackatnoon' # cipher = encrypt(message, shift=3) @@ -50,4 +53,4 @@ def decrypt(cipher, shift=3): # print('Encrypted message: ' + cipher) # print('Decrypted message: ' + decrypted) # -# main() \ No newline at end of file +# main() diff --git a/Algorithms/cryptology/hill_cipher/hill_cipher.py b/Algorithms/cryptology/hill_cipher/hill_cipher.py index 9aa57a0..5435d67 100644 --- a/Algorithms/cryptology/hill_cipher/hill_cipher.py +++ b/Algorithms/cryptology/hill_cipher/hill_cipher.py @@ -1,4 +1,4 @@ -''' +""" Implementation of Hill Cipher! Important notation: @@ -11,46 +11,53 @@ Programmed by Aladdin Persson * 2019-11-09 Initial programming -''' +""" import numpy as np -from egcd import egcd # pip install egcd +from egcd import egcd # pip install egcd -alphabet = 'abcdefghijklmnopqrstuvwxyz' +alphabet = "abcdefghijklmnopqrstuvwxyz" letter_to_index = dict(zip(alphabet, range(len(alphabet)))) index_to_letter = dict(zip(range(len(alphabet)), alphabet)) + def matrix_mod_inv(matrix, modulus): - '''We find the matrix modulus inverse by + """We find the matrix modulus inverse by Step 1) Find determinant Step 2) Find determinant value in a specific modulus (usually length of alphabet) Step 3) Take that det_inv times the det*inverted matrix (this will then be the adjoint) in mod 26 - ''' + """ - det = int(np.round(np.linalg.det(matrix))) # Step 1) + det = int(np.round(np.linalg.det(matrix))) # Step 1) det_inv = egcd(det, modulus)[1] % modulus # Step 2) - matrix_modulus_inv = det_inv * np.round(det*np.linalg.inv(matrix)).astype(int) % modulus # Step 3) + matrix_modulus_inv = ( + det_inv * np.round(det * np.linalg.inv(matrix)).astype(int) % modulus + ) # Step 3) return matrix_modulus_inv + def encrypt(message, K): - encrypted = '' + encrypted = "" message_in_numbers = [] for letter in message: message_in_numbers.append(letter_to_index[letter]) - split_P = [message_in_numbers[i:i + int(K.shape[0])] for i in range(0, len(message_in_numbers), int(K.shape[0]))] + split_P = [ + message_in_numbers[i : i + int(K.shape[0])] + for i in range(0, len(message_in_numbers), int(K.shape[0])) + ] for P in split_P: - P = np.transpose(np.asarray(P))[:,np.newaxis] + P = np.transpose(np.asarray(P))[:, np.newaxis] while P.shape[0] != K.shape[0]: - P = np.append(P, letter_to_index[' '])[:,np.newaxis] + P = np.append(P, letter_to_index[" "])[:, np.newaxis] numbers = np.dot(K, P) % len(alphabet) - n = numbers.shape[0] # length of encrypted message (in numbers) + n = numbers.shape[0] # length of encrypted message (in numbers) # Map back to get encrypted text for idx in range(n): @@ -59,17 +66,21 @@ def encrypt(message, K): return encrypted + def decrypt(cipher, Kinv): - decrypted = '' + decrypted = "" cipher_in_numbers = [] for letter in cipher: cipher_in_numbers.append(letter_to_index[letter]) - split_C = [cipher_in_numbers[i:i + int(Kinv.shape[0])] for i in range(0, len(cipher_in_numbers), int(Kinv.shape[0]))] + split_C = [ + cipher_in_numbers[i : i + int(Kinv.shape[0])] + for i in range(0, len(cipher_in_numbers), int(Kinv.shape[0])) + ] for C in split_C: - C = np.transpose(np.asarray(C))[:,np.newaxis] + C = np.transpose(np.asarray(C))[:, np.newaxis] numbers = np.dot(Kinv, C) % len(alphabet) n = numbers.shape[0] @@ -79,20 +90,22 @@ def decrypt(cipher, Kinv): return decrypted + def main(): - #message = 'my life is potato' - message = 'help' + # message = 'my life is potato' + message = "help" - K = np.matrix([[3,3],[2,5]]) + K = np.matrix([[3, 3], [2, 5]]) # K = np.matrix([[6, 24, 1], [13,16,10], [20,17,15]]) # for length of alphabet = 26 - #K = np.matrix([[3,10,20],[20,19,17], [23,78,17]]) # for length of alphabet = 27 + # K = np.matrix([[3,10,20],[20,19,17], [23,78,17]]) # for length of alphabet = 27 Kinv = matrix_mod_inv(K, len(alphabet)) encrypted_message = encrypt(message, K) decrypted_message = decrypt(encrypted_message, Kinv) - print('Original message: ' + message) - print('Encrypted message: ' + encrypted_message) - print('Decrypted message: ' + decrypted_message) + print("Original message: " + message) + print("Encrypted message: " + encrypted_message) + print("Decrypted message: " + decrypted_message) + -main() \ No newline at end of file +main() diff --git a/Algorithms/cryptology/one_time_pad/one_time_pad.py b/Algorithms/cryptology/one_time_pad/one_time_pad.py index ab85e70..a33156e 100644 --- a/Algorithms/cryptology/one_time_pad/one_time_pad.py +++ b/Algorithms/cryptology/one_time_pad/one_time_pad.py @@ -1,4 +1,4 @@ -''' +""" Implementation of the famous one time pad / Vernam Cipher In practice we need a way to generate random keys which I havn't included. @@ -6,58 +6,61 @@ Programmed by Aladdin Persson * 2019-11-12 Initial programming -''' +""" -def xor(s1,s2): + +def xor(s1, s2): xor_result = [] for i in range(min(len(s1), len(s2))): - xor_result.append(int(s1[i]) ^ int(s2[i])) # xor + xor_result.append(int(s1[i]) ^ int(s2[i])) # xor return xor_result + def encrypt(message, key): - binary_message = '' - binary_key = '' - ciphered_text = '' + binary_message = "" + binary_key = "" + ciphered_text = "" for letter in message: - binary_message += format(ord(letter), 'b') + binary_message += format(ord(letter), "b") for letter in key: - binary_key += format(ord(letter), 'b') + binary_key += format(ord(letter), "b") cipher_binary = xor(binary_message, binary_key) - return ''.join(str(e) for e in cipher_binary) + return "".join(str(e) for e in cipher_binary) + def decrypt(cipher_text, key): - binary_key = '' - decrypted_text = '' + binary_key = "" + decrypted_text = "" for letter in key: - binary_key += format(ord(letter), 'b') - + binary_key += format(ord(letter), "b") binary_message = xor(cipher_text, binary_key) - for i in range(0,len(binary_message),7): - letter = ''.join(str(e) for e in binary_message[i:i+7]) + for i in range(0, len(binary_message), 7): + letter = "".join(str(e) for e in binary_message[i : i + 7]) decrypted_text += chr(int(letter, 2)) return decrypted_text def main(): - message = 'cheesecake' # 'secret' message - key = 'randomrandomrandom' #'random' key + message = "cheesecake" # 'secret' message + key = "randomrandomrandom" #'random' key encrypted = encrypt(message, key) decrypted = decrypt(encrypted, key) - print('Original message: ' + str(message)) - print('Encrypted message (in binary): ' + str(encrypted)) - print('Decrypted message: ' + str(decrypted)) + print("Original message: " + str(message)) + print("Encrypted message (in binary): " + str(encrypted)) + print("Decrypted message: " + str(decrypted)) + -if __name__ == '__main__': - main() \ No newline at end of file +if __name__ == "__main__": + main() diff --git a/Algorithms/cryptology/vigenere_cipher/vigenere.py b/Algorithms/cryptology/vigenere_cipher/vigenere.py index 822c23f..69a71af 100644 --- a/Algorithms/cryptology/vigenere_cipher/vigenere.py +++ b/Algorithms/cryptology/vigenere_cipher/vigenere.py @@ -1,4 +1,4 @@ -''' +""" Vigenère cipher is one of the simplest that employs a form of polyalphabetic substitution (each letter is assigned more than one substitute). @@ -9,18 +9,20 @@ Programmed by Aladdin Persson * 2019-11-07 Initial programming -''' +""" -alphabet = 'abcdefghijklmnopqrstuvwxyz ' +alphabet = "abcdefghijklmnopqrstuvwxyz " letter_to_index = dict(zip(alphabet, range(len(alphabet)))) index_to_letter = dict(zip(range(len(alphabet)), alphabet)) def encrypt(message, key): - encrypted = '' - split_message = [message[i:i + len(key)] for i in range(0, len(message), len(key))] + encrypted = "" + split_message = [ + message[i : i + len(key)] for i in range(0, len(message), len(key)) + ] for each_split in split_message: i = 0 @@ -31,9 +33,12 @@ def encrypt(message, key): return encrypted + def decrypt(cipher, key): - decrypted = '' - split_encrypted = [cipher[i:i + len(key)] for i in range(0, len(cipher), len(key))] + decrypted = "" + split_encrypted = [ + cipher[i : i + len(key)] for i in range(0, len(cipher), len(key)) + ] for each_split in split_encrypted: i = 0 @@ -44,14 +49,16 @@ def decrypt(cipher, key): return decrypted + def main(): - message = 'i loove peanuts' - key = 'banana' + message = "i loove peanuts" + key = "banana" encrypted_message = encrypt(message, key) decrypted_message = decrypt(encrypted_message, key) - print('Original message: ' + message) - print('Encrypted message: ' + encrypted_message) - print('Decrypted message: ' + decrypted_message) + print("Original message: " + message) + print("Encrypted message: " + encrypted_message) + print("Decrypted message: " + decrypted_message) + -main() \ No newline at end of file +main() diff --git a/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py b/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py index 41070c8..f526381 100644 --- a/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py +++ b/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py @@ -1,4 +1,4 @@ -''' +""" Purpose is if having a bunch of items with a weight and corresponding value to each object. Which collection of objects should we choose such that we maximize the value restricted to a specific capacity of weight. Bottom up implementation of Knapsack (using loops) @@ -7,44 +7,47 @@ Programmed by Aladdin Persson 2020-02-15 Initial programming -''' +""" + def find_opt(i, c, M, values, items, weights): if i <= 0 or c <= 0: return items - if (M[i-1][c] >= (values[i-1] + M[i-1][c - weights[i-1]])) or (c - weights[i-1]) < 0: - find_opt(i-1, c, M, values, items, weights) - + if (M[i - 1][c] >= (values[i - 1] + M[i - 1][c - weights[i - 1]])) or ( + c - weights[i - 1] + ) < 0: + find_opt(i - 1, c, M, values, items, weights) + else: - items.append(i-1) - find_opt(i-1, c-weights[i-1], M, values, items, weights) - + items.append(i - 1) + find_opt(i - 1, c - weights[i - 1], M, values, items, weights) + + def knapsack(n, C, weights, values): # Initialization of matrix of size (n*W) M = [[None for i in range(C + 1)] for j in range(len(values) + 1)] - for c in range(C+1): + for c in range(C + 1): M[0][c] = 0 - for i in range(len(weights)+1): + for i in range(len(weights) + 1): M[i][0] = 0 - for i in range(1, n+1): - for c in range(1, C+1): + for i in range(1, n + 1): + for c in range(1, C + 1): # If current weight exceeds capacity then we cannot take it if weights[i - 1] > c: - M[i][c] = M[i-1][c] + M[i][c] = M[i - 1][c] # Else we can take it, then find what gives us the optimal value, either # taking it or not taking it and we consider what gives us max value of those else: - M[i][c] = max(M[i-1][c], values[i-1] + M[i-1][c-weights[i-1]]) + M[i][c] = max(M[i - 1][c], values[i - 1] + M[i - 1][c - weights[i - 1]]) items = [] find_opt(n, C, M, values, items, weights) - return M[n][C], items[::-1] diff --git a/Algorithms/dynamic_programming/knapsack/knapsack_memoization_recursive_topdown.py b/Algorithms/dynamic_programming/knapsack/knapsack_memoization_recursive_topdown.py index ba64803..d664aaf 100644 --- a/Algorithms/dynamic_programming/knapsack/knapsack_memoization_recursive_topdown.py +++ b/Algorithms/dynamic_programming/knapsack/knapsack_memoization_recursive_topdown.py @@ -8,36 +8,38 @@ # 2019-02-28 Initial programming # 2019-03-04 Made code cleaner and included a tracking of which items to choose + def knapsack(n, C, W, v, items, arr): # if n == 0 we cannot index further (since we look at n-1), further if we have no more capacity # then we cannot obtain more objects if n == 0 or C == 0: return 0, [] - elif arr[n-1][C-1] != None: - return arr[n-1][C-1], items + elif arr[n - 1][C - 1] != None: + return arr[n - 1][C - 1], items # If the weight is higher than our capacity then we can't pick it - elif W[n-1] > C: - result,items = knapsack(n-1,C, W, v, items, arr) + elif W[n - 1] > C: + result, items = knapsack(n - 1, C, W, v, items, arr) # Recursively search through all choices else: - tmp1,items1 = knapsack(n-1,C,W,v,items, arr) # exclude item - tmp2,items2 = knapsack(n-1,C - W[n-1], W, v, items, arr) # include item + tmp1, items1 = knapsack(n - 1, C, W, v, items, arr) # exclude item + tmp2, items2 = knapsack(n - 1, C - W[n - 1], W, v, items, arr) # include item items = items2 + [n - 1] if (tmp2 + v[n - 1] > tmp1) else items1 result = max(tmp1, tmp2 + v[n - 1]) - arr[n-1][C-1]=result + arr[n - 1][C - 1] = result return result, items -if __name__ == '__main__': + +if __name__ == "__main__": # Run a small example - weight = [1,2,4,2,5] - value = [5,3,5,3,2] + weight = [1, 2, 4, 2, 5] + value = [5, 3, 5, 3, 2] num_objects = len(weight) capacity = 3 diff --git a/Algorithms/dynamic_programming/knapsack/knapsack_naive_recursive.py b/Algorithms/dynamic_programming/knapsack/knapsack_naive_recursive.py index e580f3e..6eb1240 100644 --- a/Algorithms/dynamic_programming/knapsack/knapsack_naive_recursive.py +++ b/Algorithms/dynamic_programming/knapsack/knapsack_naive_recursive.py @@ -8,6 +8,7 @@ # 2019-02-28 Initial programming # 2019-03-04 Cleaned up code and included a tracking of which items to choose + def knapsack(n, C, W, v, items): # if n == 0 we cannot index further (since we look at n-1), further if we have no more capacity # then we cannot obtain more objects @@ -15,29 +16,29 @@ def knapsack(n, C, W, v, items): return 0, [] # If the weight is higher than our capacity then we can't pick it - elif W[n-1] > C: - result, items = knapsack(n-1,C, W, v, items) + elif W[n - 1] > C: + result, items = knapsack(n - 1, C, W, v, items) # Recursively search through all choices else: - tmp1, items1 = knapsack(n-1, C, W, v, items) # exclude item - tmp2, items2 = knapsack(n - 1, C - W[n - 1], W, v, items) # include item + tmp1, items1 = knapsack(n - 1, C, W, v, items) # exclude item + tmp2, items2 = knapsack(n - 1, C - W[n - 1], W, v, items) # include item - items=items2+[n-1] if (tmp2+v[n-1] > tmp1) else items1 + items = items2 + [n - 1] if (tmp2 + v[n - 1] > tmp1) else items1 - result=max(tmp1,tmp2+v[n-1]) + result = max(tmp1, tmp2 + v[n - 1]) return result, items -if __name__ == '__main__': +if __name__ == "__main__": # Run small example - weight = [1,2,4,2,5] - value = [5,3,5,3,2] + weight = [1, 2, 4, 2, 5] + value = [5, 3, 5, 3, 2] num_objects = len(weight) capacity = 3 arr = [[None for i in range(capacity)] for j in range(num_objects)] total_val_and_items = knapsack(num_objects, capacity, weight, value, []) - print(total_val_and_items)# items = [] + print(total_val_and_items) # items = [] diff --git a/Algorithms/dynamic_programming/longest_increasing_subsequence.py b/Algorithms/dynamic_programming/longest_increasing_subsequence.py index 7c3e189..8ac59f4 100644 --- a/Algorithms/dynamic_programming/longest_increasing_subsequence.py +++ b/Algorithms/dynamic_programming/longest_increasing_subsequence.py @@ -1,30 +1,30 @@ -''' +""" O(n^2) algorithm, can be faster and done in O(nlogn), but this works ok. To do: Create extensive test cases before adding to algorithm list. -''' +""" def longest_increasing_subsequence(nums): if len(nums) == 0: return 0 - + OPT = [1 for i in range(len(nums))] - + for i in range(1, len(nums)): for j in range(0, i): if nums[j] < nums[i] and OPT[j] + 1 > OPT[i]: OPT[i] = OPT[j] + 1 - + return max(OPT) -if __name__ == '__main__': +if __name__ == "__main__": # test1 = [1,5,-2,10, 50, -10, 10, 1,2,3,4] test2 = [10, 1, 2, 11, 3, 5] # test3 = [10,9,8,5,3,2,1,2,3] # test4 = [1,5,2,3,4,5,6] test5 = [] - + print(test2) - print(longest_increasing_subsequence(test2)) \ No newline at end of file + print(longest_increasing_subsequence(test2)) diff --git a/Algorithms/dynamic_programming/sequence_alignment.py b/Algorithms/dynamic_programming/sequence_alignment.py index af5e6d7..01775ae 100644 --- a/Algorithms/dynamic_programming/sequence_alignment.py +++ b/Algorithms/dynamic_programming/sequence_alignment.py @@ -1,4 +1,4 @@ -''' +""" Algorithm for solving sequence alignment Input strings x,y of len(x) = m, len(y) = n and find minimum number of edit steps and the specific steps to transform x into y. @@ -16,7 +16,8 @@ Should be working now. Extensive testing would be good. 2020-03-28 Cleaned up code by making SequenceAlignment into class -''' +""" + class SequenceAlignment(object): def __init__(self, x, y): @@ -31,43 +32,52 @@ def find_solution(self, OPT, m, n): return # We can only do insert if n != 0, align if there are element in both x, y, etc. - insert = OPT[m][n-1] + 1 if n != 0 else float('inf') - align = OPT[m-1][n-1] + self.delta(self.x, self.y, m-1,n-1) if m != 0 and n != 0 else float('inf') - delete = OPT[m-1][n] + 1 if m != 0 else float('inf') + insert = OPT[m][n - 1] + 1 if n != 0 else float("inf") + align = ( + OPT[m - 1][n - 1] + self.delta(self.x, self.y, m - 1, n - 1) + if m != 0 and n != 0 + else float("inf") + ) + delete = OPT[m - 1][n] + 1 if m != 0 else float("inf") best_choice = min(insert, align, delete) if best_choice == insert: - self.solution.append('insert_'+str(self.y[n-1])) - return self.find_solution(OPT, m, n-1) + self.solution.append("insert_" + str(self.y[n - 1])) + return self.find_solution(OPT, m, n - 1) elif best_choice == align: - self.solution.append('align_' + str(self.y[n-1])) - return self.find_solution(OPT, m-1, n-1) + self.solution.append("align_" + str(self.y[n - 1])) + return self.find_solution(OPT, m - 1, n - 1) elif best_choice == delete: - self.solution.append('remove_'+str(self.x[m-1])) - return self.find_solution(OPT, m-1, n) + self.solution.append("remove_" + str(self.x[m - 1])) + return self.find_solution(OPT, m - 1, n) def alignment(self): n = len(self.y) m = len(self.x) - OPT = [ [0 for i in range(n+1)] for j in range(m+1)] + OPT = [[0 for i in range(n + 1)] for j in range(m + 1)] - for i in range(1,m+1): + for i in range(1, m + 1): OPT[i][0] = i - for j in range(1,n+1): + for j in range(1, n + 1): OPT[0][j] = j - for i in range(1,m+1): - for j in range(1,n+1): - OPT[i][j] = min(OPT[i-1][j-1] + self.delta(self.x,self.y,i-1,j-1), OPT[i-1][j] + 1, OPT[i][j-1] + 1) #align, delete, insert respectively + for i in range(1, m + 1): + for j in range(1, n + 1): + OPT[i][j] = min( + OPT[i - 1][j - 1] + self.delta(self.x, self.y, i - 1, j - 1), + OPT[i - 1][j] + 1, + OPT[i][j - 1] + 1, + ) # align, delete, insert respectively self.find_solution(OPT, m, n) return (OPT[m][n], self.solution[::-1]) + # if __name__ == '__main__': # x = 'TGACGTGC' # y = 'TCGACGTCA' @@ -75,4 +85,4 @@ def alignment(self): # sqalign = SequenceAlignment(x, y) # min_edit, steps = sqalign.alignment() # print('Minimum amount of edit steps are: ' + str(min_edit)) -# print('And the way to do it is: ' + str(steps)) \ No newline at end of file +# print('And the way to do it is: ' + str(steps)) diff --git a/Algorithms/dynamic_programming/weighted_interval_scheduling.py b/Algorithms/dynamic_programming/weighted_interval_scheduling.py index 33be189..e5bf456 100644 --- a/Algorithms/dynamic_programming/weighted_interval_scheduling.py +++ b/Algorithms/dynamic_programming/weighted_interval_scheduling.py @@ -1,4 +1,4 @@ -''' +""" Weighted Interval Scheduling Explained YouTube video: https://www.youtube.com/watch?v=iIX1YvbLbvc Implementation walkthrough video: https://www.youtube.com/watch?v=dU-coYsd7zw @@ -8,13 +8,14 @@ 2020-03-28 Cleaned up code by making WeightedIntervalScheduling class Time complexity: O(nlogn) -''' +""" import bisect + class WeightedIntervalScheduling(object): def __init__(self, I): - self.I = sorted(I, key = lambda tup : tup[1]) #(key = lambda tup : tup[1]) + self.I = sorted(I, key=lambda tup: tup[1]) # (key = lambda tup : tup[1]) self.OPT = [] self.solution = [] @@ -50,7 +51,9 @@ def compute_opt(self, j): return self.OPT[j] else: - return max(self.I[j][2] + self.compute_opt(self.p[j]), self.compute_opt(j - 1)) + return max( + self.I[j][2] + self.compute_opt(self.p[j]), self.compute_opt(j - 1) + ) def weighted_interval(self): if len(self.I) == 0: @@ -66,6 +69,7 @@ def weighted_interval(self): return self.OPT[-1], self.solution[::-1] + # Small Example # if __name__ == '__main__': # # They are labeled as: (start, end, weight) @@ -81,4 +85,4 @@ def weighted_interval(self): # weightedinterval = WeightedIntervalScheduling(I) # max_weight, best_intervals = weightedinterval.weighted_interval() # print('Maximum weight: ' + str(max_weight)) -# print('The best items to take are: ' + str(best_intervals)) \ No newline at end of file +# print('The best items to take are: ' + str(best_intervals)) diff --git a/Algorithms/graphtheory/bellman-ford/bellman_ford.py b/Algorithms/graphtheory/bellman-ford/bellman_ford.py index 0868eba..82b462f 100644 --- a/Algorithms/graphtheory/bellman-ford/bellman_ford.py +++ b/Algorithms/graphtheory/bellman-ford/bellman_ford.py @@ -1,4 +1,4 @@ -''' +""" Purpose is to find the shortest path between one source node to all other nodes using Bellman-Ford Algorithm. The difference between Dijkstra and this is that this can handle negative edges. We do pay for this as it is a lot slower than Dijkstra. @@ -7,13 +7,14 @@ Programmed by Aladdin Persson 2019-03-04 Initial programming -''' +""" + def bellman_ford(G, start): - ''' + """ :param G: {from_node1: {to_node1, cost1, to_node2, cost2}, from_node2: {etc}} :param start: node to start from - ''' + """ if len(G) == 0: raise ValueError("There should be something in the graph") @@ -21,7 +22,7 @@ def bellman_ford(G, start): # step1: initialize by setting to infinity etc. shortest_distance = {} predecessor = {} - infinity = float('inf') + infinity = float("inf") for node in G: shortest_distance[node] = infinity @@ -39,12 +40,13 @@ def bellman_ford(G, start): # step3: check neg. cycles for from_node in G: - for to_node,weight in G[from_node].items(): + for to_node, weight in G[from_node].items(): if shortest_distance[from_node] + weight < shortest_distance[to_node]: shortest_distance[to_node] = -infinity return shortest_distance, predecessor + # if __name__ == '__main__': # G = {1: {2: -10, 3: 20}, # 2: {4: 40}, @@ -53,4 +55,4 @@ def bellman_ford(G, start): # # print(f'Current graph is: {G}') # shortest, predecessor = bellman_ford(G, 1) -# print(shortest) \ No newline at end of file +# print(shortest) diff --git a/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py b/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py index 25c2c32..fbdedaa 100644 --- a/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py +++ b/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py @@ -1,19 +1,20 @@ -''' +""" Programmed by Aladdin Persson 2019-02-17 Initial programming 2020-03-29 Cleaned up code, removed load graph, I think a small example is sufficient and instead only have the BFS function. -''' +""" from collections import deque + def BFS(G, start_node=1): - ''' + """ :param G: Graph with G = {from_node1:[to_node1, to_node2], from_node2: [to_node,] etc} :param start_node: starting node to run BFS from :return: returns visited boolean array and path in which order it visited them - ''' - visited = [False for i in range(1,len(G)+1)] + """ + visited = [False for i in range(1, len(G) + 1)] Q = deque() Q.append(start_node) @@ -25,14 +26,15 @@ def BFS(G, start_node=1): path.append(curr_node) if not visited[curr_node - 1]: - visited[curr_node-1]=True + visited[curr_node - 1] = True for connected_node in G[curr_node]: - if not visited[connected_node-1]: + if not visited[connected_node - 1]: Q.append(connected_node) return visited, path + # Small Example Run # if __name__ == '__main__': # G = {1:[2,3], 2:[1,4], 3:[1,4],4:[]} @@ -42,4 +44,4 @@ def BFS(G, start_node=1): # print("Return: This graph is connected!") # else: -# print("Not all nodes were reachable, i.e the graph is not connected.") \ No newline at end of file +# print("Not all nodes were reachable, i.e the graph is not connected.") diff --git a/Algorithms/graphtheory/depth-first-search/DFS_recursive.py b/Algorithms/graphtheory/depth-first-search/DFS_recursive.py index 2babc14..0c70523 100644 --- a/Algorithms/graphtheory/depth-first-search/DFS_recursive.py +++ b/Algorithms/graphtheory/depth-first-search/DFS_recursive.py @@ -4,23 +4,25 @@ # Programmed by Aladdin Persson # 2019-02-16 Initial programming + def DFS(G, curr_node, visited): - ''' + """ :param G: G = {from_node1:[to_node1, to_node2], from_node2: [to_node,] etc} :param curr_node: Node currently at, run from beginning this is the starting node :param visited: since it is recursive, visited is updated and needs to be sent in on recursive call :return: visited is initialized outside of DFS and updates this boolean array with which nodes has been visited - ''' + """ if visited[curr_node - 1]: return - visited[curr_node-1] = True + visited[curr_node - 1] = True neighbours = G[curr_node] for next_node in neighbours: DFS(G, next_node, visited) + # Small Eaxmple # if __name__ == '__main__': # G = {1: [2], 2: [1, 3, 4], 3: [2], 4: [2, 5], 5: [4]} @@ -31,4 +33,4 @@ def DFS(G, curr_node, visited): # DFS(G, start_node, visited) # # if any(visited) == False: -# print("Result: This graph is connected!") \ No newline at end of file +# print("Result: This graph is connected!") diff --git a/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py b/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py index b642772..91fcce6 100644 --- a/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py +++ b/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py @@ -1,18 +1,19 @@ -''' +""" Depth first search has many applications,for example finding if a graph G is connected. Identify all nodes that are reachable from a given starting node. Programmed by Aladdin Persson 2019-02-17 Initial programming 2020-03-29 Cleaned up code, made test cases -''' +""" + def DFS(G, start_node): - ''' + """ :param G: Graph with G = {from_node1:[to_node1, to_node2], from_node2: [to_node,] etc} :param start_node: starting node to run BFS from :return: returns visited boolean array and path in which order it visited them - ''' + """ visited = [False for i in range(1, len(G) + 1)] path = [start_node] stack = [] @@ -20,16 +21,17 @@ def DFS(G, start_node): while stack: v = stack.pop() - if not visited[v-1]: - visited[v-1]=True + if not visited[v - 1]: + visited[v - 1] = True for connected_node in G[v]: - if not visited[connected_node-1]: + if not visited[connected_node - 1]: stack.append(connected_node) path.append(connected_node) return visited, path + # if __name__ == '__main__': # G = {1: [2, 3], 2: [1, 4], 3: [1, 4], 4: []} # start_node = 1 @@ -38,4 +40,4 @@ def DFS(G, start_node): # if all(visited) == True: # print("Return: This graph is connected!") # else: -# print("Not all nodes were reachable, i.e the graph is not connected.") \ No newline at end of file +# print("Not all nodes were reachable, i.e the graph is not connected.") diff --git a/Algorithms/graphtheory/dijkstra/dijkstra.py b/Algorithms/graphtheory/dijkstra/dijkstra.py index ad2f0e8..6c52add 100644 --- a/Algorithms/graphtheory/dijkstra/dijkstra.py +++ b/Algorithms/graphtheory/dijkstra/dijkstra.py @@ -1,27 +1,28 @@ -''' +""" Dijkstra's algorithm for finding the shortest path in a graph, this implementation is a naive implementation, check my Heap implementation for a more efficient algorithm Programmed by Aladdin Persson 2019-01-28 Initial programming 2020-03-28 Cleaned up code -''' +""" + def dijkstra(G, start, end): - ''' + """ :param G: {from_node1: {to_node1:cost1, to_node2:cost2}, from_node2 : {.., etc.}, ...} :param start: starting node :param end: ending node where we want to find path to :return: path from starting node to end node and the cost to get between them - ''' + """ if start not in G or end not in G: - return [], float('inf') + return [], float("inf") shortest_distance = {} predecessor = {} unseenNodes = G - infinity = float('inf') + infinity = float("inf") path = [] for node in unseenNodes: @@ -29,7 +30,6 @@ def dijkstra(G, start, end): shortest_distance[start] = 0 - while unseenNodes: minNode = None @@ -39,7 +39,6 @@ def dijkstra(G, start, end): elif shortest_distance[node] < shortest_distance[minNode]: minNode = node - for childNode, weight in G[minNode].items(): if weight + shortest_distance[minNode] < shortest_distance[childNode]: shortest_distance[childNode] = weight + shortest_distance[minNode] @@ -55,22 +54,18 @@ def dijkstra(G, start, end): path.insert(0, currentNode) currentNode = predecessor[currentNode] except KeyError: - return [], float('inf') - - path.insert(0,start) + return [], float("inf") + path.insert(0, start) return path, shortest_distance[end] -if __name__ == '__main__': - G = {1:{2:10, 3:20}, - 2:{4:40}, - 3:{4:5}, - 4:{}} +if __name__ == "__main__": + G = {1: {2: 10, 3: 20}, 2: {4: 40}, 3: {4: 5}, 4: {}} - print(f'Current graph is: {G}') + print(f"Current graph is: {G}") path, shortest = dijkstra(G, 1, 4) print(path) - print(shortest) \ No newline at end of file + print(shortest) diff --git a/Algorithms/graphtheory/dijkstra/heapdijkstra.py b/Algorithms/graphtheory/dijkstra/heapdijkstra.py index 1b59293..3a593c6 100644 --- a/Algorithms/graphtheory/dijkstra/heapdijkstra.py +++ b/Algorithms/graphtheory/dijkstra/heapdijkstra.py @@ -1,4 +1,4 @@ -''' +""" Dijkstra's algorithm for finding the shortest path. Improved version with the usage of heaps. @@ -6,32 +6,41 @@ 2019-02-15 Initial coding 2020-03-28 Small code changes, fixed for edge cases not covered -''' +""" import heapq + def make_graph(file): try: - f = open(file, 'r') + f = open(file, "r") except IOError: - raise("File does not exist!") + raise ("File does not exist!") line_list = f.readlines() # Kinda messy graph loading - G = {int(line.split()[0]): {(int(tup.split(',')[0])): int(tup.split(',')[1]) - for tup in line.split()[1:] if tup} for line in line_list if line} + G = { + int(line.split()[0]): { + (int(tup.split(",")[0])): int(tup.split(",")[1]) + for tup in line.split()[1:] + if tup + } + for line in line_list + if line + } f.close() return G + def dijkstra(G, start, end=None): if start not in G or (end != None and end not in G): - return [], {end:float('inf')} + return [], {end: float("inf")} distance, visited, history, heap, path = {}, {}, {}, [], [] for node in G.keys(): - distance[node] = float('inf') + distance[node] = float("inf") visited[node] = False distance[start], visited[start] = 0, True @@ -63,18 +72,15 @@ def dijkstra(G, start, end=None): return path, distance -if __name__ == '__main__': +if __name__ == "__main__": # start, end = 1, 160 # print(f'Goal is to find the path from node {start} to node {end}') # G = make_graph('dijkstraData.txt') - G = {1: {2: 10, 3: 20}, - 2: {4: 40}, - 3: {4: 5}, - 4: {}} - start=1 - end=2 + G = {1: {2: 10, 3: 20}, 2: {4: 40}, 3: {4: 5}, 4: {}} + start = 1 + end = 2 path, dist = dijkstra(G, start, end) - print(f'Path found: {path}') - print(dist) \ No newline at end of file + print(f"Path found: {path}") + print(dist) diff --git a/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py b/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py index dcbcbfe..e65d495 100644 --- a/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py +++ b/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py @@ -1,11 +1,12 @@ -''' +""" Purpose is to the find shortest path from all nodes to all other nodes, O(n^3). Can be used with negative weights, however to check if it has negative cycles, bellman ford should prob. be used first. Programmed by Aladdin Persson * 2019-03-08 Initial programming -''' +""" + def load_graph(file_name): try: @@ -16,21 +17,38 @@ def load_graph(file_name): except IOError: raise IOError("File does not exist") - G = {int(line.split()[0]): {(int(tup.split(',')[0])): int(tup.split(',')[1]) - for tup in line.split()[1:] if tup} for line in line_list if line} + G = { + int(line.split()[0]): { + (int(tup.split(",")[0])): int(tup.split(",")[1]) + for tup in line.split()[1:] + if tup + } + for line in line_list + if line + } # If we have path set path else make value infinity - adjacency_matrix = [[G[i][j] if (i in G and j in G[i]) else float('inf') for j in range(1, len(G) + 1)] for i in range(1, len(G) + 1)] + adjacency_matrix = [ + [ + G[i][j] if (i in G and j in G[i]) else float("inf") + for j in range(1, len(G) + 1) + ] + for i in range(1, len(G) + 1) + ] # Make diagonal values all 0 for i in range(len(G)): adjacency_matrix[i][i] = 0 # next will be matrix showing which path to take for the shortest path - next = [[j if adjacency_matrix[i][j] != float('inf') else None for j in range(len(G))] for i in range(len(G))] + next = [ + [j if adjacency_matrix[i][j] != float("inf") else None for j in range(len(G))] + for i in range(len(G)) + ] return adjacency_matrix, next + def floyd_warshall(adj_matrix, next): n = len(adj_matrix) # make a copy of adj_matrix, dp will contain APSP (All-Path-Shortest-Path) solutions, @@ -49,6 +67,7 @@ def floyd_warshall(adj_matrix, next): # return APSP (All-Path-Shortest-Path) matrix return APSP, next + def construct_path_to_take(next, start, end): go_through = start path = [start] @@ -61,12 +80,13 @@ def construct_path_to_take(next, start, end): return path -if __name__ == '__main__': - adj_matrix, next = load_graph('test_graph.txt') + +if __name__ == "__main__": + adj_matrix, next = load_graph("test_graph.txt") APSP, next = floyd_warshall(adj_matrix, next) - print(f'The shortest paths are {APSP}') - print(f'The path to take is given by {next}') + print(f"The shortest paths are {APSP}") + print(f"The path to take is given by {next}") path_to_take = construct_path_to_take(next, 0, 3) - print(path_to_take) \ No newline at end of file + print(path_to_take) diff --git a/Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py b/Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py index d1c272a..572e175 100644 --- a/Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py +++ b/Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py @@ -1,4 +1,4 @@ -''' +""" Purpose of this algorithm is finding a path that is in topological ordering for a directed acyclic graph (DAG). If the graph is not a DAG and includes cycles it will return is_DAG = 'False' meaning it has cycles. @@ -9,10 +9,11 @@ * 2020-03-28 Removed load graph function, just having topological sort seems to make more sense The loading of the graph is so varying depending on input, doesn't make much sense to include it -''' +""" from collections import defaultdict, deque + def topological_ordering(graph, degree_incoming): if len(graph) == 0: return [], False @@ -20,7 +21,8 @@ def topological_ordering(graph, degree_incoming): curr_accessible_nodes = deque() for node in graph: - if degree_incoming[node] == 0: curr_accessible_nodes.append(node) + if degree_incoming[node] == 0: + curr_accessible_nodes.append(node) path = [] @@ -44,13 +46,14 @@ def topological_ordering(graph, degree_incoming): return path, is_DAG -if __name__ == '__main__': - G = {'A': ['B'], 'B': ['C', 'D'], 'C': ['D'], 'D': []} - degree_incoming = defaultdict(int, {'B': 1, 'C': 1, 'D': 2}) - print('The graph to check is : ' + str(G)) - print('Which has incoming edges: ' + str(degree_incoming)) - print('\n') +if __name__ == "__main__": + G = {"A": ["B"], "B": ["C", "D"], "C": ["D"], "D": []} + degree_incoming = defaultdict(int, {"B": 1, "C": 1, "D": 2}) + + print("The graph to check is : " + str(G)) + print("Which has incoming edges: " + str(degree_incoming)) + print("\n") path_to_take, is_DAG = topological_ordering(G, degree_incoming) - print('The graph has a topological ordering <--> G is a DAG: ' + str(is_DAG)) - print(f'One path to take that is a topological ordering is {"".join(path_to_take)}') \ No newline at end of file + print("The graph has a topological ordering <--> G is a DAG: " + str(is_DAG)) + print(f'One path to take that is a topological ordering is {"".join(path_to_take)}') diff --git a/Algorithms/graphtheory/kargers/kargermincut.py b/Algorithms/graphtheory/kargers/kargermincut.py index 3b3fc36..3d754c5 100644 --- a/Algorithms/graphtheory/kargers/kargermincut.py +++ b/Algorithms/graphtheory/kargers/kargermincut.py @@ -13,8 +13,9 @@ random.seed(1) + def load_graph(): - data = open('data.txt', 'r') + data = open("data.txt", "r") G = {} for line in data: @@ -66,5 +67,6 @@ def main(): return count + val = main() -print(val) \ No newline at end of file +print(val) diff --git a/Algorithms/graphtheory/kruskal/kruskal.py b/Algorithms/graphtheory/kruskal/kruskal.py index 0961ee8..d2e9ad1 100644 --- a/Algorithms/graphtheory/kruskal/kruskal.py +++ b/Algorithms/graphtheory/kruskal/kruskal.py @@ -1,32 +1,35 @@ -''' +""" Kruskal's algorithm for finding minimal spanning tree (MST) of a graph. Aladdin Persson 2019-02-16 Initial programming -''' +""" import sys -sys.path.append('../depth-first-search') + +sys.path.append("../depth-first-search") from DFS_stack_iterative import DFS -def load_graph(file='edges.txt'): + +def load_graph(file="edges.txt"): G = [] try: - f = open(file, 'r') + f = open(file, "r") except IOError: - raise("File does not exist!") + raise ("File does not exist!") line_list = f.readlines() - num_nodes, num_edges = map(int,line_list[0].split()) + num_nodes, num_edges = map(int, line_list[0].split()) for line in line_list[1:]: G.append(tuple(map(int, line.split()))[::-1]) return sorted(G), num_nodes + def kruskal(G, num_nodes): MST = [] tot_cost = 0 @@ -53,14 +56,14 @@ def kruskal(G, num_nodes): return MST, tot_cost -if __name__ == '__main__': - print('---- Computing minimal spanning tree using Kruskal\'s Algorithm ----') +if __name__ == "__main__": + print("---- Computing minimal spanning tree using Kruskal's Algorithm ----") print() G, num_nodes = load_graph() - print(f'Our loaded graph is: {G}') + print(f"Our loaded graph is: {G}") MST, total_cost = kruskal(G) - print(f'Our minimum spanning tree is: {MST}') - print(f'Total cost is: {total_cost}') \ No newline at end of file + print(f"Our minimum spanning tree is: {MST}") + print(f"Total cost is: {total_cost}") diff --git a/Algorithms/graphtheory/kruskal/kruskal_unionfind.py b/Algorithms/graphtheory/kruskal/kruskal_unionfind.py index 96ec4e0..63af644 100644 --- a/Algorithms/graphtheory/kruskal/kruskal_unionfind.py +++ b/Algorithms/graphtheory/kruskal/kruskal_unionfind.py @@ -5,17 +5,18 @@ from unionfind import unionfind -def load_graph(file='edges.txt'): + +def load_graph(file="edges.txt"): G = [] try: - f = open(file, 'r') + f = open(file, "r") except IOError: - raise("File does not exist!") + raise ("File does not exist!") line_list = f.readlines() - num_nodes, num_edges = map(int,line_list[0].split()) + num_nodes, num_edges = map(int, line_list[0].split()) for line in line_list[1:]: G.append(tuple(map(int, line.split()))[::-1]) @@ -30,23 +31,24 @@ def kruskal(G, num_nodes): for each_edge in G: cost, to_node, from_node = each_edge[0], each_edge[1], each_edge[2] - if not uf.issame(from_node-1, to_node-1): + if not uf.issame(from_node - 1, to_node - 1): tot_cost += cost - uf.unite(from_node-1, to_node-1) + uf.unite(from_node - 1, to_node - 1) MST.append((from_node, to_node, cost)) return MST, tot_cost -if __name__ == '__main__': - print('---- Computing minimal spanning tree using Kruskal\'s Algorithm ----') + +if __name__ == "__main__": + print("---- Computing minimal spanning tree using Kruskal's Algorithm ----") print() G, num_nodes = load_graph() - print(f'Our loaded graph is: {G}') + print(f"Our loaded graph is: {G}") print() MST, total_cost = kruskal(G) - print(f'Our minimum spanning tree is: {MST}') - print(f'Total cost is: {total_cost}') \ No newline at end of file + print(f"Our minimum spanning tree is: {MST}") + print(f"Total cost is: {total_cost}") diff --git a/Algorithms/graphtheory/prims/prim_heap.py b/Algorithms/graphtheory/prims/prim_heap.py index 03c9bbd..2167d82 100644 --- a/Algorithms/graphtheory/prims/prim_heap.py +++ b/Algorithms/graphtheory/prims/prim_heap.py @@ -1,4 +1,4 @@ -''' +""" Prims algorithm for finding minimal spanning tree (MST) of a graph. Optimized version using Heaps! If there is no MST because graph is disconnected then prim's algorithm will return the MST of the connected subgraph @@ -7,15 +7,16 @@ Aladdin Persson 2019-02-16 Initial programming 2020-03-29 Changed few lines to be able to handle empty graphs, etc, and changed how MST is computed (now correctly) -''' +""" import heapq -def load_graph(file='edges.txt'): + +def load_graph(file="edges.txt"): try: - f = open(file, 'r') + f = open(file, "r") except IOError: - raise("File does not exist!") + raise ("File does not exist!") line_list = f.readlines() @@ -23,13 +24,19 @@ def load_graph(file='edges.txt'): # We want to have edge cost first because the min heap will be based on edge cost # concretely that's why we do [::-1], a bit confusing maybe - G = {line: [tuple(map(int, tup.split()))[::-1] for tup in line_list[1:] - if (int(tup.split()[0]) == line or int(tup.split()[1]) == line)] - for line in range(1, int(num_nodes) + 1)} + G = { + line: [ + tuple(map(int, tup.split()))[::-1] + for tup in line_list[1:] + if (int(tup.split()[0]) == line or int(tup.split()[1]) == line) + ] + for line in range(1, int(num_nodes) + 1) + } f.close() return G + # Takes as input G which will have {node1: [(cost, to_node, node1), ...], node2:[(...)] } def prims_algo(G, start=1): if len(G) == 0: @@ -72,11 +79,12 @@ def prims_algo(G, start=1): return MST, tot_cost -if __name__ == '__main__': - print('---- Computing minimal spanning tree using Prims Algorithm ---- \n') + +if __name__ == "__main__": + print("---- Computing minimal spanning tree using Prims Algorithm ---- \n") G = load_graph() MST, tot_cost = prims_algo(G) - #print(f'The minimum spanning tree is: {MST}') - print(f'Total cost of minimum spanning tree is {tot_cost}') + # print(f'The minimum spanning tree is: {MST}') + print(f"Total cost of minimum spanning tree is {tot_cost}") diff --git a/Algorithms/graphtheory/prims/prim_naive.py b/Algorithms/graphtheory/prims/prim_naive.py index 2cc7dca..6b9304b 100644 --- a/Algorithms/graphtheory/prims/prim_naive.py +++ b/Algorithms/graphtheory/prims/prim_naive.py @@ -7,7 +7,8 @@ # Improvement: Want to implement using heap datastructure -def load_graph(path = 'edges.txt'): + +def load_graph(path="edges.txt"): edge_list = [] with open(path) as f: @@ -15,11 +16,12 @@ def load_graph(path = 'edges.txt'): num_nodes, num_edges = [int(i) for i in lines[0].split()] for line in lines[1:]: - node1,node2,edge_cost = [int(i) for i in line.split()] - edge_list.append( (node1,node2,edge_cost)) + node1, node2, edge_cost = [int(i) for i in line.split()] + edge_list.append((node1, node2, edge_cost)) return edge_list, num_nodes, num_edges + def prims_algo(edge_list, num_nodes): X = [] V = [i for i in range(1, num_nodes + 1)] @@ -31,7 +33,7 @@ def prims_algo(edge_list, num_nodes): V.remove(start) while len(V) != 0: - lowest_cost = float('inf') + lowest_cost = float("inf") nodeX = None nodeV = None @@ -57,11 +59,9 @@ def prims_algo(edge_list, num_nodes): return E, total_cost -if __name__ == '__main__': - print('Computing minimal spanning tree using Prims Algorithm') +if __name__ == "__main__": + print("Computing minimal spanning tree using Prims Algorithm") edge_list, num_nodes, num_edges = load_graph() E, tot_cost = prims_algo(edge_list, num_nodes) - - diff --git a/Algorithms/math/euclid_gcd/euclid_gcd.py b/Algorithms/math/euclid_gcd/euclid_gcd.py index 3a08b3e..12591d1 100644 --- a/Algorithms/math/euclid_gcd/euclid_gcd.py +++ b/Algorithms/math/euclid_gcd/euclid_gcd.py @@ -6,6 +6,7 @@ # Programmed by Aladdin Persson # 2019-02-19 Initial programming + def gcd_recursive(a, b): if b == 0: return a @@ -13,11 +14,12 @@ def gcd_recursive(a, b): return gcd_recursive(b, a % b) -def gcd_iterative(a,b): +def gcd_iterative(a, b): while b != 0: - a, b = b, a%b + a, b = b, a % b return a -if __name__ == '__main__': - print(gcd_iterative(65,14)) \ No newline at end of file + +if __name__ == "__main__": + print(gcd_iterative(65, 14)) diff --git a/Algorithms/math/extended_euclidean_algorithm/euclid_gcd.py b/Algorithms/math/extended_euclidean_algorithm/euclid_gcd.py index 22b7dcc..e456de1 100644 --- a/Algorithms/math/extended_euclidean_algorithm/euclid_gcd.py +++ b/Algorithms/math/extended_euclidean_algorithm/euclid_gcd.py @@ -1,19 +1,22 @@ -''' +""" -''' +""" import sys + sys.setrecursionlimit(100000) + def extended_euclidean(a, b): if a == 0: return (b, 0, 1) else: - gcd, x, y = extended_euclidean(b % a, a) - return (gcd, y - (b//a) * x, x) + gcd, x, y = extended_euclidean(b % a, a) + return (gcd, y - (b // a) * x, x) + -if __name__ == '__main__': - #print(extended_euclidean(5,-2772)) - print(extended_euclidean(1635, 26)) \ No newline at end of file +if __name__ == "__main__": + # print(extended_euclidean(5,-2772)) + print(extended_euclidean(1635, 26)) diff --git a/Algorithms/math/intersection_of_two_sets/intersection_of_two_sets.py b/Algorithms/math/intersection_of_two_sets/intersection_of_two_sets.py index cec55ce..d3ce2ae 100644 --- a/Algorithms/math/intersection_of_two_sets/intersection_of_two_sets.py +++ b/Algorithms/math/intersection_of_two_sets/intersection_of_two_sets.py @@ -1,4 +1,4 @@ -''' +""" Purpose is given two sets A,B find the intersection of them. I know there must be more efficients ways than what I, am doing here but havn't figured out how yet. @@ -7,36 +7,38 @@ Programmed by Aladdin Persson * 2019-03-13 Initial programming -''' +""" -def intersection(A,B): + +def intersection(A, B): # n = length of A, m = length of B # O(nlog(n) + mlog(n)) cost for sorting A = sorted(A) B = sorted(B) - i, j = 0,0 + i, j = 0, 0 AB_intersection = [] # complexity O(n+m) while i < len(A) and j < len(B): if A[i] < B[j]: - i+=1 + i += 1 elif B[j] < A[i]: - j+=1 + j += 1 elif A[i] == B[j]: AB_intersection.append(A[i]) - i+=1 - j+=1 + i += 1 + j += 1 return AB_intersection -if __name__ == '__main__': - A = [1,3,5,8,12] - B = [2,3,5,10,12] - intersection_AB = intersection(A,B) +if __name__ == "__main__": + A = [1, 3, 5, 8, 12] + B = [2, 3, 5, 10, 12] + + intersection_AB = intersection(A, B) print(intersection_AB) diff --git a/Algorithms/math/karatsuba/karatsuba.py b/Algorithms/math/karatsuba/karatsuba.py index d4d113b..e22e827 100644 --- a/Algorithms/math/karatsuba/karatsuba.py +++ b/Algorithms/math/karatsuba/karatsuba.py @@ -5,36 +5,38 @@ # import random to check if implementation is correct import random -def karatsuba(x,y): + +def karatsuba(x, y): # handle negative numbers multiplication if x < 0: - return -1 * karatsuba(-x,y) + return -1 * karatsuba(-x, y) if y < 0: - return -1 * karatsuba(x,-y) + return -1 * karatsuba(x, -y) # Base case (two numbers from 1-9 multiplication) if len(str(x)) == 1 or len(str(y)) == 1: - return (x*y) + return x * y n = max(len(str(x)), len(str(y))) # split about middle (can be done in multiple ways, found on github, thought was rly clever) - a = x // 10**(n // 2) - b = x % 10**(n // 2) - c = y // 10**(n // 2) - d = y % 10**(n // 2) + a = x // 10 ** (n // 2) + b = x % 10 ** (n // 2) + c = y // 10 ** (n // 2) + d = y % 10 ** (n // 2) # Compute the terms using recursion - ac = karatsuba(a,c) - bd = karatsuba(b,d) - ad_bc = karatsuba(a + b,c + d) - ac - bd + ac = karatsuba(a, c) + bd = karatsuba(b, d) + ad_bc = karatsuba(a + b, c + d) - ac - bd # calculate x * y - product = ac * (10**(2*(n//2))) + ad_bc * (10**(n // 2)) + bd + product = ac * (10 ** (2 * (n // 2))) + ad_bc * (10 ** (n // 2)) + bd # return x * y return product + # Following checks if implementation is correct # if __name__ == '__main__': # for _ in range(500): @@ -51,9 +53,9 @@ def karatsuba(x,y): # For Programming Assignment 1 -if __name__ == '__main__': +if __name__ == "__main__": x = 3141592653589793238462643383279502884197169399375105820974944592 y = 2718281828459045235360287471352662497757247093699959574966967627 - print(karatsuba(x,y)) - print(x*y) + print(karatsuba(x, y)) + print(x * y) diff --git a/Algorithms/math/pollard_p1/pollard_p1.py b/Algorithms/math/pollard_p1/pollard_p1.py index 89d032e..5124529 100644 --- a/Algorithms/math/pollard_p1/pollard_p1.py +++ b/Algorithms/math/pollard_p1/pollard_p1.py @@ -1,4 +1,4 @@ -''' +""" Purpose is given a number write it only as a factorization of primes. Time complexity: @@ -6,22 +6,24 @@ Programmed by Aladdin Persson * 2019-08-22 Initial programming -''' +""" from math import gcd + def pollard_p1(n): r = 2 - for i in range(2,100): - r = r**i % n + for i in range(2, 100): + r = r ** i % n if gcd(r - 1, n) != 1: - print('One factor found was: ' + str(gcd(r - 1,n))) - print('Number of iterations was: ' + str(i)) - return gcd(r - 1,n) + print("One factor found was: " + str(gcd(r - 1, n))) + print("Number of iterations was: " + str(i)) + return gcd(r - 1, n) print("No factorization was found") -if __name__ == '__main__': - pollard_p1(703425623) \ No newline at end of file + +if __name__ == "__main__": + pollard_p1(703425623) diff --git a/Algorithms/math/prime_factorization/primefactorization.py b/Algorithms/math/prime_factorization/primefactorization.py index c3299ac..1a0ea36 100644 --- a/Algorithms/math/prime_factorization/primefactorization.py +++ b/Algorithms/math/prime_factorization/primefactorization.py @@ -1,4 +1,4 @@ -''' +""" Purpose is given a number write it only as a factorization of primes. Time complexity: O(sqrt(n)) PSEUDO-POLYNOMIAL, actually exponential! @@ -8,13 +8,14 @@ * 2019-08-19 Noticed a bug when using. Should be correct now, but I need to implement more robust tests to be certain that this is a correct implementation. -''' +""" + def primefactorization(n): original_value = n values = [] - for i in range(2, int(n**0.5) + 1): + for i in range(2, int(n ** 0.5) + 1): # Will not pass this if statement if i is not a prime number. # (This is because all numbers have a prime factorization) if n % i == 0: @@ -24,11 +25,16 @@ def primefactorization(n): values.append(i) if len(values) != 0: - values.append(int(n)) # if we have found one factor <= sqrt(n), then there will be another factor. - print(f'Prime factorization of {original_value} is: {values}') + values.append( + int(n) + ) # if we have found one factor <= sqrt(n), then there will be another factor. + print(f"Prime factorization of {original_value} is: {values}") else: - print(f'There is no prime factorization because the number {original_value} is a prime') + print( + f"There is no prime factorization because the number {original_value} is a prime" + ) + -if __name__ == '__main__': - #primefactorization(2**2**6 + 1) - primefactorization(123) \ No newline at end of file +if __name__ == "__main__": + # primefactorization(2**2**6 + 1) + primefactorization(123) diff --git a/Algorithms/math/sieve_of_eratosthenes/sieve_eratosthenes.py b/Algorithms/math/sieve_of_eratosthenes/sieve_eratosthenes.py index 5779a75..2eac767 100644 --- a/Algorithms/math/sieve_of_eratosthenes/sieve_eratosthenes.py +++ b/Algorithms/math/sieve_of_eratosthenes/sieve_eratosthenes.py @@ -3,22 +3,24 @@ # Programmed by Aladdin Persson # 2019-02-27 Initial programming + def eratosthenes(n): - primes, sieve = [], [True] * (n+1) - sieve[0], sieve[1] = 'Zero', 'One' + primes, sieve = [], [True] * (n + 1) + sieve[0], sieve[1] = "Zero", "One" - for num in range(2,n+1): + for num in range(2, n + 1): if sieve[num]: primes.append(num) # "Optimized" loop here because we dont have to go up 1,2,3,4 in this # we can jump num instead - for i in range(num*num, n+1, num): + for i in range(num * num, n + 1, num): sieve[i] = False return primes -if __name__ == '__main__': - n = 10**6 + +if __name__ == "__main__": + n = 10 ** 6 primes = eratosthenes(n) print(primes) diff --git a/Algorithms/math/union_of_two_sets/union_of_two_sets.py b/Algorithms/math/union_of_two_sets/union_of_two_sets.py index 0c6625a..f9881cd 100644 --- a/Algorithms/math/union_of_two_sets/union_of_two_sets.py +++ b/Algorithms/math/union_of_two_sets/union_of_two_sets.py @@ -1,4 +1,4 @@ -''' +""" Purpose is given two sets A,B find the union of them. I know there must be more efficients ways than what I, am doing here but havn't figured out how yet. @@ -7,15 +7,16 @@ Programmed by Aladdin Persson * 2019-03-13 Initial programming -''' +""" -def union(A,B): + +def union(A, B): # n = length of A, m = length of B # O(nlog(n) + mlog(n)) cost for sorting A = sorted(A) B = sorted(B) - i, j = 0,0 + i, j = 0, 0 AB_union = [] @@ -23,25 +24,26 @@ def union(A,B): while i < len(A) and j < len(B): if A[i] < B[j]: AB_union.append(A[i]) - i+=1 + i += 1 elif B[j] < A[i]: AB_union.append(B[j]) - j+=1 + j += 1 elif A[i] == B[j]: AB_union.append(A[i]) - i+=1 - j+=1 + i += 1 + j += 1 AB_union.extend(A[i:]) AB_union.extend(B[j:]) return AB_union -if __name__ == '__main__': - A = [1,3,5,8,12] - B = [2,3,5,10,12] - AB_union = union(A,B) +if __name__ == "__main__": + A = [1, 3, 5, 8, 12] + B = [2, 3, 5, 10, 12] + + AB_union = union(A, B) print(AB_union) diff --git a/Algorithms/numerical_methods/bisection.py b/Algorithms/numerical_methods/bisection.py index 8c091bc..580f5d3 100644 --- a/Algorithms/numerical_methods/bisection.py +++ b/Algorithms/numerical_methods/bisection.py @@ -1,24 +1,27 @@ -''' +""" # Purpose of the bisection method is to find an interval where there exists a root # Programmed by Aladdin Persson # 2019-10-07 Initial programming -''' +""" + + def function(x): - #return (x**2 - 2) - return (x**2 + 2*x - 1) + # return (x**2 - 2) + return x ** 2 + 2 * x - 1 + def bisection(a0, b0, eps, delta, maxit): # Initialize search bracket s.t a <= b - alpha = min(a0,b0) - beta = max(a0,b0) + alpha = min(a0, b0) + beta = max(a0, b0) a = [] b = [] fa = function(alpha) fb = function(beta) - if function(alpha)*function(beta) > 0: + if function(alpha) * function(beta) > 0: print("Needs to have one f(a) > 0 and f(b) < 0") exit() @@ -27,13 +30,13 @@ def bisection(a0, b0, eps, delta, maxit): b.append(beta) # Carefully compute the midpoint in an effort to avoid numerical roundoff errors - midpoint = alpha + (beta - alpha)/2 + midpoint = alpha + (beta - alpha) / 2 fc = function(midpoint) # Check for small residual if abs(fc) <= eps: print("Very small function value -> we're close enough to a root") - return alpha,beta + return alpha, beta # check for small bracket if abs(beta - alpha) <= delta: @@ -41,22 +44,23 @@ def bisection(a0, b0, eps, delta, maxit): return alpha, beta # Now we know we need to run more iterations - if fa*fc < 0: + if fa * fc < 0: beta = midpoint fb = fc else: alpha = midpoint fa = fc - return alpha,beta + return alpha, beta + def main(): a = 0 b = 1 - #print(function(a)) - #print(function(b)) - alpha, beta = bisection(a,b,eps=1e-8,delta=1e-8, maxit=3) - print("Bracket is (" + str(alpha)+ ', ' + str(beta) + ')') + # print(function(a)) + # print(function(b)) + alpha, beta = bisection(a, b, eps=1e-8, delta=1e-8, maxit=3) + print("Bracket is (" + str(alpha) + ", " + str(beta) + ")") -main() +main() diff --git a/Algorithms/numerical_methods/fixpoint.py b/Algorithms/numerical_methods/fixpoint.py index 9e660e3..69b22c6 100644 --- a/Algorithms/numerical_methods/fixpoint.py +++ b/Algorithms/numerical_methods/fixpoint.py @@ -1,14 +1,14 @@ -''' +""" # Purpose of the fixpoint method is to solve equations of the form x = g(x) # Note that many equations can be rewritten in this form, to solve for example for roots. # Programmed by Aladdin Persson # 2019-10-07 Initial programming -''' +""" # Rewrite x^2 = 2 def function(x): - return (x + (2/x))/2 + return (x + (2 / x)) / 2 def fixpoint(x0, tol): @@ -21,9 +21,11 @@ def fixpoint(x0, tol): return y + def main(): x0 = 2 val = fixpoint(x0, tol=1e-8) print(val) + main() diff --git a/Algorithms/other/Huffman/Huffman.py b/Algorithms/other/Huffman/Huffman.py index 807374d..9573687 100644 --- a/Algorithms/other/Huffman/Huffman.py +++ b/Algorithms/other/Huffman/Huffman.py @@ -1,6 +1,7 @@ import heapq from bitarray import bitarray + class Node(object): def __init__(self, ch, freq, left=None, right=None): self.ch = ch @@ -11,9 +12,10 @@ def __init__(self, ch, freq, left=None, right=None): def __lt__(self, other): return self.freq < other.freq + def make_frequency_dict(file="huffman.txt"): - freq ={} - text = '' + freq = {} + text = "" with open(file) as f: for line in f: @@ -26,6 +28,7 @@ def make_frequency_dict(file="huffman.txt"): return freq, text + def make_heap(freq): heap = [] for char in freq: @@ -34,20 +37,21 @@ def make_heap(freq): return heap + def build_tree(heap): # Create our binary tree - while (len(heap) > 1): + while len(heap) > 1: nodeL = heapq.heappop(heap) nodeR = heapq.heappop(heap) - tot_freq = nodeL.freq+nodeR.freq + tot_freq = nodeL.freq + nodeR.freq - heapq.heappush(heap, Node('', tot_freq, nodeL, nodeR)) + heapq.heappush(heap, Node("", tot_freq, nodeL, nodeR)) return heap -def create_mapping(root, map={}, binarytext=''): +def create_mapping(root, map={}, binarytext=""): # Create a mapping from each character to a binary string if root == None: @@ -57,13 +61,14 @@ def create_mapping(root, map={}, binarytext=''): # if we are a leaf map[root.ch] = binarytext - left = create_mapping(root.left, map, binarytext+'0') - right = create_mapping(root.right, map, binarytext+'1') + left = create_mapping(root.left, map, binarytext + "0") + right = create_mapping(root.right, map, binarytext + "1") return map + def decode(binarystring, root): - decoded_msg = '' + decoded_msg = "" curr_node = root i = 0 @@ -73,43 +78,46 @@ def decode(binarystring, root): decoded_msg += str(curr_node.ch) curr_node = root - if i == len(binarystring): i += 1 + if i == len(binarystring): + i += 1 # If 1 walk right - elif binarystring[i] == '1': + elif binarystring[i] == "1": curr_node = curr_node.right i += 1 # If 0 walk left - elif binarystring[i] == '0': + elif binarystring[i] == "0": curr_node = curr_node.left i += 1 return decoded_msg + def main(): freq, text = make_frequency_dict(file="Huffman.txt") - #print(f"Our message that we wish to decompress using Huffman is: \n{text}") + # print(f"Our message that we wish to decompress using Huffman is: \n{text}") heap = make_heap(freq) tree = build_tree(heap) mapping = create_mapping(tree[0]) - print(f'Our mapping is: \n{mapping}') + print(f"Our mapping is: \n{mapping}") # Get encoded message - encoded = '' + encoded = "" for letter in text: encoded += mapping[letter] - print(f'Our encoded message is: \n{encoded}') + print(f"Our encoded message is: \n{encoded}") out = bitarray(encoded) - with open('compressed_file.bin', 'wb') as f: + with open("compressed_file.bin", "wb") as f: out.tofile(f) - #original_text = decode(encoded, tree[0]) + # original_text = decode(encoded, tree[0]) + -if __name__ == '__main__': - main() \ No newline at end of file +if __name__ == "__main__": + main() diff --git a/Algorithms/other/Kadanes_algorithm.py b/Algorithms/other/Kadanes_algorithm.py index 2fc6abc..304bb8f 100644 --- a/Algorithms/other/Kadanes_algorithm.py +++ b/Algorithms/other/Kadanes_algorithm.py @@ -1,4 +1,4 @@ -''' +""" Purpose of the Kadane's Algorithm is to the find the sum of the maximum contigous subarray of an array. Ex: [-2,1,-3,4,-1,2,1,-5,4] has [4,-1,2,1] with the largest sum = 6 @@ -6,18 +6,19 @@ Programmed by Aladdin Persson # 2020-03-08 Initial programming -''' +""" + def kadane_algorithm(array): max_current, max_global = array[0], array[0] - + for val in array[1:]: max_current = max(val, max_current + val) - + if max_current > max_global: max_global = max_current - + return max_global -print(kadane_algorithm([-2,1,-3,4,-1,2,1,-5,4])) - + +print(kadane_algorithm([-2, 1, -3, 4, -1, 2, 1, -5, 4])) diff --git a/Algorithms/other/binarysearch.py b/Algorithms/other/binarysearch.py index 651880b..ba1cdcd 100644 --- a/Algorithms/other/binarysearch.py +++ b/Algorithms/other/binarysearch.py @@ -1,11 +1,11 @@ -''' +""" Purpose of this is to find a target element in an already sorted list L. We use the fact that it is already sorted and get a O(log(n)) search algorithm. Programmed by Aladdin Persson # 2019-03-12 Initial programming -''' +""" def binarysearch_iterative(L, target): @@ -13,7 +13,7 @@ def binarysearch_iterative(L, target): high = len(L) - 1 while low <= high: - middle = (low+high)//2 + middle = (low + high) // 2 if target == L[middle]: return True, middle @@ -26,8 +26,9 @@ def binarysearch_iterative(L, target): return False, None + def binarysearch_recursive(L, target, low, high): - middle = (low+high)//2 + middle = (low + high) // 2 if low > high: return False, None @@ -36,20 +37,18 @@ def binarysearch_recursive(L, target, low, high): return True, middle elif target < L[middle]: - return binarysearch_recursive(L, target, low, middle-1) + return binarysearch_recursive(L, target, low, middle - 1) else: - return binarysearch_recursive(L, target, middle+1, high) - + return binarysearch_recursive(L, target, middle + 1, high) -if __name__ == '__main__': +if __name__ == "__main__": target = 1 - sorted_array = [1,1,1,1,1,1,1,1] + sorted_array = [1, 1, 1, 1, 1, 1, 1, 1] exists, idx = binarysearch_iterative(sorted_array, target) - print(f'The target {target} exists in array: {exists}. The idx of it is: {idx}') - - exists, idx = binarysearch_recursive(sorted_array, target, 0, len(sorted_array)-1) - print(f'The target {target} exists in array: {exists}. The idx of it is: {idx}') + print(f"The target {target} exists in array: {exists}. The idx of it is: {idx}") + exists, idx = binarysearch_recursive(sorted_array, target, 0, len(sorted_array) - 1) + print(f"The target {target} exists in array: {exists}. The idx of it is: {idx}") diff --git a/Algorithms/other/counting_inversions.py b/Algorithms/other/counting_inversions.py index e14600a..ce0f870 100644 --- a/Algorithms/other/counting_inversions.py +++ b/Algorithms/other/counting_inversions.py @@ -1,16 +1,17 @@ def merge_sort(array): total_inversions = 0 if len(array) <= 1: - return (array,0) + return (array, 0) midpoint = int(len(array) / 2) (left, left_inversions) = merge_sort(array[:midpoint]) (right, right_inversions) = merge_sort(array[midpoint:]) (merged_array, merge_inversions) = merge_and_count(left, right) - + return (merged_array, left_inversions + right_inversions + merge_inversions) + def merge_and_count(left, right): count_inversions = 0 result = [] @@ -24,7 +25,7 @@ def merge_and_count(left, right): left_pointer += 1 elif right[right_pointer] < left[left_pointer]: - count_inversions += (left_len - left_pointer) + count_inversions += left_len - left_pointer result.append(right[right_pointer]) right_pointer += 1 @@ -33,6 +34,7 @@ def merge_and_count(left, right): return (result, count_inversions) + if __name__ == "__main__": array = [9, 2, 1, 5, 2, 3, 5, 1, 2, 32, 12, 11] print(array) diff --git a/Algorithms/other/interval_scheduling.py b/Algorithms/other/interval_scheduling.py index 67d6381..d02adc9 100644 --- a/Algorithms/other/interval_scheduling.py +++ b/Algorithms/other/interval_scheduling.py @@ -7,6 +7,7 @@ # Video: https://youtu.be/SmPxC8m0yIY + def interval_scheduling(R, O): R.sort(key=lambda x: x[1]) # sort by finish times f1 <= f2 <= ... <= fn @@ -20,6 +21,7 @@ def interval_scheduling(R, O): return O + # def interval_scheduling_complicated_version(R, O): # while R: # keep going while R still has elements # (si, fi) = R[0] @@ -36,7 +38,7 @@ def interval_scheduling(R, O): # idx += 1 # return O -if __name__ == '__main__': +if __name__ == "__main__": # run small example # request is: (start, end) r1 = (0, 3) @@ -48,8 +50,8 @@ def interval_scheduling(R, O): r7 = (5, 10) r8 = (8, 10) - R = [r1,r2,r3,r4,r5,r6,r7,r8] + R = [r1, r2, r3, r4, r5, r6, r7, r8] O = [] O = interval_scheduling(R, O) - print('The intervals to choose are: ' + str(O)) \ No newline at end of file + print("The intervals to choose are: " + str(O)) diff --git a/Algorithms/other/median_maintenance.py b/Algorithms/other/median_maintenance.py index 31b4669..2d53127 100644 --- a/Algorithms/other/median_maintenance.py +++ b/Algorithms/other/median_maintenance.py @@ -14,13 +14,14 @@ import heapq + class Maintain_Median(object): def __init__(self): self.maxheap = [] self.minheap = [] def medmain_insert(self, x): - if (len(self.maxheap) == 0): + if len(self.maxheap) == 0: heapq.heappush(self.maxheap, -x) else: @@ -39,8 +40,11 @@ def medmain_insert(self, x): y = -heapq.heappop(self.maxheap) heapq.heappush(self.minheap, y) - return (-self.maxheap[0] + self.minheap[0])/2 if len(self.maxheap) == len(self.minheap) else -self.maxheap[0] - + return ( + (-self.maxheap[0] + self.minheap[0]) / 2 + if len(self.maxheap) == len(self.minheap) + else -self.maxheap[0] + ) def main(self, data): if len(data) < 1: @@ -51,8 +55,9 @@ def main(self, data): return median -if __name__ == '__main__': + +if __name__ == "__main__": data = [1, 3, 8, 5, 10] maintain_median = Maintain_Median() median = maintain_median.main(data) - print(median) \ No newline at end of file + print(median) diff --git a/Algorithms/sorting/bubblesort.py b/Algorithms/sorting/bubblesort.py index 6f27ff9..625c80c 100644 --- a/Algorithms/sorting/bubblesort.py +++ b/Algorithms/sorting/bubblesort.py @@ -1,11 +1,12 @@ -''' +""" Bubblesort sorting algorithm. This is not a very efficient sorting algorithm, T(n) = O(n^2). Programmed by Aladdin Persson * 2019-01-23 Initial code * 2019-03-05 Improved code by having swapped, while-loop and raise error -''' +""" + def bubblesort(L): swapped = True @@ -14,12 +15,13 @@ def bubblesort(L): swapped = False for j in range(len(L) - 1): - if L[j] > L[j+1]: - L[j], L[j + 1] = L[j+1], L[j] + if L[j] > L[j + 1]: + L[j], L[j + 1] = L[j + 1], L[j] swapped = True return L -if __name__ == '__main__': - unsorted = [5,2,4,6,1,3] + +if __name__ == "__main__": + unsorted = [5, 2, 4, 6, 1, 3] sorted = bubblesort(unsorted) - print(sorted) \ No newline at end of file + print(sorted) diff --git a/Algorithms/sorting/hopesort.py b/Algorithms/sorting/hopesort.py index 567b455..c265b19 100644 --- a/Algorithms/sorting/hopesort.py +++ b/Algorithms/sorting/hopesort.py @@ -1,18 +1,20 @@ -''' +""" Hopesort algorithm. If it works, then it works in constant time. Use at own risk :) Programmed by Aladdin Persson * 2019-03-08 Initial code -''' +""" + def hopesort(L): # hope it is sorted return L -if __name__ == '__main__': - unsorted = [1,2,3,4,5,6] + +if __name__ == "__main__": + unsorted = [1, 2, 3, 4, 5, 6] # constant time hopefully_sorted = hopesort(unsorted) - print(hopefully_sorted) \ No newline at end of file + print(hopefully_sorted) diff --git a/Algorithms/sorting/insertionsort.py b/Algorithms/sorting/insertionsort.py index 7fa76fb..d466e2d 100644 --- a/Algorithms/sorting/insertionsort.py +++ b/Algorithms/sorting/insertionsort.py @@ -1,10 +1,11 @@ -''' +""" Insertion sort algorithm O(n^2). Programmed by Aladdin Persson * 2019-01-23 Initial programming * 2019-03-05 Made code cleaner -''' +""" + def insertionsort(L): # loop through all except first element in list @@ -15,7 +16,7 @@ def insertionsort(L): # inserts the key into the correct place while position >= 0 and L[position] > value: - L[position+1] = L[position] + L[position + 1] = L[position] position -= 1 L[position + 1] = value @@ -23,7 +24,7 @@ def insertionsort(L): return L -if __name__ == '__main__': - unsorted = [7,2,4,1,5,3] +if __name__ == "__main__": + unsorted = [7, 2, 4, 1, 5, 3] sorted = insertionsort(unsorted) - print(sorted) \ No newline at end of file + print(sorted) diff --git a/Algorithms/sorting/mergesort.py b/Algorithms/sorting/mergesort.py index 4989f6d..3a87d26 100644 --- a/Algorithms/sorting/mergesort.py +++ b/Algorithms/sorting/mergesort.py @@ -9,6 +9,7 @@ def merge_sort(array): return merge(left, right) + def merge(left, right): result = [] left_pointer = right_pointer = 0 @@ -18,7 +19,7 @@ def merge(left, right): result.append(left[left_pointer]) left_pointer += 1 - elif right[right_pointer] < left[left_pointer] : + elif right[right_pointer] < left[left_pointer]: result.append(right[right_pointer]) right_pointer += 1 @@ -27,6 +28,7 @@ def merge(left, right): return result + # if __name__ == "__main__": # array = [5, 4, 3, 2, 1] # print(array) diff --git a/Algorithms/sorting/quicksort.py b/Algorithms/sorting/quicksort.py index c966db9..6d2ee26 100644 --- a/Algorithms/sorting/quicksort.py +++ b/Algorithms/sorting/quicksort.py @@ -1,5 +1,6 @@ # Quicksort with pivot always using first index as pivot + def quicksort_firstpivot(L): if len(L) <= 1: return L @@ -10,17 +11,18 @@ def quicksort_firstpivot(L): for j in range(1, len(L)): if L[j] < pivot: - L[j], L[i+1] = L[i+1], L[j] + L[j], L[i + 1] = L[i + 1], L[j] i += 1 L[0], L[i] = L[i], L[0] left = quicksort_firstpivot(L[:i]) - right = quicksort_firstpivot(L[i+1:]) + right = quicksort_firstpivot(L[i + 1 :]) left.append(L[i]) result = left + right return result + # Quicksort with pivot always using last index as pivot def quicksort_lastpivot(x): if len(x) <= 1: @@ -33,14 +35,14 @@ def quicksort_lastpivot(x): for j in range(1, len(x)): if x[j] < pivot: - x[j], x[i+1] = x[i+1], x[j] + x[j], x[i + 1] = x[i + 1], x[j] i += 1 x[0], x[i] = x[i], x[0] left = quicksort_lastpivot(x[:i]) - right = quicksort_lastpivot(x[i+1:]) + right = quicksort_lastpivot(x[i + 1 :]) left.append(x[i]) result = left + right - return result \ No newline at end of file + return result diff --git a/Algorithms/sorting/randomized_quicksort.py b/Algorithms/sorting/randomized_quicksort.py index 75e58fd..e47aa47 100644 --- a/Algorithms/sorting/randomized_quicksort.py +++ b/Algorithms/sorting/randomized_quicksort.py @@ -1,4 +1,4 @@ -''' +""" Purpose is to sort a list. The reason why randomizing is better is that on average, regardless on the input randomized quicksort will have a running time of O(n*logn). This is regardless of the ordering of the inputted list. This is in constrast to first pivot, median pivot, etc Quicksort. @@ -6,16 +6,17 @@ Programmed by Aladdin Persson * 2019-03-08 Initial programming -''' +""" import random + def quicksort_randomized(L): if len(L) <= 1: return L # Randomly choose a pivot idx - pivot_idx = random.randint(0, len(L)-1) + pivot_idx = random.randint(0, len(L) - 1) pivot = L[pivot_idx] # Swap pivot_idx to the first position @@ -25,20 +26,21 @@ def quicksort_randomized(L): # range(1, len(L)) because we the pivot element is the first element for j in range(1, len(L)): if L[j] < pivot: - L[j], L[i+1] = L[i+1], L[j] + L[j], L[i + 1] = L[i + 1], L[j] i += 1 L[0], L[i] = L[i], L[0] left = quicksort_randomized(L[:i]) - right = quicksort_randomized(L[i + 1:]) + right = quicksort_randomized(L[i + 1 :]) left.append(L[i]) result = left + right return result -if __name__ == '__main__': - l = [6,7,3,4,5,1,3,7,123] + +if __name__ == "__main__": + l = [6, 7, 3, 4, 5, 1, 3, 7, 123] sorted_l = quicksort_randomized(l) - print(sorted_l) \ No newline at end of file + print(sorted_l) diff --git a/Algorithms/sorting/selectionsort.py b/Algorithms/sorting/selectionsort.py index c3f3f8e..8d3aa5a 100644 --- a/Algorithms/sorting/selectionsort.py +++ b/Algorithms/sorting/selectionsort.py @@ -1,10 +1,10 @@ -''' +""" Selection sort algorithm. T(n) = O(n^2) Programmed by Aladdin Persson * 2019-03-05 Initial coding -''' +""" # Selection sort that creates a copy. More "intuitive" but requires extra memory. def selectionsort_intuitive(L): @@ -14,7 +14,7 @@ def selectionsort_intuitive(L): min = L[0] for element in L: - min=element if element < min else min + min = element if element < min else min correctly_sorted.append(min) L.remove(min) @@ -23,11 +23,11 @@ def selectionsort_intuitive(L): def selectionsort(L): - for i in range(len(L)-1): + for i in range(len(L) - 1): min_index = i # Look through entire list, look which is the smallest element - for j in range(i+1, len(L)): + for j in range(i + 1, len(L)): if L[j] < L[min_index]: min_index = j @@ -37,7 +37,8 @@ def selectionsort(L): return L -if __name__ == '__main__': - unsorted = [10000,2,7,4,1,5,3,15,13,169] + +if __name__ == "__main__": + unsorted = [10000, 2, 7, 4, 1, 5, 3, 15, 13, 169] sorted = selectionsort_intuitive(unsorted) - print(sorted) \ No newline at end of file + print(sorted) diff --git a/setup.py b/setup.py index 3a0453e..331b2bb 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,9 @@ from distutils.core import setup setup( - name='Algorithms', - packages=['Algorithm_test'], - version='0.0.7', - description='Testing Algorithm Collection', - url='https://github.com/AladdinPerzon/Algorithms-Collection-Python', + name="Algorithms", + packages=["Algorithm_test"], + version="0.0.7", + description="Testing Algorithm Collection", + url="https://github.com/AladdinPerzon/Algorithms-Collection-Python", ) From ca8067abe7715355a34410778a809685aa70e06a Mon Sep 17 00:00:00 2001 From: gilip Date: Fri, 28 Aug 2020 00:43:06 +0300 Subject: [PATCH 57/60] Heuristic solver for tsp --- Algorithm_tests/graphtheory_tests/test_NN.py | 69 ++++++++++ .../NearestNeighborTSP.py | 126 ++++++++++++++++++ .../nearest-neighbor-tsp/graph.txt | 9 ++ 3 files changed, 204 insertions(+) create mode 100644 Algorithm_tests/graphtheory_tests/test_NN.py create mode 100644 Algorithms/graphtheory/nearest-neighbor-tsp/NearestNeighborTSP.py create mode 100644 Algorithms/graphtheory/nearest-neighbor-tsp/graph.txt diff --git a/Algorithm_tests/graphtheory_tests/test_NN.py b/Algorithm_tests/graphtheory_tests/test_NN.py new file mode 100644 index 0000000..ad8322f --- /dev/null +++ b/Algorithm_tests/graphtheory_tests/test_NN.py @@ -0,0 +1,69 @@ +import unittest +import sys + +# Import from different folder +sys.path.append("Algorithms/graphtheory/nearest-neighbor-tsp/") + +import NearestNeighborTSP + + +class TestNN(unittest.TestCase): + def setUp(self): + self.G1 = [[0,3,-1],[3,0,1],[-1,1,0]] + self.correct_path1 = [0,1,2,0] + + # No possible solution for this one so its a dead end + self.G2 = [[0, 2, -1,-1,-1], [2, 0,5,1,-1], [-1, 5, 0, -1, -1],[-1, 1, -1, 0, 3], [-1, -1, -1, 3, 0]] + self.correct_path2 = [0,1,3,4] + + # No possible solution for this one so its a dead end + self.G3 = [[0, 2, -1,-1,-1], [2, 0,5,1,-1], [-1, 5, 0, -1, -1],[-1, 1, -1, 0, -1], [-1, -1, -1, -1, 0]] + self.correct_path3 = [0, 1, 3] + + # Multiple possible solutions + self.G4 = [[0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0]] + self.correct_path4 = [0, 1, 2, 3, 0] + + + # adjacency matrix of a graph for testing + adjMatrix = [[0,2,5,-1,3],[2,0,2,4,-1],[5,2,0,5,5],[-1,4,5,0,2],[3,-1,5,2,0]] + # correct rank of each node's neighbors + correctNeighbors = [[1,4,2],[0,2,3],[1,0,3,4],[4,1,2],[3,0,2]] + + + def test_0_rankNeighbors(self): + for i in range(0,4): + self.assertEqual(NearestNeighborTSP.rankNeighbors(i, self.adjMatrix), self.correctNeighbors[i], "Check if order is different.") + + + def test_1_nnTSP(self): + path=NearestNeighborTSP.nnTSP(self.adjMatrix) + # Test if path is null + self.assertIsNotNone(path,"Output is empty") + # Test if path is not complete + self.assertEqual(len(path),len(self.adjMatrix)+1,"Path in incomplete") + + + def test_linear_graph(self): + #print(NearestNeighbor.nnTSP(self.G2)) + path = NearestNeighborTSP.nnTSP(self.G1) + self.assertEqual(path,self.correct_path1) + + + def test_simple_graph(self): + path = NearestNeighborTSP.nnTSP(self.G2) + self.assertEqual(path,self.correct_path2) + + + def test_disconnected_graph(self): + path = NearestNeighborTSP.nnTSP(self.G3) + self.assertEqual(path, self.correct_path3) + + + def test_complete_graph(self): + path = NearestNeighborTSP.nnTSP(self.G4) + self.assertEqual(path, self.correct_path4) + +if __name__ == '__main__': + print("Running Nearest Neighbor TSP solver tests:") + unittest.main() \ No newline at end of file diff --git a/Algorithms/graphtheory/nearest-neighbor-tsp/NearestNeighborTSP.py b/Algorithms/graphtheory/nearest-neighbor-tsp/NearestNeighborTSP.py new file mode 100644 index 0000000..fc6b658 --- /dev/null +++ b/Algorithms/graphtheory/nearest-neighbor-tsp/NearestNeighborTSP.py @@ -0,0 +1,126 @@ +""" +Author: Philip Andreadis +e-mail: philip_andreadis@hotmail.com + + This script implements a simple heuristic solver for the Traveling Salesman Problem. + It is not guaranteed that an optimal solution will be found. + + Format of input text file must be as follows: + 1st line - number of nodes + each next line is an edge and its respective weight + + The program is executed via command line with the graph in the txt format as input. + +""" + +import time +import sys + + + +""" +This function reads the text file and returns a 2d list which represents +the adjacency matrix of the given graph +""" +def parseGraph(path): + # Read number of vertices and create adjacency matrix + f = open(path, "r") + n = int(f.readline()) + adjMatrix = [[-1 for i in range(n)] for j in range(n)] + #Fill adjacency matrix with the correct edges + for line in f: + edge = line.split(" ") + edge = list(map(int, edge)) + adjMatrix[edge[0]][edge[1]] = edge[2] + adjMatrix[edge[1]][edge[0]] = edge[2] + for i in range(len(adjMatrix)): + adjMatrix[i][i] = 0 + return adjMatrix + + + +""" +Returns all the neighboring nodes of a node sorted based on the distance between them. +""" +def rankNeighbors(node,adj): + sortednn = {} + nList = [] + for i in range(len(adj[node])): + if adj[node][i]>0: + sortednn[i] = adj[node][i] + sortednn = {k: v for k, v in sorted(sortednn.items(), key=lambda item: item[1])} + nList = list(sortednn.keys()) + return nList + + +""" +Function implementing the logic of nearest neighbor TSP. +Generate two lists a and b, placing the starting node in list a and the rest in list b. +While b is not empty append to a the closest neighboring node of the last node in a and remove it from b. +Repeat until a full path has been added to a and b is empty. +Returns list a representing the shortest path of the graph. +""" +def nnTSP(adj): + nodes = list(range(0, len(adj))) + #print(nodes) + weight = 0 + global length + # Starting node is 0 + a = [] + a.append(nodes[0]) + b = nodes[1:] + while b: + # Take last placed node in a + last = a[-1] + # Find its nearest neighbor + sortedNeighbors = rankNeighbors(last,adj) + # If node being checked has no valid neighbors and the path is not complete a dead end is reached + if (not sortedNeighbors) and len(a) Date: Sat, 30 Jan 2021 21:53:34 +0100 Subject: [PATCH 58/60] changed setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 331b2bb..4369946 100644 --- a/setup.py +++ b/setup.py @@ -5,5 +5,5 @@ packages=["Algorithm_test"], version="0.0.7", description="Testing Algorithm Collection", - url="https://github.com/AladdinPerzon/Algorithms-Collection-Python", + url="https://github.com/aladdinpersson/Algorithms-Collection-Python", ) From 74006c85daf4c213b65a801c3b8b4175673a8c4e Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 30 Jan 2021 22:01:28 +0100 Subject: [PATCH 59/60] updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ed6c6b..597b286 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPerzon/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![codecov](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python/branch/master/graph/badge.svg)](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python) +[![Build Status](https://travis-ci.com/AladdinPersson/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPersson/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![codecov](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python/branch/master/graph/badge.svg)](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python) # Algorithms Collection Python Whenever I face an interesting problem I document the algorithm that I learned to solve it. The goals of this repository is to have clean, efficient and most importantly correct code. From 266e5608b0c3558c3738ab749e27329010cd9fd6 Mon Sep 17 00:00:00 2001 From: Aladdin Persson Date: Sat, 30 Jan 2021 22:02:13 +0100 Subject: [PATCH 60/60] updated readme --- README.md | 86 +++++++++++++++++++++++++++---------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 597b286..115182e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.com/AladdinPersson/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPersson/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![codecov](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python/branch/master/graph/badge.svg)](https://codecov.io/gh/AladdinPerzon/Algorithms-Collection-Python) +[![Build Status](https://travis-ci.com/AladdinPersson/Algorithms-Collection-Python.svg?branch=master)](https://travis-ci.com/AladdinPersson/Algorithms-Collection-Python) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![codecov](https://codecov.io/gh/aladdinpersson/Algorithms-Collection-Python/branch/master/graph/badge.svg)](https://codecov.io/gh/aladdinpersson/Algorithms-Collection-Python) # Algorithms Collection Python Whenever I face an interesting problem I document the algorithm that I learned to solve it. The goals of this repository is to have clean, efficient and most importantly correct code. @@ -7,64 +7,64 @@ Whenever I face an interesting problem I document the algorithm that I learned t :small_red_triangle:: If the algorithm is untested # Dynamic Programming -* :white_check_mark: [Knapsack 0/1](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py) **- O(nC) Bottom-Up implementation (Loops)** -* :white_check_mark: [:movie_camera:](https://youtu.be/XmyxiSc3LKg)[Sequence Alignment](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/sequence_alignment.py) **- O(nm)** -* :white_check_mark: [:movie_camera:](https://youtu.be/dU-coYsd7zw)[Weighted Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/weighted_interval_scheduling.py) **- O(nlog(n))** +* :white_check_mark: [Knapsack 0/1](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/knapsack/knapsack_bottomup.py) **- O(nC) Bottom-Up implementation (Loops)** +* :white_check_mark: [:movie_camera:](https://youtu.be/XmyxiSc3LKg)[Sequence Alignment](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/sequence_alignment.py) **- O(nm)** +* :white_check_mark: [:movie_camera:](https://youtu.be/dU-coYsd7zw)[Weighted Interval Scheduling](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/dynamic_programming/weighted_interval_scheduling.py) **- O(nlog(n))** # Graph theory -* :white_check_mark: [Kahns Topological Sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py) **- O(n + m)** -* :white_check_mark: [Bellman-Ford Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/bellman-ford/bellman_ford.py) **- O(mn)** -* :small_red_triangle: [Floyd-Warshall Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py) **- O(n3)** -* :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/dijkstra.py) **- Naive implementation** -* :white_check_mark: [Dijkstra Shortest Path](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/heapdijkstra.py) **- O(mlog(n)) - Heap implementation** -* :small_red_triangle: [Karger's Minimum cut](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kargers/kargermincut.py) -* :small_red_triangle: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prim_naive.py) **- O(mn) Naive implementation** -* :white_check_mark: [Prim's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prim_heap.py) **- O(mlog(n)) Heap implementation** -* :small_red_triangle: [Kruskal's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal.py) **- O(mn) implementation** -* :white_check_mark: [Kruskal's Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal_unionfind.py) **- O(mlog(n))** -* :white_check_mark: [Breadth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py) **- O(n + m) - Queue Implementation** -* :white_check_mark: [Depth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py) **- O(n + m) - Stack Implementation** -* :white_check_mark: [Depth First Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_recursive.py) **- O(n + m) - Recursive Implementation** +* :white_check_mark: [Kahns Topological Sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kahns-toposort/kahn_topological_ordering.py) **- O(n + m)** +* :white_check_mark: [Bellman-Ford Shortest Path](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/bellman-ford/bellman_ford.py) **- O(mn)** +* :small_red_triangle: [Floyd-Warshall Shortest Path](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/floyd-warshall/floyd-warshall.py) **- O(n3)** +* :white_check_mark: [Dijkstra Shortest Path](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/dijkstra.py) **- Naive implementation** +* :white_check_mark: [Dijkstra Shortest Path](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/dijkstra/heapdijkstra.py) **- O(mlog(n)) - Heap implementation** +* :small_red_triangle: [Karger's Minimum cut](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kargers/kargermincut.py) +* :small_red_triangle: [Prim's Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prim_naive.py) **- O(mn) Naive implementation** +* :white_check_mark: [Prim's Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/prims/prim_heap.py) **- O(mlog(n)) Heap implementation** +* :small_red_triangle: [Kruskal's Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal.py) **- O(mn) implementation** +* :white_check_mark: [Kruskal's Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/kruskal/kruskal_unionfind.py) **- O(mlog(n))** +* :white_check_mark: [Breadth First Search](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/breadth-first-search/BFS_queue_iterative.py) **- O(n + m) - Queue Implementation** +* :white_check_mark: [Depth First Search](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_stack_iterative.py) **- O(n + m) - Stack Implementation** +* :white_check_mark: [Depth First Search](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/graphtheory/depth-first-search/DFS_recursive.py) **- O(n + m) - Recursive Implementation** # Mathematics ### Algebra -* :small_red_triangle: [Karatsuba Multiplication](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/karatsuba/karatsuba.py) **- O(n1.585)** -* :white_check_mark: [Intersection of two sets](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/intersection_of_two_sets/intersection_of_two_sets.py) **- O(nlog(n)) + O(mlog(m))** -* :white_check_mark: [Union of two sets](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/union_of_two_sets/union_of_two_sets.py) **- O(nlog(n)) + O(mlog(m))** +* :small_red_triangle: [Karatsuba Multiplication](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/karatsuba/karatsuba.py) **- O(n1.585)** +* :white_check_mark: [Intersection of two sets](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/intersection_of_two_sets/intersection_of_two_sets.py) **- O(nlog(n)) + O(mlog(m))** +* :white_check_mark: [Union of two sets](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/union_of_two_sets/union_of_two_sets.py) **- O(nlog(n)) + O(mlog(m))** ### Number Theory -* :small_red_triangle: [Pollard p-1 factorization](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/pollard_p1/pollard_p1.py) -* :small_red_triangle: [Euclidean Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/euclid_gcd/euclid_gcd.py) **- O(log(n))** -* :small_red_triangle: [Extended Euclidean Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/extended_euclidean_algorithm/euclid_gcd.py) **- O(log(n))** -* :small_red_triangle: [Sieve of Eratosthenes](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/sieve_of_eratosthenes/sieve_eratosthenes.py) **- O(nlog(log(n)))** -* :small_red_triangle: [Prime factorization](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/math/prime_factorization/primefactorization.py) **- O(sqrt(n))** +* :small_red_triangle: [Pollard p-1 factorization](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/pollard_p1/pollard_p1.py) +* :small_red_triangle: [Euclidean Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/euclid_gcd/euclid_gcd.py) **- O(log(n))** +* :small_red_triangle: [Extended Euclidean Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/extended_euclidean_algorithm/euclid_gcd.py) **- O(log(n))** +* :small_red_triangle: [Sieve of Eratosthenes](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/sieve_of_eratosthenes/sieve_eratosthenes.py) **- O(nlog(log(n)))** +* :small_red_triangle: [Prime factorization](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/math/prime_factorization/primefactorization.py) **- O(sqrt(n))** ### Cryptography -* :white_check_mark: [Ceasar Cipher](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py) -* :small_red_triangle: [Hill Cipher](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/hill_cipher/hill_cipher.py) -* :small_red_triangle: [Vigenere Cipher](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/vigenere_cipher/vigenere.py)* -* :small_red_triangle: [One time pad](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/one_time_pad/one_time_pad.py) -* :small_red_triangle: [RSA-Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/RSA_algorithm/RSA.py) +* :white_check_mark: [Ceasar Cipher](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/ceasar_shifting_cipher/ceasar_shift_cipher.py) +* :small_red_triangle: [Hill Cipher](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/hill_cipher/hill_cipher.py) +* :small_red_triangle: [Vigenere Cipher](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/vigenere_cipher/vigenere.py)* +* :small_red_triangle: [One time pad](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/one_time_pad/one_time_pad.py) +* :small_red_triangle: [RSA-Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/cryptology/RSA_algorithm/RSA.py) ### Numerical Methods -* :small_red_triangle: [Bisection Method](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/numerical_methods/bisection.py) -* :small_red_triangle: [(simple) Fixpoint iteration](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/numerical_methods/fixpoint.py) +* :small_red_triangle: [Bisection Method](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/numerical_methods/bisection.py) +* :small_red_triangle: [(simple) Fixpoint iteration](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/numerical_methods/fixpoint.py) # Other -* :white_check_mark: [Maintaining Median](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/median_maintenance.py) **- O(nlog(n))** -* :small_red_triangle: [Huffman Algorithm](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/Huffman/Huffman.py) -* :white_check_mark: [:movie_camera:](https://youtu.be/SmPxC8m0yIY)[Interval Scheduling](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/interval_scheduling.py) **- O(nlog(n))** -* :white_check_mark: [Binary Search](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/other/binarysearch.py) **- O(log(n))** +* :white_check_mark: [Maintaining Median](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/other/median_maintenance.py) **- O(nlog(n))** +* :small_red_triangle: [Huffman Algorithm](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/other/Huffman/Huffman.py) +* :white_check_mark: [:movie_camera:](https://youtu.be/SmPxC8m0yIY)[Interval Scheduling](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/other/interval_scheduling.py) **- O(nlog(n))** +* :white_check_mark: [Binary Search](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/other/binarysearch.py) **- O(log(n))** # Sorting algorithms -* :white_check_mark: [Bubble sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/bubblesort.py) **- O(n2)** -* :small_red_triangle: [Hope sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/hopesort.py) **- O(1), hopefully** -* :white_check_mark: [Insertion sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/insertionsort.py) **- O(n2)** -* :white_check_mark: [Selection sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/selectionsort.py) **- O(n2)** -* :white_check_mark: [Merge sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/mergesort.py) **- O(nlog(n))** -* :white_check_mark: [Randomized Quick sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/randomized_quicksort.py) **- Average O(nlogn) (Input independent!)** -* :white_check_mark: [Quick sort](https://github.com/AladdinPerzon/Algorithms-Collection-Python/blob/master/Algorithms/sorting/quicksort.py) **- Average O(nlog(n))** +* :white_check_mark: [Bubble sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/bubblesort.py) **- O(n2)** +* :small_red_triangle: [Hope sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/hopesort.py) **- O(1), hopefully** +* :white_check_mark: [Insertion sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/insertionsort.py) **- O(n2)** +* :white_check_mark: [Selection sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/selectionsort.py) **- O(n2)** +* :white_check_mark: [Merge sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/mergesort.py) **- O(nlog(n))** +* :white_check_mark: [Randomized Quick sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/randomized_quicksort.py) **- Average O(nlogn) (Input independent!)** +* :white_check_mark: [Quick sort](https://github.com/aladdinpersson/Algorithms-Collection-Python/blob/master/Algorithms/sorting/quicksort.py) **- Average O(nlog(n))** # Contributing I appreciate feedback on potential improvements and/or if you see an error that I've made! Also if you would like to contribute then do a pull request with algorithm & tests! :)