Skip to content

Commit 91e2280

Browse files
committed
Added compression.py, games.py, lattices.py, and number_theory.py problems.
1 parent 0284169 commit 91e2280

File tree

7 files changed

+1298
-118
lines changed

7 files changed

+1298
-118
lines changed

templates/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
from . import chess
44
from . import classic_puzzles
55
from . import codeforces
6+
from . import compression
7+
from . import conways_game_of_life
8+
from . import games
69
from . import game_theory
710
from . import graphs
811
from . import ICPC
912
from . import IMO
13+
from . import lattices
14+
from . import number_theory
1015
from . import probability
1116
from . import study
1217
from . import trivial_inverse

templates/algebra.py

-118
Original file line numberDiff line numberDiff line change
@@ -139,124 +139,6 @@ def gen_random(self):
139139
self.add(dict(coeffs=coeffs)) # won't add duplicates
140140

141141

142-
# @register
143-
# class _3(Problem):
144-
# """
145-
# See [](https://)"""
146-
#
147-
# @staticmethod
148-
# def sat():
149-
# pass
150-
#
151-
# @staticmethod
152-
# def sol():
153-
# pass
154-
#
155-
# def gen_random(self):
156-
# pass
157-
#
158-
#
159-
# @register
160-
# class _4(Problem):
161-
# """
162-
# See [](https://)"""
163-
#
164-
# @staticmethod
165-
# def sat():
166-
# pass
167-
#
168-
# @staticmethod
169-
# def sol():
170-
# pass
171-
#
172-
# def gen_random(self):
173-
# pass
174-
#
175-
#
176-
# @register
177-
# class _5(Problem):
178-
# """
179-
# See [](https://)"""
180-
#
181-
# @staticmethod
182-
# def sat():
183-
# pass
184-
#
185-
# @staticmethod
186-
# def sol():
187-
# pass
188-
#
189-
# def gen_random(self):
190-
# pass
191-
#
192-
#
193-
# @register
194-
# class _6(Problem):
195-
# """
196-
# See [](https://)"""
197-
#
198-
# @staticmethod
199-
# def sat():
200-
# pass
201-
#
202-
# @staticmethod
203-
# def sol():
204-
# pass
205-
#
206-
# def gen_random(self):
207-
# pass
208-
#
209-
#
210-
# @register
211-
# class _7(Problem):
212-
# """
213-
# See [](https://)"""
214-
#
215-
# @staticmethod
216-
# def sat():
217-
# pass
218-
#
219-
# @staticmethod
220-
# def sol():
221-
# pass
222-
#
223-
# def gen_random(self):
224-
# pass
225-
#
226-
#
227-
# @register
228-
# class _8(Problem):
229-
# """
230-
# See [](https://)"""
231-
#
232-
# @staticmethod
233-
# def sat():
234-
# pass
235-
#
236-
# @staticmethod
237-
# def sol():
238-
# pass
239-
#
240-
# def gen_random(self):
241-
# pass
242-
#
243-
#
244-
# @register
245-
# class _9(Problem):
246-
# """
247-
# See [](https://)"""
248-
#
249-
# @staticmethod
250-
# def sat():
251-
# pass
252-
#
253-
# @staticmethod
254-
# def sol():
255-
# pass
256-
#
257-
# def gen_random(self):
258-
# pass
259-
260142

261143
if __name__ == "__main__":
262144
for problem in get_problems(globals()):

