Skip to content
Snippets Groups Projects
Commit 8dcb4313 authored by Pavel Veselý's avatar Pavel Veselý
Browse files

Merge branch 'master' of gitlab.kam.mff.cuni.cz:datovky/assignments

parents 32463bc6 8e4e4b13
Branches
No related tags found
No related merge requests found
#include <algorithm>
#include <functional>
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#include "tree_successor.h"
using namespace std;
// If the condition is not true, report an error and halt.
#define EXPECT(condition, message) do { if (!(condition)) expect_failed(message); } while (0)
void expect_failed(const string& message);
void test(const vector<int>& sequence, Tree &tree) {
Node* node = tree.successor(nullptr);
for (const auto& element : sequence) {
EXPECT(node, "Expected successor " + to_string(element) + ", got nullptr");
EXPECT(node->key == element,
"Expected successor " + to_string(element) + ", got " + to_string(node->key));
node = tree.successor(node);
}
EXPECT(!node, "Expected no successor, got " + to_string(node->key));
}
vector<int> get_linear_sequence() {
vector<int> numbers;
for (int i = 0; i < 10000000; i++)
numbers.push_back((int)(7.13*i));
return numbers;
}
void test_path(bool right) {
vector<int> numbers = get_linear_sequence();
Tree tree;
Node *node = nullptr;
if (right)
for (int key : numbers)
node = tree.insert(key, node);
else
for (int index = numbers.size() - 1; index >= 0; --index)
node = tree.insert(numbers[index], node);
test(numbers, tree);
}
void test_two_paths() {
vector<int> numbers = get_linear_sequence();
Tree tree;
Node *node = nullptr;
for(size_t i = numbers.size()/2; i < numbers.size(); i++)
node = tree.insert(numbers[i], node);
node = nullptr;
for(int i = numbers.size()/2 - 1; i >= 0; i--)
node = tree.insert(numbers[i], node);
test(numbers, tree);
}
void test_sequence(vector<int> &&sequence) {
Tree tree;
for (const auto& element : sequence)
tree.insert(element);
sort(sequence.begin(), sequence.end());
test(sequence, tree);
}
void test_random() {
vector<int> sequence = {997};
for (int i = 2; i < 199999; i++)
sequence.push_back((sequence.back() * int64_t(997)) % 199999);
test_sequence(move(sequence));
}
void test_trivial() {
test_sequence({5});
test_sequence({7,9});
test_sequence({7,3});
test_sequence({5,3,7});
}
void test_comb() {
vector<int> numbers = get_linear_sequence();
Tree tree;
Node *node = nullptr;
for(size_t i = numbers.size()/2; i < numbers.size(); i++)
node = tree.insert(numbers[i], node);
node = nullptr;
for(int i = numbers.size()/2 - 1; i >= 0; i-=2) {
node = tree.insert(numbers[i-1], node);
tree.insert(numbers[i], node);
}
test(numbers, tree);
}
vector<pair<string, function<void()>>> tests = {
{ "trivial", test_trivial },
{ "right_path", []{ test_path(true); } },
{ "left_path", []{ test_path(false); } },
{ "random_tree", test_random },
{ "two_paths", test_two_paths },
{ "comb", test_comb }
};
#!/usr/bin/env python3
import sys
from tree_successor import Tree
def test_tree(tree, sequence):
node = tree.successor(None)
for element in sequence:
assert node is not None, "Expected successor {}, got None".format(element)
assert node.key == element, "Expected successor {}, got {}".format(element, node.key)
node = tree.successor(node)
assert node is None, "Expected no successor, got {}".format(node.key)
def test_sequence(sequence):
tree = Tree()
for i in sequence:
tree.insert(i)
sequence.sort()
test_tree(tree, sequence)
def test_trivial_tree():
test_sequence([5])
test_sequence([7,9])
test_sequence([7,3])
test_sequence([5,3,7])
def test_random_tree():
test_sequence([pow(997, i, 199999) for i in range(1, 199999)])
def test_path(right):
sequence = [int(7.13*i) for i in range(1000000)]
tree = Tree()
node = None
sequence_insert = sequence if right else reversed(sequence)
for key in sequence_insert:
node = tree.insert(key, node)
test_tree(tree, sequence)
def test_two_paths():
sequence_left = [int(7.13*i) for i in range(1000000)]
sequence_right = [int(7.13*i) for i in range(1000000, 2000000)]
tree = Tree()
node = None
for key in sequence_right:
node = tree.insert(key, node)
node = None
for key in reversed(sequence_left):
node = tree.insert(key, node)
test_tree(tree, sequence_left + sequence_right)
def test_comb():
sequence = [int(7.13*i) for i in range(1000000)]
tree = Tree()
node = None
for i in range(len(sequence)//2, len(sequence)):
node = tree.insert(sequence[i], node)
node = None
for i in range(len(sequence)//2-1, 0, -2):
node = tree.insert(sequence[i-1], node)
tree.insert(sequence[i], node)
test_tree(tree, sequence)
tests = [
("trivial", test_trivial_tree),
("random_tree", test_random_tree),
("right_path", lambda: test_path(True)),
("left_path", lambda: test_path(False)),
("two_paths", test_two_paths),
("comb", test_comb),
]
if __name__ == "__main__":
for required_test in sys.argv[1:] or [name for name, _ in tests]:
for name, test in tests:
if name == required_test:
print("Running test {}".format(name), file=sys.stderr)
test()
break
else:
raise ValueError("Unknown test {}".format(name))
...@@ -15,3 +15,8 @@ You should submit the file `tree_successor.*` (but not the ...@@ -15,3 +15,8 @@ You should submit the file `tree_successor.*` (but not the
`tree_successor_test.*`). `tree_successor_test.*`).
Source code templates can be found in [the git repository](https://gitlab.kam.mff.cuni.cz/datovky/assignments/-/tree/master). Source code templates can be found in [the git repository](https://gitlab.kam.mff.cuni.cz/datovky/assignments/-/tree/master).
Files tree_successor_more_tests.{cpp,py} contain additional tests
for bugs discovered in students' solutions during this semester.
They are not included on recodex, but your program should pass them
in few seconds.
#include <algorithm>
#include <cassert>
#include <fstream>
#include <functional>
#include <string>
#include <utility>
#include <vector>
#include "splay_operation.h"
using namespace std;
// If the condition is not true, report an error and halt.
#define EXPECT(condition, message) do { if (!(condition)) expect_failed(message); } while (0)
void expect_failed(const string& message);
// Flatten the tree: return a sorted list of all keys in the tree.
vector<int> flatten(const Tree& tree) {
constexpr int L = 0, R = 1, F = 2;
Node* node = tree.root;
vector<int> flattened, stack = {L};
while (!stack.empty()) {
if (stack.back() == L) {
stack.back() = R;
if (node->left) {
node = node->left;
stack.push_back(L);
}
} else if (stack.back() == R) {
flattened.push_back(node->key);
stack.back() = F;
if (node->right) {
node = node->right;
stack.push_back(L);
}
} else {
node = node->parent;
stack.pop_back();
}
}
return flattened;
}
// Test for splay operation with required helpers
class TestSplay {
public:
static Node* deserialize_node(const string& text, int& index) {
EXPECT(text[index++] == '(', "Internal error during example deserialization");
if (text[index] == ')') {
index++;
return nullptr;
} else {
int comma = text.find(',', index);
int key = stoi(text.substr(index, comma - index));
Node* left = deserialize_node(text, (index=comma + 1));
Node* right = deserialize_node(text, ++index);
EXPECT(text[index++] == ')', "Internal error during example deserialization");
return new Node(key, nullptr, left, right);
}
}
static Node* deserialize_root(const string& text) {
int index = 0;
Node* root = deserialize_node(text, index);
assert(index == text.size());
return root;
}
static string compare(Node* system, Node* gold) {
if (!system && gold) {
return "expected node with key " + to_string(gold->key) + ", found None";
} else if (system && !gold) {
return "expected None, found node with key " + to_string(system->key);
} else if (system && gold) {
if (system->key != gold->key)
return "expected node with key " + to_string(gold->key) + ", found " + to_string(system->key);
auto result = compare(system->left, gold->left);
if (!result.empty()) return result;
return compare(system->right, gold->right);
}
return string();
}
static void test() {
ifstream splay_tests_file("splay_tests.txt");
EXPECT(splay_tests_file.is_open(), "Cannot open splay_tests.txt file with the tests");
string original, splayed;
int target;
while (splay_tests_file >> original >> target >> splayed) {
Tree original_tree(deserialize_root(original));
Tree splayed_tree(deserialize_root(splayed));
Node* target_node = original_tree.root;
while (target_node && target_node->key != target)
if (target < target_node->key)
target_node = target_node->left;
else
target_node = target_node->right;
EXPECT(target_node, "Internal error during finding the target node in the tree to splay");
original_tree.splay(target_node);
auto error = compare(original_tree.root, splayed_tree.root);
EXPECT(error.empty(), "Error running splay on key " + to_string(target) + " of " + original + ": " + error);
}
}
};
const int elements = 5000000;
void test_lookup() {
// Insert even numbers
Tree tree;
for (int i = 0; i < elements; i += 2)
tree.insert(i);
// Find non-existing
for (int i = 1; i < elements; i += 2)
for (int j = 0; j < 10; j++)
EXPECT(!tree.lookup(i), "Non-existing element was found");
// Find existing
for (int i = 0; i < elements; i += 2)
for (int j = 0; j < 10; j++)
EXPECT(tree.lookup(i), "Existing element was not found");
}
void test_insert() {
// Test validity first
{
Tree tree;
vector<int> sequence = {997};
for (int i = 2; i < 1999; i++)
sequence.push_back((sequence.back() * sequence.front()) % 1999);
for (const auto& i : sequence)
tree.insert(i);
vector<int> flattened = flatten(tree);
sort(sequence.begin(), sequence.end());
EXPECT(flattened == sequence, "Incorrect tree after a sequence of inserts");
}
// Test speed
{
Tree tree;
for (int i = 0; i < elements; i++)
for (int j = 0; j < 10; j++)
tree.insert(i);
}
{
Tree tree;
for (int i = elements; i >= 0; i--)
tree.insert(i);
for (int i = 0; i < elements; i++)
tree.insert(elements);
}
}
void test_remove() {
// Test validity first
{
Tree tree;
for (int i = 2; i < 1999 * 2; i++)
tree.insert(i);
vector<int> sequence = {2 * 997};
for (int i = 2; i < 1999; i++)
sequence.push_back(2 * ((sequence.back() * sequence.front() / 4) % 1999));
for (const auto& i : sequence)
tree.remove(i + 1);
vector<int> flattened = flatten(tree);
sort(sequence.begin(), sequence.end());
EXPECT(flattened == sequence, "Correct tree after a sequence of removes");
}
// Test speed
{
Tree tree;
for (int i = 0; i < elements; i++)
tree.insert(i);
// Non-existing elements
for (int i = 1; i < elements; i += 2)
for (int j = 0; j < 10; j++)
tree.remove(i);
// Existing elements
for (int i = 2; i < elements; i += 2)
for (int j = 0; j < 10; j++)
tree.remove(i);
}
{
Tree tree;
for (int i = 1; i < elements; i++)
tree.insert(i);
for (int i = 1; i < elements; i++)
tree.remove(0);
}
}
vector<pair<string, function<void()>>> tests = {
{ "splay", TestSplay::test },
{ "lookup", test_lookup },
{ "insert", test_insert },
{ "remove", test_remove },
};
#!/usr/bin/env python3
import itertools
import math
import sys
from splay_operation import Tree, Node
def flatten(tree):
"""Flatten given tree in ascending order."""
L, R, F = 0, 1, 2
node, stack, flattened = tree.root, [L], []
while node is not None:
if stack[-1] == L:
stack[-1] = R
if node.left is not None:
node = node.left
stack.append(L)
elif stack[-1] == R:
flattened.append(node.key)
stack[-1] = F
if node.right is not None:
node = node.right
stack.append(L)
else:
node = node.parent
stack.pop()
return flattened
def test_splay():
def deserialize_tree(string):
def deserialize_node(i):
assert string[i] == "("
i += 1
if string[i] == ")":
return i + 1, None
else:
comma = string.find(",", i)
comma2, left = deserialize_node(comma + 1)
rparen, right = deserialize_node(comma2 + 1)
assert string[rparen] == ")"
return rparen + 1, Node(int(string[i : comma]), left=left, right=right)
index, root = deserialize_node(0)
assert index == len(string)
return Tree(root)
def compare(system, gold):
if system is None and gold is not None:
return "expected node with key {}, found None".format(gold.key)
elif system is not None and gold is None:
return "expected None, found node with key {}".format(system.key)
elif system is not None and gold is not None:
if system.key != gold.key:
return "expected node with key {}, found {}".format(gold.key, system.key)
return compare(system.left, gold.left) or compare(system.right, gold.right)
with open("splay_tests.txt", "r") as splay_tests_file:
for line in splay_tests_file:
original_serialized, target_serialized, splayed_serialized = line.rstrip("\n").split()
original = deserialize_tree(original_serialized)
splayed = deserialize_tree(splayed_serialized)
target = int(target_serialized)
node = original.root
while node is not None and node.key != target:
if target < node.key: node = node.left
else: node = node.right
assert node is not None
original.splay(node)
error = compare(original.root, splayed.root)
assert not error, "Error running splay on key {} of {}: {}".format(node.key, original_serialized, error)
def test_lookup():
tree = Tree()
for elem in range(0, 100000, 2):
tree.insert(elem)
# Find non-existing
for elem in range(1, 100000, 2):
for _ in range(10):
assert tree.lookup(elem) is None, "Non-existing element was found"
# Find existing
for elem in range(0, 100000, 2):
for _ in range(10):
assert tree.lookup(elem) is not None, "Existing element was not found"
def test_insert():
# Test validity first
tree = Tree()
sequence = [pow(997, i, 1999) for i in range(1, 1999)]
for elem in sequence:
tree.insert(elem)
assert flatten(tree) == sorted(sequence), "Incorrect tree after a sequence of inserts"
# Test speed
elements = 200000
tree = Tree()
for elem in range(elements):
for _ in range(10):
tree.insert(elem)
tree = Tree()
for elem in reversed(range(elements)):
tree.insert(elem)
for elem in range(elements):
tree.insert(elements)
def test_remove():
# Test validity first
tree = Tree()
for elem in range(2, 1999 * 2):
tree.insert(elem)
sequence = [2 * pow(997, i, 1999) for i in range(1, 1999)]
for elem in sequence:
tree.remove(elem + 1)
assert flatten(tree) == sorted(sequence), "Incorrect tree after a sequence of removes"
# Test speed
elements = 200000
tree = Tree()
for elem in range(0, elements, 2):
tree.insert(elem)
# Non-existing elements
for elem in range(1, elements, 2):
for _ in range(10):
tree.remove(elem)
# Existing elements
for elem in range(2, elements, 2):
tree.remove(elem)
tree = Tree()
for elem in range(1, elements):
tree.insert(elem)
for elem in range(elements):
tree.remove(0)
tests = [
("splay", test_splay),
("lookup", test_lookup),
("insert", test_insert),
("remove", test_remove),
]
if __name__ == "__main__":
for required_test in sys.argv[1:] or [name for name, _ in tests]:
for name, test in tests:
if name == required_test:
print("Running test {}".format(name), file=sys.stderr)
test()
break
else:
raise ValueError("Unknown test {}".format(name))
...@@ -10,3 +10,8 @@ You should submit the `splay_operation.*` file (but not the ...@@ -10,3 +10,8 @@ You should submit the `splay_operation.*` file (but not the
`splay_operation_test.*`). `splay_operation_test.*`).
Source code templates can be found in [the git repository](https://gitlab.kam.mff.cuni.cz/datovky/assignments/-/tree/master). Source code templates can be found in [the git repository](https://gitlab.kam.mff.cuni.cz/datovky/assignments/-/tree/master).
Files splay_operation_more_tests.{cpp,py} contain additional tests
for bugs discovered in students' solutions during this semester.
They are not included on recodex, but your program should pass them
in few seconds.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment