init
This commit is contained in:
14 files changed
+453
No files matched your search
+10
@@ -0,0 +1,10 @@
|
||||
# Python-generated files
|
||||
__pycache__/
|
||||
*.py[oc]
|
||||
build/
|
||||
dist/
|
||||
wheels/
|
||||
*.egg-info
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
@@ -0,0 +1 @@
|
||||
3.14
|
||||
@@ -0,0 +1,17 @@
|
||||
[project]
|
||||
name = "whatcryption"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
authors = [
|
||||
{ name = "lda", email = "[email protected]" }
|
||||
]
|
||||
requires-python = ">=3.14"
|
||||
dependencies = []
|
||||
|
||||
[project.scripts]
|
||||
whatcryption = "whatcryption:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["uv_build>=0.12.19,<0.13.0"]
|
||||
build-backend = "uv_build"
|
||||
@@ -0,0 +1,49 @@
|
||||
from itertools import islice
|
||||
|
||||
from whatcryption.app import App
|
||||
from whatcryption.pairs.bulls import MORE_bulls
|
||||
from whatcryption.pairs.index_mapper import index_mapper
|
||||
from whatcryption.pairs.simple import counter
|
||||
from whatcryption.thing import thing
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("whatcryption")
|
||||
|
||||
def app_gen() -> App:
|
||||
things = [
|
||||
thing(
|
||||
mapper=index_mapper([2, 0, 1, 3]),
|
||||
counter=counter(4, n, c),
|
||||
)
|
||||
for n, c in [(1, 0), (2, 1), (3, 1), (0, 2)]
|
||||
]
|
||||
|
||||
return_mapper = MORE_bulls([1, 0, 3, 2])
|
||||
|
||||
app = App(
|
||||
things=things,
|
||||
return_mapper=return_mapper,
|
||||
)
|
||||
return app
|
||||
|
||||
app = app_gen()
|
||||
print(f"{app.things = }")
|
||||
x = [0, 1, 1, 0, 3, 2, 3, 1, 0, 2, 1, 3, 2, 0, 2, 3, 1, 1, 0, 1, 2]
|
||||
xi = iter(x)
|
||||
c = [app.run(next(xi))]
|
||||
print(f"{app.things = }")
|
||||
print(f"{c = }")
|
||||
assert app.things[0].can_propagate_rotation() is True
|
||||
c = [*c, app.run(next(xi))]
|
||||
assert app.things[0].can_propagate_rotation() is False
|
||||
assert app.things[1].can_propagate_rotation() is True
|
||||
print(f"{app.things = }")
|
||||
c = [*c, *(app.run(i) for i in islice(xi, 3))]
|
||||
print(f"{app.things = }")
|
||||
c = [*c, *(app.run(i) for i in xi)]
|
||||
|
||||
app2 = app_gen()
|
||||
|
||||
c2 = [app2.run(i) for i in c]
|
||||
assert c2 == x, f"c2 = {c2}, x = {x}"
|
||||
@@ -0,0 +1,56 @@
|
||||
from whatcryption.pairs.bulls import MORE_bulls, bulls
|
||||
from whatcryption.thing import thing
|
||||
|
||||
|
||||
class App:
|
||||
def __init__(
|
||||
self,
|
||||
things: list[thing],
|
||||
return_mapper: MORE_bulls,
|
||||
opt_mapper: bulls | None = None,
|
||||
):
|
||||
superverify(return_mapper, things, opt_mapper)
|
||||
self.opt_mapper: bulls | None = opt_mapper
|
||||
self.things: list[thing] = things
|
||||
self.return_mapper: MORE_bulls = return_mapper
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"App(things={self.things}, return_mapper={self.return_mapper}, opt_mapper={self.opt_mapper})"
|
||||
|
||||
def run(self, i: int) -> int:
|
||||
if self.opt_mapper:
|
||||
i = self.opt_mapper.forward(i)
|
||||
|
||||
for this in self.things:
|
||||
i = this.forward(i)
|
||||
i = self.return_mapper.forward(i)
|
||||
for this in reversed(self.things):
|
||||
# it feels like you put something in the stack then pop it...
|
||||
i = this.backward(i)
|
||||
|
||||
propagate_rotation = True
|
||||
for this in self.things: # then IDFK what this shit is
|
||||
this.rotate_if_(propagate_rotation)
|
||||
propagate_rotation = propagate_rotation and this.can_propagate_rotation()
|
||||
if self.opt_mapper:
|
||||
i = self.opt_mapper.backward(i)
|
||||
return i
|
||||
|
||||
|
||||
def superverify(
|
||||
return_mapper: MORE_bulls, things: list[thing], opt_mapper: bulls | None
|
||||
):
|
||||
"on super g"
|
||||
if not return_mapper:
|
||||
raise ValueError("return_mapper must not be None")
|
||||
if not things:
|
||||
raise ValueError("things must not be empty")
|
||||
if opt_mapper is not None and not isinstance(opt_mapper, bulls):
|
||||
raise ValueError("opt_mapper must be a bulls instance or None")
|
||||
|
||||
if not all(len(this) == len(return_mapper) for this in things):
|
||||
raise ValueError(
|
||||
"All things must have the same length, and the same length as return_mapper"
|
||||
)
|
||||
if opt_mapper is not None and len(opt_mapper) != len(return_mapper):
|
||||
raise ValueError("opt_mapper must have the same length as return_mapper")
|
||||
@@ -0,0 +1,62 @@
|
||||
from whatcryption.pairs.bulls import bulls
|
||||
|
||||
int2str = "abcdefghijklmnopqrstuvwxyz"
|
||||
str2int = {c: i for i, c in enumerate(int2str)}
|
||||
|
||||
|
||||
def swaps_to_(swaps: list[tuple[int, int]], l: int) -> list[int]:
|
||||
"""
|
||||
Convert a list of swaps to a permutation of range(l).
|
||||
|
||||
Arguments:
|
||||
swaps (list[tuple[int, int]]): a list of swaps
|
||||
l (int): the length of the permutation
|
||||
|
||||
Returns:
|
||||
list[int]: a permutation of range(l)
|
||||
"""
|
||||
p = list(range(l))
|
||||
for a, b in swaps:
|
||||
p[a], p[b] = p[b], p[a]
|
||||
return p
|
||||
|
||||
|
||||
def verify_swap_list(swaps: list[tuple[int, int]]):
|
||||
"""
|
||||
Verify that a list of swaps is valid.
|
||||
|
||||
Arguments:
|
||||
swaps (list[tuple[int, int]]): a list of swaps
|
||||
Raises:
|
||||
ValueError: if there is (a, b) but also (b, c) in the list.
|
||||
"""
|
||||
seen = set()
|
||||
for i, (a, b) in enumerate(swaps):
|
||||
if a in seen or b in seen:
|
||||
raise ValueError(
|
||||
f"Invalid swap list: {swaps} at index {i}, at pair ({a}, {b}); either number has already been swapped in a previous pair."
|
||||
)
|
||||
seen.add(a)
|
||||
seen.add(b)
|
||||
|
||||
|
||||
def swaps_to_BULLS(swaps: list[tuple[int, int]], l: int, cls: type[bulls]) -> list[int]:
|
||||
"""
|
||||
Convert a list of swaps to a BULLS permutation of range(l).
|
||||
|
||||
since its bullshit.
|
||||
|
||||
Arguments:
|
||||
swaps (list[tuple[int, int]]): a list of swaps
|
||||
l (int): the length of the permutation
|
||||
cls (type[bulls]): the class of BULLS to use for verification
|
||||
|
||||
Returns:
|
||||
list[int]: a BULLS permutation of range(l)
|
||||
"""
|
||||
if not issubclass(cls, bulls):
|
||||
raise TypeError(f"cls must be a subclass of bulls, got {cls}")
|
||||
verify_swap_list(swaps)
|
||||
p = swaps_to_(swaps, l)
|
||||
cls.verify(p)
|
||||
return p
|
||||
@@ -0,0 +1,63 @@
|
||||
"some bullshit"
|
||||
|
||||
from .index_mapper import index_mapper
|
||||
|
||||
|
||||
class bulls(index_mapper):
|
||||
"""forward(x) = backward(x) = i[x]. i[i[x]] = x"""
|
||||
|
||||
@staticmethod
|
||||
def verify(i: list[int]):
|
||||
super(bulls, bulls).verify(i)
|
||||
for id, x in enumerate(i):
|
||||
if i[x] != id:
|
||||
raise ValueError(
|
||||
f"bulls: i[i[x]] != x, i[i[{x}]] = i[{i[x]}] = {id} != {x}"
|
||||
)
|
||||
|
||||
|
||||
class MORE_bulls(bulls):
|
||||
@staticmethod
|
||||
def verify(i: list[int]):
|
||||
super(MORE_bulls, MORE_bulls).verify(i)
|
||||
for id, x in enumerate(i):
|
||||
if id == x:
|
||||
raise ValueError(
|
||||
f"MORE_bulls: i[x] should not equal x, but i[{x}] == {id}"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# test bulls
|
||||
i = [2, 1, 0, 4, 3]
|
||||
m = bulls(i)
|
||||
for x in range(len(i)):
|
||||
assert m.forward(x) == i[x]
|
||||
assert m.backward(x) == i[x], "this"
|
||||
|
||||
try:
|
||||
i = [3, 1, 0, 2]
|
||||
m = bulls(i)
|
||||
except ValueError as e:
|
||||
print(f"caught expected exception: {e}")
|
||||
# because i[0] = 3, but i[3] = 2 != 0
|
||||
|
||||
# test MORE_bulls
|
||||
i = [2, 3, 0, 1]
|
||||
m = MORE_bulls(i)
|
||||
for x in range(len(i)):
|
||||
assert m.forward(x) == i[x]
|
||||
assert m.backward(x) == i[x]
|
||||
|
||||
try:
|
||||
i = [3, 1, 4, 0, 2]
|
||||
m = MORE_bulls(i)
|
||||
except ValueError as e:
|
||||
print(f"caught expected exception: {e}")
|
||||
# because i[1] = 1.
|
||||
try:
|
||||
i = [3, 1, 0, 2]
|
||||
m = MORE_bulls(i)
|
||||
except ValueError as e:
|
||||
print(f"caught expected exception: {e}")
|
||||
# inheritance
|
||||
@@ -0,0 +1,67 @@
|
||||
"""
|
||||
thing <-> index
|
||||
thing2 <-> index2
|
||||
|
||||
index <-> index2
|
||||
|
||||
thing <-> index <-> index2 <-> thing2
|
||||
"""
|
||||
|
||||
|
||||
class index_mapper:
|
||||
def __init__(self, i: list[int]):
|
||||
"""
|
||||
Arguments:
|
||||
i (list[int]): a permutation of range(len(i))
|
||||
"""
|
||||
|
||||
self.verify(i)
|
||||
|
||||
self._i = [*i]
|
||||
self._r = {v: k for k, v in enumerate(i)}
|
||||
self._l = len(i)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"index_mapper(i={self._i})"
|
||||
|
||||
def __len__(self) -> int:
|
||||
return self._l
|
||||
|
||||
def forward(self, x: int) -> int:
|
||||
return self._i[x % self._l]
|
||||
|
||||
def backward(self, x: int) -> int:
|
||||
return self._r[x % self._l]
|
||||
|
||||
@staticmethod
|
||||
def verify(i: list[int]):
|
||||
if not i:
|
||||
raise ValueError("index_mapper: i must not be empty")
|
||||
if set(i) != set(range(len(i))): # this also clears uniqueness
|
||||
raise ValueError("index_mapper: i must be a permutation of range(len(i))")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# test index_mapper
|
||||
i = [4, 2, 0, 1, 3]
|
||||
m = index_mapper(i)
|
||||
for x in range(len(i)):
|
||||
assert m.forward(x) == i[x]
|
||||
assert m.backward(i[x]) == x
|
||||
|
||||
# usage example
|
||||
i = [4, 2, 0, 1, 3]
|
||||
m = index_mapper(i)
|
||||
l = len(i)
|
||||
|
||||
def _r(o):
|
||||
print(f"offset = {o}")
|
||||
for x in range(l):
|
||||
s = x + o
|
||||
f = m.forward(s % l)
|
||||
print(f"forward({x + o} % {l} = {s % l}) = {f}")
|
||||
b = m.backward(f)
|
||||
print(f"backward({f}) = {b}")
|
||||
|
||||
_r(2)
|
||||
_r(3)
|
||||
@@ -0,0 +1,30 @@
|
||||
class counter:
|
||||
def __init__(self, l: int, n: int, c: int):
|
||||
self.l = l
|
||||
self.n = n % l
|
||||
self.init(c)
|
||||
|
||||
def __len__(self) -> int:
|
||||
return self.l
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"counter(l={self.l}, n={self.n}, c={self.c})"
|
||||
|
||||
def init(self, c: int):
|
||||
self.c = c % self.l
|
||||
|
||||
def forward(self, x: int) -> int:
|
||||
return (x + self.c) % self.l
|
||||
|
||||
def backward(self, x: int) -> int:
|
||||
return (x - self.c) % self.l
|
||||
|
||||
def can_propagate_rotation(self) -> bool:
|
||||
return self.c == self.n
|
||||
|
||||
def rotate(self, by: int = 1):
|
||||
self.init(self.c + by)
|
||||
|
||||
def rotate_if_(self, can_rotate: bool):
|
||||
if can_rotate:
|
||||
self.rotate()
|
||||
@@ -0,0 +1,34 @@
|
||||
from whatcryption.pairs.index_mapper import index_mapper
|
||||
from whatcryption.pairs.simple import counter
|
||||
|
||||
|
||||
class thing:
|
||||
"dont switch up the attributes, dont use them after passed. make a new instance"
|
||||
|
||||
def __init__(self, mapper: index_mapper, counter: counter) -> None:
|
||||
if len(mapper) != counter.l:
|
||||
raise ValueError(
|
||||
f"thing: mapper length {len(mapper)} must match counter length {counter.l}"
|
||||
)
|
||||
self.mapper = mapper
|
||||
self.counter = counter
|
||||
|
||||
def forward(self, x: int) -> int:
|
||||
x = self.counter.forward(x)
|
||||
return self.mapper.forward(x)
|
||||
|
||||
def backward(self, x: int) -> int:
|
||||
x = self.mapper.backward(x)
|
||||
return self.counter.backward(x)
|
||||
|
||||
def rotate_if_(self, can_rotate: bool):
|
||||
self.counter.rotate_if_(can_rotate)
|
||||
|
||||
def can_propagate_rotation(self) -> bool:
|
||||
return self.counter.can_propagate_rotation()
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.mapper)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"thing(mapper={self.mapper}, counter={self.counter})"
|
||||
@@ -0,0 +1,9 @@
|
||||
from typing import Protocol
|
||||
|
||||
|
||||
class twowayable(Protocol):
|
||||
def forward(self, x: int) -> int:
|
||||
raise NotImplementedError
|
||||
|
||||
def backward(self, x: int) -> int:
|
||||
raise NotImplementedError
|
||||
@@ -0,0 +1,47 @@
|
||||
# thats why elixir is THE language
|
||||
|
||||
from collections.abc import Callable, Sequence
|
||||
|
||||
|
||||
def ouoe[T](*c: Callable[[T], T]) -> Callable[[T], T]:
|
||||
"pipe"
|
||||
|
||||
def f(x: T) -> T:
|
||||
for c_ in c:
|
||||
x = c_(x)
|
||||
return x
|
||||
|
||||
return f
|
||||
|
||||
|
||||
def LOL[F, T](
|
||||
e: Callable[[F], Callable[[T], T]],
|
||||
o: Callable[[F], Callable[[T], T]],
|
||||
f: Sequence[F],
|
||||
m: Callable[[T], T],
|
||||
):
|
||||
"""
|
||||
for each object in f, apply e(object) to the input, then apply m to the result, then apply o(object) in reverse order to the result of m
|
||||
"""
|
||||
|
||||
def x(q: T) -> T:
|
||||
for i in f:
|
||||
q = e(i)(q)
|
||||
m(q)
|
||||
for i in reversed(f):
|
||||
q = o(i)(q)
|
||||
return q
|
||||
|
||||
return x
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
def f(x: int) -> int:
|
||||
return x + 1
|
||||
|
||||
def g(x: int) -> int:
|
||||
return x * 2
|
||||
|
||||
h = ouoe(f, g)
|
||||
print(h(3)) # Output: 8
|
||||
Reference in new issue
Block a user