templates/compression.py

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
"""Invert a given de/compression algorithm."""
2+
3+
from problems import Problem, register, get_problems
4+
from typing import List
5+
6+
7+
def _compress_LZW(text): # for development
8+
index = {chr(i): i for i in range(256)}
9+
10+
seq = []
11+
buffer = ""
12+
for c in text:
13+
if buffer + c in index:
14+
buffer += c
15+
continue
16+
seq.append(index[buffer])
17+
index[buffer + c] = len(index) + 1
18+
buffer = c
19+
20+
if text != "":
21+
seq.append(index[buffer])
22+
23+
return seq
24+
25+
26+
def _decompress_LZW(seq: List[int]): # for development
27+
index = [chr(i) for i in range(256)]
28+
pieces = [""]
29+
for i in seq:
30+
pieces.append(pieces[-1] + pieces[-1][0] if i == len(index) else index[i])
31+
index.append(pieces[-2] + pieces[-1][0])
32+
return "".join(pieces)
33+
34+
35+
@register
36+
class LZW(Problem):
37+
"""Find a (short) compression that decompresses to the given string.
38+
We have provided a simple version of the *decompression* algorithm of
39+
[Lempel-Ziv-Welch](https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch)
40+
so the solution is the *compression* algorithm.
41+
"""
42+
43+
# _compress_LZW("Hellooooooooooooooooooooo world!") is length-17
44+
45+
@staticmethod
46+
def sat(seq: List[int], compressed_len=17, text="Hellooooooooooooooooooooo world!"):
47+
index = [chr(i) for i in range(256)]
48+
pieces = [""]
49+
for i in seq:
50+
pieces.append((pieces[-1] + pieces[-1][0]) if i == len(index) else index[i])
51+
index.append(pieces[-2] + pieces[-1][0])
52+
return "".join(pieces) == text and len(seq) <= compressed_len
53+
54+
@staticmethod
55+
def sol(compressed_len, text): # compressed_len is ignored
56+
index = {chr(i): i for i in range(256)}
57+
seq = []
58+
buffer = ""
59+
for c in text:
60+
if buffer + c in index:
61+
buffer += c
62+
continue
63+
seq.append(index[buffer])
64+
index[buffer + c] = len(index) + 1
65+
buffer = c
66+
67+
if text != "":
68+
seq.append(index[buffer])
69+
70+
return seq
71+
72+
def gen(self, _target_num_problems):
73+
self.add({"text": "", "compressed_len": 0})
74+
self.add({"text": "c" * 1000, "compressed_len": len(_compress_LZW("c" * 1000))})
75+
76+
def gen_random(self):
77+
max_len = self.random.choice([10, 100, 1000])
78+
text = self.random.pseudo_word(0, max_len)
79+
self.add({"text": text, "compressed_len": len(_compress_LZW(text))})
80+
81+
82+
@register
83+
class LZW_decompress(Problem):
84+
"""Find a string that compresses to the target sequence for the provided simple version of
85+
[Lempel-Ziv-Welch](https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch)
86+
so the solution is the *decompression* algorithm.
87+
"""
88+
89+
@staticmethod
90+
def sat(text: str, seq=[72, 101, 108, 108, 111, 32, 119, 111, 114, 100, 262, 264, 266, 263, 265, 33]):
91+
index = {chr(i): i for i in range(256)}
92+
seq2 = []
93+
buffer = ""
94+
for c in text:
95+
if buffer + c in index:
96+
buffer += c
97+
continue
98+
seq2.append(index[buffer])
99+
index[buffer + c] = len(index) + 1
100+
buffer = c
101+
102+
if text != "":
103+
seq2.append(index[buffer])
104+
105+
return seq2 == seq
106+
107+
@staticmethod
108+
def sol(seq):
109+
index = [chr(i) for i in range(256)]
110+
pieces = [""]
111+
for i in seq:
112+
pieces.append(pieces[-1] + pieces[-1][0] if i == len(index) else index[i])
113+
index.append(pieces[-2] + pieces[-1][0])
114+
return "".join(pieces)
115+
116+
def gen(self, _target_num_problems):
117+
for s in ['', 'a', 'b' * 1000, 'ab' * 1000 + '!']:
118+
self.add({"seq": _compress_LZW(s)})
119+
120+
def gen_random(self):
121+
max_len = self.random.choice([10, 100, 1000])
122+
text = self.random.pseudo_word(0, max_len)
123+
self.add({"seq": _compress_LZW(text)})
124+
125+
126+
@register
127+
class PackingHam(Problem):
128+
"""Pack a certain number of binary strings so that they have a minimum hamming distance between each other.
129+
130+
This is a [classic problem](https://en.wikipedia.org/wiki/Sphere_packing#Other_spaces) in coding theory."""
131+
132+
@staticmethod
133+
def sat(words: List[str], num=100, bits=100, dist=34):
134+
assert len(words) == num and all(len(word) == bits and set(word) <= {"0", "1"} for word in words)
135+
return all(sum([a != b for a, b in zip(words[i], words[j])]) >= dist for i in range(num) for j in range(i))
136+
137+
@staticmethod
138+
def sol(num, bits, dist):
139+
import random # key insight, use randomness!
140+
r = random.Random(0)
141+
while True:
142+
seqs = [r.getrandbits(bits) for _ in range(num)]
143+
if all(bin(seqs[i] ^ seqs[j]).count("1") >= dist for i in range(num) for j in range(i)):
144+
return [bin(s)[2:].rjust(bits, '0') for s in seqs]
145+
146+
def gen_random(self):
147+
bits = self.random.randrange(1, self.random.choice([10, 100]))
148+
num = self.random.randrange(2, self.random.choice([10, 100]))
149+
150+
def score(seqs):
151+
return min(bin(seqs[i] ^ seqs[j]).count("1") for i in range(num) for j in range(i))
152+
153+
# best of 5
154+
seqs = min([[self.random.getrandbits(bits) for _ in range(num)] for _ in range(5)], key=score)
155+
dist = score(seqs)
156+
if dist > 0:
157+
self.add(dict(num=num, bits=bits, dist=dist))
158+
159+
160+
if __name__ == "__main__":
161+
for problem in get_problems(globals()):
162+
problem.test()

0 commit comments

Comments
 (0)