Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f265d19

Browse files
committed
Fixed docstrings, added a couple of human_eval puzzles
1 parent 6ccde8f commit f265d19

File tree

10 files changed

+669
-223
lines changed

10 files changed

+669
-223
lines changed

‎generators/chess.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,10 @@ def gen_random(self):
180180
self.add(dict(m=m, n=n, target=target)) # solved by someone
181181

182182

183-
class UNSOLVED_UncrossedKnightsPath(UncrossedKnightsPath):
183+
class UNSOLVED_UncrossedKnightsPath(PuzzleGenerator):
184184
"""Uncrossed Knights Path (open problem, unsolved)
185185
186-
The goal of these problems is to *beat* the nxn_records from
186+
Similar to above, but the goal of these problems is to *beat* the nxn_records from
187187
[http://ukt.alex-black.ru/](http://ukt.alex-black.ru/)
188188
(accessed 2020年11月29日).
189189
@@ -193,11 +193,37 @@ class UNSOLVED_UncrossedKnightsPath(UncrossedKnightsPath):
193193
unsolved_nxn_records = {10: 61, 11: 76, 12: 94, 13: 113, 14: 135, 15: 158,
194194
16: 183, 17: 211, 18: 238, 19: 268, 20: 302, 21: 337, 22: 375, 23: 414}
195195

196+
@staticmethod
197+
def sat(path: List[List[int]], m=10, n=10, target=62):
198+
"""Find a long (open) tour of knight moves on an m x n chess-board whose edges don't cross."""
199+
def legal_move(m):
200+
(a, b), (i, j) = m
201+
return {abs(i - a), abs(j - b)} == {1, 2}
202+
203+
def legal_quad(m1, m2): # non-overlapping test: parallel or bounding box has (width - 1) * (height - 1) >= 5
204+
(i1, j1), (i2, j2) = m1
205+
(a1, b1), (a2, b2) = m2
206+
return (len({(i1, j1), (i2, j2), (a1, b1), (a2, b2)}) < 4 # adjacent edges in path, ignore
207+
or (i1 - i2) * (b1 - b2) == (j1 - j2) * (a1 - a2) # parallel
208+
or (max(a1, a2, i1, i2) - min(a1, a2, i1, i2)) * (max(b1, b2, j1, j2) - min(b1, b2, j1, j2)) >= 5
209+
# far
210+
)
211+
212+
assert all(i in range(m) and j in range(n) for i, j in path), "move off board"
213+
assert len({(i, j) for i, j in path}) == len(path), "visited same square twice"
214+
215+
moves = list(zip(path, path[1:]))
216+
assert all(legal_move(m) for m in moves), "illegal move"
217+
assert all(legal_quad(m1, m2) for m1 in moves for m2 in moves), "intersecting move pair"
218+
219+
return len(path) >= target
220+
221+
196222
def gen(self, target_num_instances):
197-
for count, n in enumerate(self.nxn_records):
223+
for n in self.unsolved_nxn_records:
198224
if len(self.instances) >= target_num_instances:
199225
return
200-
self.add(dict(m=n, n=n, target=self.nxn_records[n] + 1)) # Note the +1 means breaking the record!
226+
self.add(dict(m=n, n=n, target=self.unsolved_nxn_records[n] + 1)) # Note the +1 means breaking the record!
201227

202228

203229
if __name__ == "__main__":

‎generators/codeforces.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,7 @@ class CombinationLockObfuscated(CombinationLock):
10481048

10491049
@staticmethod
10501050
def sat(states: List[str], start="012", combo="329", target_len=6):
1051+
"""Figure out what this does only from the code"""
10511052
return all(sum((int(a[i]) - int(b[i])) ** 2 % 10 for i in range(len(start))) == 1
10521053
for a, b in zip([start] + states, states[:target_len] + [combo]))
10531054

‎generators/human_eval.py

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2556,7 +2556,6 @@ def gen_random(self):
25562556
self.add(dict(n=n))
25572557

25582558

