diff --git a/elect.py b/elect.py
index 0341a47df5985793732e42a42f83d4d6154857f6..fcf15484b822b3ced42e9227333f92b0425d54f7 100755
--- a/elect.py
+++ b/elect.py
@@ -1,6 +1,7 @@
 #!/usr/bin/env python3
 import argparse
 import json
+import networkx as nx
 import numpy as np
 
 # N[a,b] is the number of voters who prefer candidate a to candidate b
@@ -78,6 +79,101 @@ def schulze_winners(n, candidates, link_strength_method='margin'):
             winners.append(candidates[i])
     return winners
 
+# from https://en.wikipedia.org/wiki/Schwartz_set (2023-07-14)
+# In voting systems, the Schwartz set is the union of all Schwartz set components.
+# A Schwartz set component is any non-empty set S of candidates such that
+# Every candidate inside the set S is pairwise unbeaten by every candidate outside S; and
+# No non-empty proper subset of S fulfills the first property.
+def schwartz_set(graph, candidates):
+    nb_nodes = 0
+    candidate_to_beat_index = dict()
+    beat_index_to_candidate = dict()
+    for node in graph.nodes():
+        candidate_to_beat_index[node] = nb_nodes
+        beat_index_to_candidate[nb_nodes] = node
+        nb_nodes += 1
+
+    beats = np.zeros((nb_nodes, nb_nodes), dtype=bool)
+    for (i, neighbors) in graph.adjacency():
+        for j in neighbors:
+            beats[candidate_to_beat_index[i]][candidate_to_beat_index[j]] = True
+
+    for k in range(nb_nodes):
+        for i in range(nb_nodes):
+            for j in range(nb_nodes):
+                beats[i][j] = beats[i][j] or (beats[i][k] and beats[k][j])
+
+    schwartz_components = []
+    for i in range(nb_nodes):
+        schwartz_component = {i}
+        is_schwartz = True
+        for j in range(nb_nodes):
+            if beats[j][i]:
+                if beats[i][j]:
+                    schwartz_component.add(j)
+                else:
+                    is_schwartz = False
+        if is_schwartz:
+            schwartz_components.append(schwartz_component)
+
+    schwartz_set_index = set.union(*schwartz_components)
+    return [beat_index_to_candidate[x] for x in schwartz_set_index]
+
+# As defined in Appendix 4 of https://citizensassembly.arts.ubc.ca/resources/submissions/csharman-10_0409201706-143.pdf
+def schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin'):
+    nb_candidates = len(candidates)
+    graph = nx.DiGraph()
+    graph.add_nodes_from(candidates)
+
+    for i in range(nb_candidates):
+        for j in range(i, nb_candidates):
+            margin = n[i][j] - n[j][i]
+            if margin != 0:
+                (x, y) = (i, j) if margin > 0 else (j, i)
+                if link_strength_method == 'margin':
+                    graph.add_edge(candidates[x], candidates[y], weight=abs(margin))
+                elif link_strength_method == 'ratio':
+                    graph.add_edge(candidates[x], candidates[y], weight=np.Inf if n[y][x] == 0 else n[x][y]/n[y][x])
+                elif link_strength_method == 'winning_votes':
+                    graph.add_edge(candidates[x], candidates[y], weight=n[x][y])
+                elif link_strength_method == 'losing_votes':
+                    graph.add_edge(candidates[x], candidates[y], weight=-n[y][x])
+                else:
+                    raise ValueError(f"link_strength_method='{link_strength_method}' is not implemented")
+
+    while len(graph.nodes()) > 1:
+        s_set = schwartz_set(graph, candidates)
+        #print(f'Schwartz set: {s_set}')
+
+        # eliminate all candidates that are not in the Schwartz set
+        nodes_to_remove = []
+        for candidate in graph.nodes():
+            if candidate not in s_set:
+                nodes_to_remove.append(candidate)
+        if len(nodes_to_remove) > 0:
+            #print(f'Removing nodes: {nodes_to_remove}')
+            graph.remove_nodes_from(nodes_to_remove)
+
+        if len(graph.nodes()) > 1 and len(graph.edges()) > 1:
+            # remove all the edges that have the current minimal weight
+            minimum_weight = np.Inf
+            edges_per_weight = dict()
+            for (i, neighbors) in graph.adjacency():
+                for (neighbor, data) in neighbors.items():
+                    weight = data['weight']
+                    minimum_weight = min(minimum_weight, weight)
+                    if weight in edges_per_weight:
+                        edges_per_weight[weight].append((i, neighbor))
+                    else:
+                        edges_per_weight[weight] = [(i, neighbor)]
+
+            #print(f'Removing edges of weight={minimum_weight}: {edges_per_weight[minimum_weight]}')
+            for (i, j) in edges_per_weight[minimum_weight]:
+                graph.remove_edge(i, j)
+            continue
+        break
+
+    return [x for x in graph.nodes()]
 
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(description='Computes winners of the election')
@@ -107,6 +203,13 @@ if __name__ == '__main__':
         print(f'Weak Condorcet winners: {weak_c_winners}')
 
     # Schulze winners (win every head-to-head contest, directly or indirectly)
