Commit 5970f441 authored by Temujin's avatar Temujin

added somee tests

parent 2c60a6d3
...@@ -18,8 +18,7 @@ class FamilyTree: ...@@ -18,8 +18,7 @@ class FamilyTree:
1 get all the nodes and edges, check if they're valid. 1 get all the nodes and edges, check if they're valid.
2 Make sure there's only one root. 2 Make sure there's only one root.
3 Find and set the root 3 Find and set the root
4 Set the generations 5 run set_generations() method
5 run precompute method
6 done 6 done
""" """
...@@ -41,12 +40,15 @@ class FamilyTree: ...@@ -41,12 +40,15 @@ class FamilyTree:
Note: Will not work if there's more than one node without a parent Note: Will not work if there's more than one node without a parent
""" """
arbitrary_node = next(iter(self.family_tree.values())) try:
arbitrary_node = next(iter(self.family_tree.values()))
while arbitrary_node.get_parent() is not None: while arbitrary_node.get_parent() is not None:
arbitrary_node = arbitrary_node.get_parent() arbitrary_node = arbitrary_node.get_parent()
self.root = arbitrary_node self.root = arbitrary_node
except StopIteration:
print("The tree is empty.")
def insert_person(self, person): def insert_person(self, person):
"""Add a Person object to the dict with the name as the key.""" """Add a Person object to the dict with the name as the key."""
...@@ -83,15 +85,8 @@ class FamilyTree: ...@@ -83,15 +85,8 @@ class FamilyTree:
descendants.sort() descendants.sort()
return descendants return descendants
def precompute(self): def set_generations(self):
"""Do the precomputations necessary to find LCA and degree. """Set the generations of the node by doing DFS."""
DFS from root. (todo)
Along the way, set the generations (levels)
and fill up the arrays for the lca query (TODO)
Raises exception if a root cannot be found.
"""
def set_gen(node): def set_gen(node):
"""Set the generation of a node to be one more than its parent.""" """Set the generation of a node to be one more than its parent."""
if node.parent is not None: if node.parent is not None:
...@@ -99,11 +94,6 @@ class FamilyTree: ...@@ -99,11 +94,6 @@ class FamilyTree:
else: else:
node.set_generation(1) node.set_generation(1)
def pre_lca(node):
# TODO
self.dfs_order.append(node.get_name())
self.dfs_gen.append(node.get_generation())
if self.root is None: if self.root is None:
self.find_root() self.find_root()
if self.root is None: if self.root is None:
...@@ -113,10 +103,8 @@ class FamilyTree: ...@@ -113,10 +103,8 @@ class FamilyTree:
def dfs(self, s, *funcs): def dfs(self, s, *funcs):
"""Depth first search from s, doing the given functions on each node. """Depth first search from s, doing the given functions on each node.
S = name of person in starting node. s = name of person in starting node.
*funcs = the operations to be done on the node *funcs = the operations to be done on the node
#TODO FIX THIS
""" """
visited = [] visited = []
current_node = self.family_tree[s] current_node = self.family_tree[s]
...@@ -135,10 +123,6 @@ class FamilyTree: ...@@ -135,10 +123,6 @@ class FamilyTree:
self.dfs(rc.get_name(), *funcs) self.dfs(rc.get_name(), *funcs)
def find_lca(self, name1, name2): def find_lca(self, name1, name2):
"""Find the lowest common ancestor of two nodes."""
return self.slow_lca(name1, name2)
def slow_lca(self, name1, name2):
"""Find the lca slowly. """Find the lca slowly.
Two pointer method. Two pointer method.
...@@ -161,13 +145,6 @@ class FamilyTree: ...@@ -161,13 +145,6 @@ class FamilyTree:
p2 = p2.get_parent() p2 = p2.get_parent()
return p1 return p1
def fast_lca(self, a, b):
"""Find the lca fast.
Reduction to range min. query
"""
return
def relationship(self, p1, p2): def relationship(self, p1, p2):
"""Determine the relationship between two distinct people in the tree. """Determine the relationship between two distinct people in the tree.
...@@ -197,7 +174,9 @@ class FamilyTree: ...@@ -197,7 +174,9 @@ class FamilyTree:
elif furthest == 2: elif furthest == 2:
return self.TERM("nibling", d1, d2, p2.sex) return self.TERM("nibling", d1, d2, p2.sex)
else: else:
return self.GREAT(furthest-2) + "grand" + self.TERM("nibling", d1, d2, p2.sex) # SPECIAL CASES: grand-niece/nephew, grand-aunt/uncle.
num_greats = abs(p1.get_generation() - p2.get_generation()) - 2
return self.GREAT(num_greats) + "grand" + self.TERM("nibling", d1, d2, p2.sex)
elif nearest == 0: elif nearest == 0:
if furthest == 1: if furthest == 1:
return self.TERM("child", d1, d2, p2.sex) return self.TERM("child", d1, d2, p2.sex)
...@@ -355,7 +334,7 @@ def openfile(filename): ...@@ -355,7 +334,7 @@ def openfile(filename):
p2.set_parent(p1) p2.set_parent(p1)
readF.close() readF.close()
atree.precompute() atree.set_generations()
return atree return atree
...@@ -384,7 +363,7 @@ def savefile(filename, tree): ...@@ -384,7 +363,7 @@ def savefile(filename, tree):
saveF.write("child " + parent.get_name() + " " + x.get_name() + "\n") saveF.write("child " + parent.get_name() + " " + x.get_name() + "\n")
def commandLine(): def command_line():
"""Open command line.""" """Open command line."""
tree = FamilyTree() tree = FamilyTree()
while True: while True:
...@@ -461,7 +440,7 @@ def commandLine(): ...@@ -461,7 +440,7 @@ def commandLine():
print("Error: File not found") print("Error: File not found")
elif cmd[0] == "save": elif cmd[0] == "save":
tree.find_root() tree.find_root()
tree.precompute() tree.set_generations()
savefile(cmd[1], tree) savefile(cmd[1], tree)
print("file saved") print("file saved")
elif cmd[0] == "bye": elif cmd[0] == "bye":
...@@ -472,66 +451,17 @@ def commandLine(): ...@@ -472,66 +451,17 @@ def commandLine():
def main(): def main():
r"""For testing.
A
/ \
B C
/ \
D E
"""
ftree = FamilyTree()
A = Person("A", 69, True)
B = Person("B", 69, True)
C = Person("C", 69, False)
D = Person("D", 69, True)
E = Person("E", 666, False)
ftree.insert_person(A)
ftree.insert_person(B)
ftree.insert_person(C)
ftree.insert_person(D)
ftree.insert_person(E)
B.set_parent(A)
C.set_parent(A)
D.set_parent(B)
E.set_parent(B)
ftree.find_root()
ancestors = ftree.get_ancestors(D.get_name())
descendants = ftree.get_descendants(A.get_name())
print("The root of the tree is {}.".format(ftree.root))
print("ancestors of {}: {}".format("D", ancestors))
print("descendants of {}: {}".format("A", descendants))
ftree.precompute()
for key, node in ftree.family_tree.items():
print("{}: {}".format(node, node.get_generation()))
print("The lca of {} and {} is {}".format(D, C, ftree.find_lca("D", "C")))
print("The lca of {} and {} is {}".format(B, D, ftree.find_lca("B", "D")))
print("The lca of {} and {} is {}".format(A, B, ftree.find_lca("A", "B")))
# parent/child
print("{} is {}'s: {}".format(B, A, ftree.relationship(A, B)))
print("{} is {}'s: {}".format(A, B, ftree.relationship(B, A)))
# grandparent/granchild
print("")
# sibling
print("{} is {}'s: {}".format(B, C, ftree.relationship(C, B)))
print("{} is {}'s: {}".format(C, B, ftree.relationship(B, C)))
# nibling
print("{} is {}'s: {}".format(D, C, ftree.relationship(C, D)))
print("{} is {}'s: {}".format(C, D, ftree.relationship(D, C)))
print("{} is {}'s: {}".format(A, D, ftree.relationship(D, A)))
print("{} is {}'s: {}".format(D, A, ftree.relationship(A, D)))
# test for opening and saving files # test for opening and saving files
ntree = openfile("chandelier") ntree = openfile("chandelier")
ntree.find_root() ntree.find_root()
ntree.precompute() ntree.set_generations()
print("The root of the tree is {}.".format(ntree.root)) print("The root of the tree is {}.".format(ntree.root))
for key, node in ntree.family_tree.items(): for key, node in ntree.family_tree.items():
print("{}: {}".format(node, node.get_generation())) print("{}: {}".format(node, node.get_generation()))
savefile("test", ntree) savefile("test", ntree)
command_line()
if __name__ == "__main__": if __name__ == "__main__":
......
Files Included:
family_tree.py
Minimum specs:
Processors: Intel Atom® processor or Intel® Core™ i3 processor
Disk space: 1 GB
Operating systems: Windows* 7 or later, macOS
Python* versions: 3.6.X
Special cases:
The lca of two people x and y, if x is an ancestor of y, is x.
lca(x, y) = x
Although not really the "lowest common ancestor", since a node is not
an ancestor of itself, this implementation was chosen to make it work
with the pseudocode for the relationship function.
How to start the program:
Open terminal:
> python family_tree.py
import sys
import os
sys.path.insert(0, os.path.abspath(
os.path.join(os.path.dirname(__file__), '..')))
import family_tree
import context as c """Unittest for family_tree."""
import sys
import os
sys.path.insert(0, os.path.abspath(
os.path.join(os.path.dirname(__file__), '..')))
import family_tree as f
import unittest import unittest
class TestFamilyTree(unittest.TestCase): class TestFamilyTree(unittest.TestCase):
"""For testing family tree."""
def setUp(self): def setUp(self):
r"""For testing. r"""For testing.
Test tree:
A A
/ \ / \
B C B C
/ \ / \
D E D E
/
F
""" """
self.ftree = c.FamilyTree() self.ftree = f.FamilyTree()
ftree = c.FamilyTree() A = f.Person("A", 69, True)
A = c.Person("A", 69, True) B = f.Person("B", 69, True)
B = c.Person("B", 69, True) C = f.Person("C", 69, False)
C = c.Person("C", 69, False) D = f.Person("D", 69, True)
D = c.Person("D", 69, True) E = f.Person("E", 666, False)
E = c.Person("E", 666, False) F = f.Person("F", 420, False)
ftree.insert_person(A) self.ftree.insert_person(A)
ftree.insert_person(B) self.ftree.insert_person(B)
ftree.insert_person(C) self.ftree.insert_person(C)
ftree.insert_person(D) self.ftree.insert_person(D)
ftree.insert_person(E) self.ftree.insert_person(E)
self.ftree.insert_person(F)
self.assertGreater(len(self.ftree.family_tree), 0)
B.set_parent(A) B.set_parent(A)
C.set_parent(A) C.set_parent(A)
D.set_parent(B) D.set_parent(B)
E.set_parent(B) E.set_parent(B)
ftree.find_root() F.set_parent(D)
self.ftree.find_root()
def test_find_ancestors(self): def test_find_ancestors(self):
pass D_ancestors = self.ftree.get_ancestors("D")
r = set(["B", "A"])
self.assertEqual(set(D_ancestors), r)
root_ancestor = self.ftree.get_ancestors("A")
self.assertListEqual(root_ancestor, [])
def test_find_descendants(self): def test_find_descendants(self):
pass root_descendants = set(self.ftree.get_descendants("A"))
r = set(self.ftree.family_tree.keys()) - {"A"}
self.assertEqual(root_descendants, r)
leaf_descendants = self.ftree.get_descendants("F")
self.assertListEqual(leaf_descendants, [])
def test_set_generations(self): def test_set_generations(self):
pass self.ftree.set_generations()
for name, person in self.ftree.family_tree.items():
self.assertFalse(person.get_generation() is None)
def test_lca(self):
self.ftree.set_generations()
lca1 = self.ftree.find_lca("D", "C")
lca2 = self.ftree.find_lca("B", "D")
lca3 = self.ftree.find_lca("A", "B")
A = self.ftree.get_person("A")
B = self.ftree.get_person("B")
self.assertEqual(lca1, A)
self.assertEqual(lca2, B)
self.assertEqual(lca3, A)
def test_relationship(self): def test_relationship(self):
self.ftree.set_generations()
A = self.ftree.get_person("A")
B = self.ftree.get_person("B")
C = self.ftree.get_person("C")
D = self.ftree.get_person("D")
F = self.ftree.get_person("F")
# parent/child
self.assertEqual(self.ftree.relationship(A, B), "son")
self.assertEqual(self.ftree.relationship(B, A), "father")
# grand parent/child
self.assertEqual(self.ftree.relationship(A, D), "grandson")
self.assertEqual(self.ftree.relationship(D, A), "grandfather")
# great grandparent/child
self.assertEqual(self.ftree.relationship(F, A), "greatgrandfather")
self.assertEqual(self.ftree.relationship(A, F), "greatgranddaughter")
# sibling
self.assertEqual(self.ftree.relationship(C, B), "brother")
self.assertEqual(self.ftree.relationship(B, C), "sister")
# nibling
self.assertEqual(self.ftree.relationship(C, D), "nephew")
self.assertEqual(self.ftree.relationship(D, C), "aunt")
# grand nibling
self.assertEqual
self.assertEqual(self.ftree.relationship(C, F), "grandniece")
self.assertEqual(self.ftree.relationship(F, C), "grandaunt")
if __name__ == "__main__": if __name__ == "__main__":
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment