def greedy_make_change(n): C = Array.indexed(1, 6) d = Array([1, 2, 5, 10, 20, 50]) for i in rbetween(d.length, 1): C[i] = math.floor(n / d[i]) n %= d[i] return C
def memoized_matrix_chain(p): n = p.length - 1 m = Array([Array.indexed(1, n) for _ in between(1, n)]) for i in between(1, n): for j in between(i, n): m[i, j] = math.inf return lookup_chain(p, m, 1, n)
def merge_(A, p, q, r): n1 = q - p + 1 n2 = r - q L = Array.indexed(1, n1) R = Array.indexed(1, n2) for i in between(1, n1): L[i] = A[p + i - 1] for j in between(1, n2): R[j] = A[q + j] i = j = 1 k = p while i <= n1 and j <= n2: if L[i] <= R[j]: A[k] = L[i] i = i + 1 else: A[k] = R[j] j = j + 1 k = k + 1 while i <= n1: A[k] = L[i] i = i + 1 k = k + 1 while j <= n2: A[k] = R[j] j = j + 1 k = k + 1
def test_edit_distance(self): len1 = random.randint(0, 8) len2 = random.randint(0, 8) word1 = Array(''.join(random.choice('abcde') for _ in range(len1))) word2 = Array(''.join(random.choice('abcde') for _ in range(len2))) cost_insert = random.randint(0, 10) cost_delete = random.randint(0, 10) cost = {'copy': random.randint(0, max(10, cost_insert + cost_delete)), 'replace': random.randint(0, max(10, cost_insert + cost_delete)), 'insert': cost_insert, 'delete': cost_delete, 'twiddle': random.randint(0, 10), 'kill': random.randint(0, 10)} captured_output = io.StringIO() actual_costs, actual_op, actual_left, actual_right = edit_distance(word1, word2, cost) with redirect_stdout(captured_output): print_operations(actual_op, actual_left, actual_right, len1, len2) expected_cost = get_edit_distance_bruteforce(word1, word2, cost) assert_that(actual_costs[len1, len2], is_(equal_to(expected_cost))) actual_operations = captured_output.getvalue().splitlines() assert_valid_operations(actual_operations, word1, word2) cost_of_operations = get_operations_cost(actual_operations, cost) assert_that(cost_of_operations, is_(equal_to(expected_cost)))
def get_random_multiple_array_list(min_size=1, max_size=10, max_value=999): list_size = random.randint(min_size, max_size) array_size = random.randint(list_size, max_size) key, next, prev = Array.indexed(1, array_size), Array.indexed(1, array_size), Array.indexed(1, array_size) list_indexes = random.sample(range(1, array_size + 1), list_size) head = None prev_index = None for index in list_indexes: key[index] = random.randint(0, max_value) if prev_index is None: head = index else: next[prev_index] = index prev[index] = prev_index prev_index = index free_indexes = [i for i in range(1, array_size + 1) if i not in list_indexes] random.shuffle(free_indexes) free = None prev_free_index = None for free_index in free_indexes: if prev_free_index is None: free = free_index else: next[prev_free_index] = free_index prev_free_index = free_index return MultipleArrayList(key, next, prev, head, free)
def test_checkerboard(self): n = random.randint(1, 8) # profit[i, j] contains a triple (a, b, c), where the profit of moving from square of coords (i, j): # to square of coords (i+1, j-1) is a, to square of coords (i+1, j) is b, to square of coords (i+1, j+1) is c, # where (i, j) means i-th row from the bottom and j-th column from the left profit = Array([Array.indexed(1, n) for _ in between(1, n - 1)]) for i in between(1, n - 1): profit[i, 1] = (None, random.randint(-100, 100), random.randint(-100, 100)) for j in between(2, n - 1): profit[i, j] = (random.randint(-100, 100), random.randint(-100, 100), random.randint(-100, 100)) profit[i, n] = (random.randint(-100, 100), random.randint(-100, 100), None) captured_output = io.StringIO() actual_maximum_profit, squares, last_square = checkerboard( n, lambda x, y: checkerboard_profit(profit, x, y)) with redirect_stdout(captured_output): print_moves(squares, n, last_square) expected_maximum_profit = \ get_optimal_checkerboard_path_bruteforce(n, lambda x, y: checkerboard_profit(profit, x, y)) assert_that(actual_maximum_profit, is_(equal_to(expected_maximum_profit))) assert_squares_path(n, captured_output.getvalue().splitlines(), profit, expected_maximum_profit)
def fastest_way_(a, t, e, x, n): f = Array([Array.indexed(1, 2), Array.indexed(1, 2)]) l = Array([Array.indexed(1, n), Array.indexed(1, n)]) f[1, 2] = e[1] + a[1, 1] f[2, 2] = e[2] + a[2, 1] for j in between(2, n): f[1, 1] = f[1, 2] f[2, 1] = f[2, 2] if f[1, 1] + a[1, j] <= f[2, 1] + t[2, j - 1] + a[1, j]: f[1, 2] = f[1, 1] + a[1, j] l[1, j] = 1 else: f[1, 2] = f[2, 1] + t[2, j - 1] + a[1, j] l[1, j] = 2 if f[2, 1] + a[2, j] <= f[1, 1] + t[1, j - 1] + a[2, j]: f[2, 2] = f[2, 1] + a[2, j] l[2, j] = 2 else: f[2, 2] = f[1, 1] + t[1, j - 1] + a[2, j] l[2, j] = 1 if f[1, 2] + x[1] <= f[2, 2] + x[2]: f_star = f[1, 2] + x[1] l_star = 1 else: f_star = f[2, 2] + x[2] l_star = 2 return f_star, l, l_star
def get_min_schedule(activities, schedule, time): min_schedule_cost = math.inf min_schedule = Array(schedule.elements) earliest_future_release_time = math.inf for i in range(len(activities)): activity = activities[i] if activity.r <= time and activity.p > 0: activity.p -= 1 deleted = False if activity.p == 0: schedule[activity.id] = time + 1 del activities[i] deleted = True schedule = get_min_schedule(activities, schedule, time + 1) cost = sum(schedule.elements) if cost < min_schedule_cost: min_schedule_cost = cost min_schedule = Array(schedule.elements) if deleted: activities.insert(i, activity) activity.p += 1 if activity.r > time and activity.p > 0: earliest_future_release_time = min(earliest_future_release_time, activity.r) if earliest_future_release_time < math.inf: schedule = get_min_schedule(activities, schedule, earliest_future_release_time) if sum(schedule.elements) < min_schedule_cost: return Array(schedule.elements) return min_schedule
def _effective_fractional_knapsack(items, K, W): n = items.length if n == 0: return K unit_values = Array([item.value / item.weight for item in items]) m = select(unit_values, 1, n, math.floor((n + 1) / 2)) G = Array([item for item in items if item.value / item.weight > m]) E = Array([item for item in items if item.value / item.weight == m]) L = Array([item for item in items if item.value / item.weight < m]) w_G = sum([item.weight for item in G]) w_E = sum([item.weight for item in E]) if w_G >= W: return _effective_fractional_knapsack(G, K, W) for item in G: K[item.id] = item.weight weight_sum = w_G for item in E: if weight_sum + item.weight > W: K[item.id] = W - weight_sum break K[item.id] = item.weight weight_sum += item.weight if w_G + w_E >= W: return K else: return _effective_fractional_knapsack(L, K, W - w_G - w_E)
def test_lcs_length__(self): sequence1 = Array(''.join(random.choice('ABCD') for _ in range(random.randint(1, 10)))) sequence2 = Array(''.join(random.choice('ABCD') for _ in range(random.randint(1, 10)))) actual_maximum_length = lcs_length__(sequence1, sequence2) expected_maximum_length = get_maximum_lcs_length_bruteforce(sequence1, sequence2) assert_that(actual_maximum_length, is_(equal_to(expected_maximum_length)))
def memoized_lcs_length(X, Y): m = X.length n = Y.length c = Array([Array.indexed(0, n) for _ in between(0, m)], start=0) for i in between(0, m): for j in between(0, n): c[i, j] = math.inf return lookup_lcs(c, X, Y, m, n)
def integers_sort(A): n = sum(len(str(integer)) for integer in A) nonnegative = Array([integer for integer in A if integer >= 0]) negative = Array([-integer for integer in A if integer < 0]) sorted_nonnegative = _nonnegative_integers_sort(nonnegative, n) sorted_negative = _nonnegative_integers_sort(negative, n) A.elements = list(reversed([-integer for integer in sorted_negative ])) + sorted_nonnegative
def test_bucket_sort(self): n = random.randint(1, 20) elements = [random.random() for _ in range(n)] array = Array(elements) bucket_sort(array) expected_array = Array(sorted(elements)) assert_that(array, is_(equal_to(expected_array)))
def test_unstable_counting_sort(self): k = 20 array, elements = get_random_array(max_value=k) actual_sorted_array = Array.indexed(1, array.length) unstable_counting_sort(array, actual_sorted_array, k) expected_array = Array(sorted(elements)) assert_that(actual_sorted_array, is_(equal_to(expected_array)))
def setup_activities(n): start_times = Array.indexed(0, n + 1) finish_times = Array.indexed(0, n + 1) for i in between(1, n): start_times[i] = random.randint(0, 49) finish_times[i] = start_times[i] + random.randint(1, 50) start_times[0], finish_times[0] = 0, 0 start_times[n + 1], finish_times[n + 1] = math.inf, math.inf return start_times, finish_times
def test_below_square_sort(self): n = random.randint(1, 20) elements = [random.randint(0, n**2 - 1) for _ in range(n)] array = Array(elements) below_square_sort(array) expected_array = Array(sorted(elements)) assert_that(array, is_(equal_to(expected_array)))
def get_random_min_heap(ary=2, min_size=1, max_size=20, max_value=999): size = random.randint(min_size, max_size) keys = [random.randint(0, max_value)] for i in range(1, size): bound = keys[(i - 1) // ary] keys.append(random.randint(bound, max_value)) heap = Array(keys) heap.heap_size = size return heap, keys
def dynamic_binary_insert(A, x): B = Array([x]) i = 0 while A[i].length != 0: B = Array(A[i].elements + B.elements) merge(B, 1, A[i].length, B.length) A[i] = Array([]) i = i + 1 A[i] = Array(B.elements)
def test_optimal_alignment(self): len1 = random.randint(0, 8) len2 = random.randint(0, 8) word1 = Array(''.join(random.choice('ACGT') for _ in range(len1))) word2 = Array(''.join(random.choice('ACGT') for _ in range(len2))) actual_score, _, _, _ = optimal_alignment(word1, word2) expected_score = get_optimal_alignment_bruteforce(word1, word2) assert_that(actual_score, is_(equal_to(expected_score)))
def _sort_by_length(A, n): numbers_by_length = Array.indexed(1, n) for number in A: if numbers_by_length[len(str(number))] is None: numbers_by_length[len(str(number))] = [] numbers_by_length[len(str(number))].append(number) for i in between(1, n): if numbers_by_length[i] is not None: numbers_by_length[i] = Array(numbers_by_length[i]) return numbers_by_length
def test_counting_sort_in_place(self): n = random.randint(1, 20) k = 20 elements = [random.randint(1, k) for _ in range(n)] array = Array(elements) counting_sort_in_place(array, k) expected_array = Array(sorted(elements)) assert_that(array, is_(equal_to(expected_array)))
def test_recursive_matrix_chain(self): n = random.randint(1, 10) dimensions = Array([random.randint(1, 999) for _ in range(n + 1)], start=0) m = Array([Array.indexed(1, n) for _ in between(1, n)]) actual_minimum_cost = recursive_matrix_chain(dimensions, m, 1, n) expected_minimum_cost = get_minimum_matrix_product_cost( dimensions, 1, n) assert_that(actual_minimum_cost, is_(equal_to(expected_minimum_cost)))
def knapsack(w, v, W): n = w.length K = Array([Array.indexed(0, W) for _ in between(0, n)], start=0) for j in between(0, W): K[0, j] = 0 for i in between(1, n): for j in between(0, W): K[i, j] = K[i - 1, j] if w[i] <= j and K[i - 1, j - w[i]] + v[i] > K[i, j]: K[i, j] = K[i - 1, j - w[i]] + v[i] return K
def test_bit_reversal_(self): k = random.randint(0, 4) n = 2**k elements = [random.randint(0, 999) for _ in range(n)] array = Array(elements, start=0) original_array = Array(elements, start=0) bit_reversal_(array) for i in between(0, n - 1): assert_that(array[i], is_(equal_to(original_array[rev(k, i)])))
def test_merge_(self): n1 = random.randint(1, 10) n2 = random.randint(1, 10) elements1 = sorted([random.randrange(1000) for _ in range(n1)]) elements2 = sorted([random.randrange(1000) for _ in range(n2)]) array = Array(elements1 + elements2) merge_(array, 1, n1, n1 + n2) expected_array = Array(sorted(elements1 + elements2)) assert_that(array, is_(equal_to(expected_array)))
def test_jugs_match(self): n = random.randint(1, 20) red_elements = [random.randrange(1000) for _ in range(n)] blue_elements = random.sample(red_elements, n) reds_array = Array(red_elements) blues_array = Array(blue_elements) jugs_match(reds_array, blues_array, 1, n) assert_that(reds_array.elements, contains_inanyorder(*red_elements)) assert_that(reds_array, is_(equal_to(blues_array)))
def _create_arrays(): k = random.randint(1, 5) array = Array.indexed(0, k - 1) for i in between(0, k - 1): if random.randint(0, 1) == 0: array[i] = Array([]) else: elements = sorted( [random.randint(0, 2**(k - 1)) for _ in range(2**i)]) array[i] = Array(elements) return array, k
def make_change(n, d): c = Array.indexed(0, n) denom = Array.indexed(1, n) c[0] = 0 for j in between(1, n): c[j] = math.inf for i in between(1, d.length): if j >= d[i] and 1 + c[j - d[i]] < c[j]: c[j] = 1 + c[j - d[i]] denom[j] = d[i] return c, denom
def test_matrix_chain_multiply(self): n = random.randint(1, 10) dimensions = Array([random.randint(1, 10) for _ in range(n + 1)], start=0) A = Array.indexed(1, n) for i in between(1, n): A[i], _ = get_random_matrix(dimensions[i - 1], dimensions[i]) _, optimal_solution = matrix_chain_order(dimensions) actual_product = matrix_chain_multiply(A, optimal_solution, 1, n) expected_product = get_matrix_product(A) assert_that(actual_product, expected_product)
def test_strings_sort(self): size = random.randint(1, 50) elements = [] for _ in range(size): string_length = random.randint(0, 10) elements.append(''.join( random.choice(string.ascii_lowercase) for _ in range(string_length))) array = Array(elements) strings_sort(array) expected_array = Array(sorted(elements)) assert_that(array, is_(equal_to(expected_array)))
def test_print_optimal_parens(self): n = random.randint(1, 10) s = Array([Array.indexed(1, n) for _ in between(1, n)]) for i in between(1, n - 1): for j in between(i + 1, n): s[i, j] = random.randint(i, j - 1) captured_output = io.StringIO() with redirect_stdout(captured_output): print_optimal_parens(s, 1, n) actual_output = captured_output.getvalue().splitlines()[0] expected_output = get_optimal_parens_bruteforce(s, 1, n) assert_that(actual_output, is_(equal_to(expected_output)))
def get_random_huge_array(max_value=999): table_size = max_value table_capacity = random.randint(1, min(20, max_value)) nelements = random.randint(0, table_capacity) table = Array.indexed(0, table_size - 1) stack = Array.indexed(1, table_capacity) keys = random.sample(range(max_value), nelements) for i, key in enumerate(keys): table[key] = i + 1 stack[i + 1] = Element(key) stack.top = len(keys) return table, stack, keys
def test_reset(self): k = random.randint(1, 8) highest = random.randint(-1, k - 1) if highest == -1: elements = [0] * k else: elements = [random.randint(0, 1) for _ in range(highest)] + [1] + [0] * (k - 1 - highest) array = Array(elements, start=0) array.highest = highest reset(array) actual_zero = bits_to_number(array.elements) assert_that(actual_zero, is_(equal_to(0))) assert_that(array.highest, is_(equal_to(-1)))
def dynamic_activity_selector(s, f): n = s.length - 2 c = Array([Array.indexed(0, n + 1) for _ in between(0, n + 1)]) A = Array([Array.indexed(0, n + 1) for _ in between(0, n + 1)]) for l in between(2, n + 2): for i in between(0, n - l + 2): j = i + l - 1 c[i, j] = 0 A[i, j] = set() for k in between(i + 1, j - 1): q = c[i, k] + c[k, j] + 1 if f[i] <= s[k] < f[k] <= s[j] and q > c[i, j]: c[i, j] = q A[i, j] = A[i, k] | {'a' + str(k)} | A[k, j] return A[0, n + 1]
def _construct_secondary_hash_table_no_collisions(keys, size, h_): S = Array.indexed(0, size - 1) for k in keys: if S[h_(k)] is not None: return None S[h_(k)] = k return S
def get_random_single_array_list(min_size=1, max_size=10, max_value=999): list_size = random.randint(min_size, max_size) array_size = 3 * random.randint(list_size, max_size) A = Array.indexed(1, array_size) list_indexes = random.sample(range(1, array_size + 1, 3), list_size) head = None prev_index = None for index in list_indexes: A[index] = random.randint(0, max_value) if prev_index is None: head = index else: A[prev_index + 1] = index A[index + 2] = prev_index prev_index = index free_indexes = [i for i in range(1, array_size + 1, 3) if i not in list_indexes] random.shuffle(free_indexes) free = None prev_free_index = None for free_index in free_indexes: if prev_free_index is None: free = free_index else: A[prev_free_index + 1] = free_index prev_free_index = free_index return SingleArrayList(A, head, free)
def permute_by_sorting(A): n = A.length P = Array.indexed(1, n) for i in between(1, n): P[i] = random(1, n ** 3) _sort_using_priorities(A, P) return A
def matrix_chain_order(p): n = p.length - 1 m = Array([Array.indexed(1, n) for _ in between(1, n)]) s = Array([Array.indexed(1, n) for _ in between(1, n)]) for i in between(1, n): m[i, i] = 0 for l in between(2, n): for i in between(1, n - l + 1): j = i + l - 1 m[i, j] = math.inf for k in between(i, j - 1): q = m[i, k] + m[k + 1, j] + p[i - 1] * p[k] * p[j] if q < m[i, j]: m[i, j] = q s[i, j] = k return m, s
def monge_minimums(A): m = A.rows minimums_indices = _monge_minimums_indices(A) minimums = Array.indexed(1, m) for i in between(1, m): minimums[i] = A[i, minimums_indices[i]] return minimums
def assert_valid_operations(operations, word1, word2): i = 1 j = 1 m = word1.length n = word2.length result = Array.indexed(1, n) for op in operations: if op == 'copy': result[j] = word1[i] i += 1 j += 1 elif op[:11] == 'replace by ': ch = op[11:] result[j] = ch i += 1 j += 1 elif op == 'delete': i += 1 elif op[:7] == 'insert ': ch = op[7:] result[j] = ch j += 1 elif op == 'twiddle': result[j] = word1[i + 1] result[j + 1] = word1[i] i += 2 j += 2 else: assert_that(op, is_(equal_to('kill'))) assert_that(op, is_(equal_to(operations[-1]))) i = m + 1 assert_that(i, is_(equal_to(m + 1))) assert_that(result, is_(equal_to(word2)))
def lis_length(X): n = X.length c = Array.indexed(1, n) b = Array.indexed(1, n) m = 0 b_star = 0 for i in between(1, n): c[i] = 1 b[i] = 0 for j in between(1, i - 1): if X[j] <= X[i] and c[j] + 1 > c[i]: c[i] = c[j] + 1 b[i] = j if c[i] > m: m = c[i] b_star = i return m, b, b_star
def get_random_direct_address_table(): table_size = random.randint(1, 10) nelements = random.randint(0, table_size) elements = [Element(key) for key in random.sample(range(table_size), nelements)] table = Array.indexed(0, table_size - 1) for element in elements: table[element.key] = element return table, elements
def test_counting_sort(self): k = 20 array, elements = get_random_array(max_value=k) actual_sorted_array = Array.indexed(1, array.length) counting_sort(array, actual_sorted_array, k) expected_array = Array(sorted(elements)) assert_that(actual_sorted_array, is_(equal_to(expected_array)))
def optimal_bst(p, q, n): e = Array([Array.indexed(0, n) for _ in between(1, n + 1)]) w = Array([Array.indexed(0, n) for _ in between(1, n + 1)]) root = Array([Array.indexed(1, n) for _ in between(1, n)]) for i in between(1, n + 1): e[i, i - 1] = q[i - 1] w[i, i - 1] = q[i - 1] for l in between(1, n): for i in between(1, n - l + 1): j = i + l - 1 e[i, j] = math.inf w[i, j] = w[i, j - 1] + p[j] + q[j] for r in between(i, j): t = e[i, r - 1] + e[r + 1, j] + w[i, j] if t < e[i, j]: e[i, j] = t root[i, j] = r return e, root
def test_recursive_matrix_chain(self): n = random.randint(1, 10) dimensions = Array([random.randint(1, 999) for _ in range(n + 1)], start=0) m = Array([Array.indexed(1, n) for _ in between(1, n)]) actual_minimum_cost = recursive_matrix_chain(dimensions, m, 1, n) expected_minimum_cost = get_minimum_matrix_product_cost(dimensions, 1, n) assert_that(actual_minimum_cost, is_(equal_to(expected_minimum_cost)))
def lcs_length_(X, Y): m = X.length n = Y.length if m < n: return lcs_length_(Y, X) c = Array([Array.indexed(0, n), Array.indexed(0, n)], start=0) for j in between(0, n): c[0, j] = 0 c[1, 0] = 0 for i in between(1, m): for j in between(1, n): if X[i] == Y[j]: c[1, j] = c[0, j - 1] + 1 else: c[1, j] = max(c[1, j - 1], c[0, j]) for j in between(1, n): c[0, j] = c[1, j] return c[1, n]
def jobs_scheduling(t, p, d): n = p.length a = Array(list(between(1, n))) _sort_jobs_by_deadlines(a, t, p, d) for i in between(1, n): d[i] = min(d[i], n ** 2) P = Array.indexed(0, d[n]) s = Array([Array.indexed(0, d[n]) for _ in between(1, n)]) for j in between(0, d[n]): P[j] = 0 for i in between(1, n): for j in between(0, d[n]): s[i, j] = 0 for i in between(1, n): for j in rbetween(d[n], t[i]): if P[min(j, d[i]) - t[i]] + p[i] > P[j]: P[j] = P[min(j, d[i]) - t[i]] + p[i] s[i, j] = 1 return P, s, a
def bitonic_tsp(p): n = p.length _sort_by_x_coordinates(p) b = Array([Array.indexed(1, n) for _ in between(1, n)]) r = Array([Array.indexed(1, n) for _ in between(1, n)]) b[1, 1] = 0 for j in between(2, n): for i in between(1, j): if i == 1 or i < j - 1: b[i, j] = b[i, j - 1] + _distance(p[j - 1], p[j]) r[i, j] = j - 1 else: b[i, j] = math.inf for k in between(1, i - 1): q = b[k, i] + _distance(p[k], p[j]) if q < b[i, j]: b[i, j] = q r[i, j] = k return b, r
def binary_add(A, B): n = A.length C = Array.indexed(1, n + 1) for i in between(1, n + 1): C[i] = 0 for i in between(1, n): sum = A[i] + B[i] + C[i] C[i] = sum % 2 C[i + 1] = math.floor(sum / 2) return C
def random_hash_table(h, table_size, max_value): table = Array.indexed(0, table_size - 1) nelements = random.randint(0, table.length) keys = [random.randint(0, max_value) for _ in range(nelements)] for key in keys: i = 0 while table[h(key, i, table_size)] is not None: i += 1 table[h(key, i, table_size)] = key return table, keys
def counting_sort(A, B, k): C = Array.indexed(0, k) for i in between(0, k): C[i] = 0 for j in between(1, A.length): C[A[j]] = C[A[j]] + 1 for i in between(1, k): C[i] = C[i] + C[i - 1] for j in rbetween(A.length, 1): B[C[A[j]]] = A[j] C[A[j]] = C[A[j]] - 1