-    schulze_winners = schulze_winners(n, candidates)
-    assert(len(schulze_winners) > 0)
-    print(f'Schulze winners: {schulze_winners}')
+    for method in ['margin', 'ratio']:
+        s_winners = schulze_winners(n, candidates, link_strength_method=method)
+        assert(len(s_winners) > 0)
+        print(f'Schulze winners (beatpath, {method}): {s_winners}')
+
+    # Schulze winners, computed via the Schwartz sequential dropping algorithm
+    for method in ['margin', 'ratio', 'winning_votes', 'losing_votes']:
+        s_winners = schwartz_sequential_dropping_winners(n, candidates, link_strength_method=method)
+        assert(len(s_winners) > 0)
+        print(f'Schulze winners (ssd, {method}): {s_winners}')
diff --git a/test_schulze_examples.py b/test_schulze_examples.py
index 13b7aedc564875e57707edef419efed35662f1bf..8ff367df648f1c688b2b7224b1fe4de645ff09b9 100644
--- a/test_schulze_examples.py
+++ b/test_schulze_examples.py
@@ -29,6 +29,10 @@ def test_example1():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['d']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['d']
 
 
 def test_example2():
@@ -53,6 +57,10 @@ def test_example2():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['c']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['c']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['c']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['c']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['c']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['c']
 
 
 def test_example3():
@@ -81,6 +89,10 @@ def test_example3():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['e']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['e']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['e']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['e']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['e']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['e']
 
 
 def test_example4():
@@ -104,6 +116,10 @@ def test_example4():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['b', 'd']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['b', 'd']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['b', 'd']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['b', 'd']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['b', 'd']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['b', 'd']
 
 
 def test_example5():
@@ -128,6 +144,10 @@ def test_example5():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['d']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['d']
 
 
 def test_example6():
@@ -154,6 +174,10 @@ def test_example6():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['a', 'c']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['a', 'c']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['a', 'c']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['a', 'c']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['a', 'c']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['a', 'c']
 
 def test_example7():
     # situation 1
@@ -182,6 +206,10 @@ def test_example7():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['a']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['a']
 
     # situation 2
     candidates = ['a', 'b', 'c', 'd', 'e', 'f']
@@ -203,6 +231,10 @@ def test_example7():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['d']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['d']
 
 
 def test_example8():
@@ -232,6 +264,10 @@ def test_example8():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['a']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['a']
 
     # situation 2
     candidates = ['a', 'b', 'c', 'd', 'e']
@@ -260,6 +296,10 @@ def test_example8():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['b']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['b']
 
 
 def test_example9():
@@ -284,6 +324,10 @@ def test_example9():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['a']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['a']
 
     # situation 2
     candidates = ['a', 'b', 'c', 'd', 'e']
@@ -307,6 +351,10 @@ def test_example9():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['b']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['b']
 
 def test_example10():
     candidates = ['a', 'b', 'c', 'd']
@@ -337,9 +385,10 @@ def test_example10():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['a']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['b']
-
-    #assert False, "TODO: implement other methods to compute strength of link"
-
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['a']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['d']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['c']
 
 def test_example11():
     candidates = ['a', 'b', 'c', 'd', 'e']
@@ -367,6 +416,10 @@ def test_example11():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['b']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['b']
 
 
 def test_example12():
@@ -395,6 +448,10 @@ def test_example12():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['e']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['e']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['e']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['e']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['e']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['e']
 
 
 def test_example13():
@@ -416,3 +473,7 @@ def test_example13():
     assert len(elect.weak_condorcet_winners(n, candidates)) == 0
     assert elect.schulze_winners(n, candidates, link_strength_method='margin') == ['a', 'b']
     assert elect.schulze_winners(n, candidates, link_strength_method='ratio') == ['a', 'b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='margin') == ['a', 'b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='ratio') == ['a', 'b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='winning_votes') == ['a', 'b']
+    assert elect.schwartz_sequential_dropping_winners(n, candidates, link_strength_method='losing_votes') == ['a', 'b']