2559-
25602559
class HexPrimes(PuzzleGenerator):
25612560
"""Inspired by [HumanEval](https://github.com/openai/human-eval) \\#78"""
25622561

@@ -2587,7 +2586,7 @@ def sat(b: str, n=5324680297138495285):
25872586
assert inside[0] == "1" or len(inside) == 1
25882587
m = 0
25892588
for c in inside:
2590-
m = 2*m + int(c)
2589+
m = 2*m + int(c)
25912590
return m == n
25922591

25932592
@staticmethod
@@ -2601,6 +2600,93 @@ def gen_random(self):
26012600
self.add(dict(n=n))
26022601

26032602

2603+
class NearbyDuplicates(PuzzleGenerator):
2604+
"""Inspired by [HumanEval](https://github.com/openai/human-eval) \\#80"""
2605+
2606+
@staticmethod
2607+
def sat(indices: List[int], s="I am an unhappy string!"):
2608+
"""A string is happy if every three consecutive characters are distinct. Find two indices making s unhappy."""
2609+
i, j = indices
2610+
return s[i] == s[j] and 0 <= i < j < i + 3
2611+
2612+
@staticmethod
2613+
def sol(s):
2614+
for i in range(len(s) - 2):
2615+
if s[i] == s[i + 1]:
2616+
return [i, i + 1]
2617+
if s[i] == s[i + 2]:
2618+
return [i, i + 2]
2619+
2620+
def gen_random(self):
2621+
a = self.random.string(min_len=1)
2622+
s = a + self.random.choice(["", self.random.char()]) + a[-1] + self.random.string(min_len=1)
2623+
self.add(dict(s=s))
2624+
2625+
2626+
class Grader(PuzzleGenerator):
2627+
"""Inspired by [HumanEval](https://github.com/openai/human-eval) \\#81"""
2628+
2629+
@staticmethod
2630+
def sat(grades: List[str], gpas=[2.8, 3.1, 4.0, 2.2, 3.1, 2.5, 0.9]):
2631+
"""
2632+
Convert GPAs to letter grades according to the following table:
2633+
4.0: A+
2634+
3.7: A
2635+
3.4: A-
2636+
3.0: B+
2637+
2.7: B
2638+
2.4: B-
2639+
2.0: C+
2640+
1.7: C
2641+
1.4: C-
2642+
below: F
2643+
2644+
Sample input: [4.0, 3.5, 3.8]
2645+
Sample output: ['A+', 'A-', 'A']
2646+
"""
2647+
assert len(grades) == len(gpas)
2648+
letters = ['A+', 'A', 'A-', 'B+', 'B', 'B-', 'C+', 'C', 'C-', 'F']
2649+
scores = [4.0, 3.7, 3.4, 3.0, 2.7, 2.4, 2.0, 1.7, 1.4, 0.0]
2650+
for grade, gpa in zip(grades, gpas):
2651+
i = letters.index(grade)
2652+
assert gpa >= scores[i]
2653+
assert i == 0 or gpa <= scores[i - 1]
2654+
return True
2655+
2656+
@staticmethod
2657+
def sol(gpas):
2658+
letters = ['A+', 'A', 'A-', 'B+', 'B', 'B-', 'C+', 'C', 'C-', 'F']
2659+
scores = [4.0, 3.7, 3.4, 3.0, 2.7, 2.4, 2.0, 1.7, 1.4, 0.0]
2660+
ans = []
2661+
for gpa in gpas:
2662+
i = 0
2663+
while gpa < scores[i]:
2664+
i += 1
2665+
ans.append(letters[i])
2666+
return ans
2667+
2668+
def gen_random(self):
2669+
gpas = [self.random.random() * 4.0 for _ in range(self.random.randrange(10))]
2670+
self.add(dict(gpas=gpas))
2671+
2672+
2673+
class FactorString(PuzzleGenerator):
2674+
"""Inspired by [HumanEval](https://github.com/openai/human-eval) \\#82"""
2675+
2676+
@staticmethod
2677+
def sat(factor: str, s="catscatcatscatcatscat"):
2678+
"""Find a string which when repeated more than once gives s"""
2679+
return len(factor) < len(s) and s == factor * (len(s) // len(factor))
2680+
2681+
@staticmethod
2682+
def sol(s):
2683+
n = len(s)
2684+
return next(s[:i] for i in range(1, len(s)) if s == s[:i] * (n // i))
2685+
2686+
def gen_random(self):
2687+
s = self.random.pseudo_word() * self.random.randrange(2, 10)
2688+
self.add(dict(s=s))
2689+
26042690

26052691
if __name__ == "__main__":
26062692
PuzzleGenerator.debug_problems()

‎generators/number_theory.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
class FermatsLastTheorem(PuzzleGenerator):
1212
"""[Fermat's last theorem](https://en.wikipedia.org/w/index.php?title=Fermat%27s_Last_Theorem)
1313
14-
Find integers a,b,c > 0, n > 2, such such that `a ** n + b ** n == c ** n`
1514
Supposedly unsolvable, but how confident are really in the super-complicated proof?
1615
1716
See [Wiles, Andrew. "Modular elliptic curves and Fermat's last theorem." Annals of mathematics 141.3 (1995): 443-551.](https://www.jstor.org/stable/2118559)"""
1817

1918
@staticmethod
2019
def sat(nums: List[int]):
20+
"""Find integers a,b,c > 0, n > 2, such such that a^n + b^n == c^n"""
2121
a, b, c, n = nums
2222
return (a ** n + b ** n == c ** n) and min(a, b, c) > 0 and n > 2
2323

@@ -28,12 +28,11 @@ class GCD(PuzzleGenerator):
2828
"""[Greatest Common Divisor](https://en.wikipedia.org/w/index.php?title=Greatest_common_divisor&oldid=990943381)
2929
(GCD)
3030
31-
Find the greatest common divisor of two integers.
32-
3331
See also the [Euclidean algorithm](https://en.wikipedia.org/wiki/Euclidean_algorithm)"""
3432

3533
@staticmethod
3634
def sat(n: int, a=15482, b=23223, lower_bound=5):
35+
"""Find a large common divisor of two integers."""
3736
return a % n == 0 and b % n == 0 and n >= lower_bound
3837

3938
@staticmethod
@@ -66,12 +65,11 @@ class GCD_multi(PuzzleGenerator):
6665
"""[Greatest Common Divisor](https://en.wikipedia.org/w/index.php?title=Greatest_common_divisor&oldid=990943381)
6766
(GCD)
6867
69-
Find the greatest common divisor of a *list* of integers.
70-
7168
See also the [Euclidean algorithm](https://en.wikipedia.org/wiki/Euclidean_algorithm)"""
7269

7370
@staticmethod
7471
def sat(n: int, nums=[77410, 23223, 54187], lower_bound=2):
72+
"""Find a large common divisor of the list of integers."""
7573
return all(i % n == 0 for i in nums) and n >= lower_bound
7674

7775
@staticmethod
@@ -96,12 +94,11 @@ class LCM(PuzzleGenerator):
9694
"""[Least Common Multiple](https://en.wikipedia.org/wiki/Least_common_multiple)
9795
(LCM)
9896
99-
Find the least common multiple of two integers.
100-
10197
See also the [Euclidean algorithm](https://en.wikipedia.org/wiki/Euclidean_algorithm)"""
10298

10399
@staticmethod
104100
def sat(n: int, a=15, b=27, upper_bound=150):
101+
"""Find a small common multiple of two integers."""
105102
return n % a == 0 and n % b == 0 and 0 < n <= upper_bound
106103

107104
@staticmethod
@@ -123,12 +120,11 @@ class LCM_multi(PuzzleGenerator):
123120
"""[Least Common Multiple](https://en.wikipedia.org/wiki/Least_common_multiple)
124121
(LCM)
125122
126-
Find the least common multiple of a list of integers.
127-
128123
See also the [Euclidean algorithm](https://en.wikipedia.org/wiki/Euclidean_algorithm)"""
129124

130125
@staticmethod
131126
def sat(n: int, nums=[15, 27, 102], upper_bound=5000):
127+
"""Find a small common multiple of a list of integers."""
132128
return all(n % i == 0 for i in nums) and n <= upper_bound
133129

134130
@staticmethod
@@ -152,15 +148,14 @@ def gen_random(self):
152148
class SmallExponentBigSolution(PuzzleGenerator):
153149
"""Small exponent, big solution
154150
155-
Solve for n: b^n = target (mod n)
156-
157151
Problems have small b and target but solution is typically a large n.
158152
Some of them are really hard, for example, for `b=2, target=3`, the smallest solution is `n=4700063497`
159153
160154
See [Richard K. Guy "The strong law of small numbers", (problem 13)](https://doi.org/10.2307/2322249)"""
161155

162156
@staticmethod
163157
def sat(n: int, b=2, target=5):
158+
"""Solve for n: b^n = target (mod n)"""
164159
return (b ** n) % n == target
165160

166161
@staticmethod
@@ -205,6 +200,7 @@ class ThreeCubes(PuzzleGenerator):
205200

206201
@staticmethod
207202
def sat(nums: List[int], target=10):
203+
"""Given n, find integers a, b, c such that a^3 + b^3 + c^3 = n."""
208204
assert target % 9 not in [4, 5], "Hint"
209205
return len(nums) == 3 and sum([i ** 3 for i in nums]) == target
210206

‎generators/trivial_inverse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,9 +661,9 @@ def gen_random(self):
661661

662662

663663
class IntNegSquareRoot(PuzzleGenerator):
664-
"""Find a negative integer that when squared equals perfect-square a."""
665664
@staticmethod
666665
def sat(n: int, a=10000200001):
666+
"""Find a negative integer that when squared equals perfect-square a."""
667667
return a == n * n and n < 0
668668

669669
@staticmethod

‎make_dataset.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ def save_readme(gen_modules, filename):
5757
n = len(puzzles)
5858
link = f"[{sec_name}](#{sec_name.lower().replace(' ', '-')})"
5959
n_instances = sum(p["n_instances"] for p in puzzles)
60-
tot_instances += len(puzzles)
6160
tot_instances += n_instances
6261
table += f"- [{sec_name} ({len(puzzles):,} problems, {n_instances:,} instances)](#{sec_name.lower().replace(' ', '-')})\n"
6362
for i, puzzle in enumerate(puzzles):
@@ -138,10 +137,15 @@ def main(args):
138137
"examples": examples
139138
}
140139

140+
for p in puzzles:
141+
if p["sat"] == utils.remove_docstring(p["sat"]):
142+
print(p["sat"])
143+
assert False, f"Puzzle {p['name']} in {p['module']} doesn't have a valid docstring"
144+
141145
utils.save_json(puzzles, args.json, make_dirs_if_necessary=True, indent=2)
142146
save_readme(summaries, args.readme)
143147
utils.info(f"Elapsed time: {(time.perf_counter() - start_time) / 60:.2f} minutes")
144-
148+
utils.info(f"Saved {len(puzzles)} to {args.json} and {args.readme}")
145149

146150
if __name__ == "__main__":
147151
args = parser.parse_args()

‎puzzle_generator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,8 @@ def add_test(self, sol_src, run_test_type=False):
362362
"""Assert that the solution satisfies the given instance and add the solution to the instance.
363363
Do a round-trip json encoding/decoding to mimic the actual test and deter strange attacks.
364364
Ideally this could be done by running a protected process (like in evaluating programming
365-
contest submissions) but that is much slower so we will only add that later if the AI
366-
starts misbehaving."""
365+
contest submissions) but that is much slower. Since this is a test we authored presumably it has
366+
no evil code."""
367367

368368
if sol_src in self.sol_srcs: # already added this solution
369369
return

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /