How to reduce multiple sets of possible character mappings? - python

I am running a slide attack on a cipher to determine the cipher's key. I want to know if there is an existing mathematical/programmatic-based representation I could use within this attack. Below is a list of mapping relationships compiled by comparing various outputs and their respective inputs. It reads as follows, where '->' is used to represent a mapping from the lhs to the rhs:
If b->d... then z->i AND q->f.
Likewise, if z->i AND q->f... then b->d.
Alphabet: 'abcdefghijklmnopqrstuvwxyz_'
Example key: 'uwmsqbhkc_pgvtilnyfexjzarod' (i.e. a shuffled alphabet)
c1 c2 c3 c4
===============
a: t, g | o, t
b: z, q | x, q
c: w, t | c, _
d: i, h | i, f
e: w, y | t, e
f: u, e | e, d
g: w, _ | y, m
h: n, m | z, d
i: i, j | h, f
j: l, h | r, g
k: w, b | t, v
l: r, c | e, b
m: l, u | z, e
n: r, i | x, y
o: g, s | e, a
p: t, f | z, w
q: u, r | z, r
r: s, a | p, o
s: t, _ | c, k
t: n, t | y, c
u: a, o | e, h
v: y, l | g, x
w: x, z | o, n
x: z, n | u, i
y: k, z | f, u
z: t, x | a, o
_: o, s | g, k
Additionally, the character frequencies of c1 and c2 MUST match the character frequencies of c3 and c4, respectively. In pseudo code, len(c1[freq1]) == len(c3[freq1]) and len(c2[freq2]) == len(c4[freq2]). Based on this, I have generated the following frequency "table" (a dictionary[freq: set(chars)] per column) where you can visually confirm this behavior:
c1: {4: {w, t}, 2: {u, i, r, l, z, n}, 1: {a, s, k, x, o, g, y}}
c3: {4: {e, z}, 2: {c, x, t, o, g, y}, 1: {u, i, r, a, f, p, h}}
c2: {2: {_, s, z, t, h}, 1: {n, m, q, b, u, i, r, a, c, f, l, x, e, j, o, g, y}}
c4: {2: {d, f, k, e, o}, 1: {y, n, m, q, b, u, i, a, _, r, c, x, w, v, g, t, h}}
This frequency table is what gives me a start on cracking the cipher. In the case of sets with a single character, we automatically learn the associated character mapping. Otherwise, we need to cross reference to learn mappings. The two methods I used to accomplish this are set intersections and set differences. For example, note that both c1[4] and c2[2] contain the character t. If we take the intersection of their potential mappings (i.e. c3[4] and c4[2]), we are left with the set {e} and thus t->e. Finding mappings via set differences is similar, so I won't give an example. Mappings found here can often be used to derive additional mappings from the first table.
In terms of this program, I am trying to find the best way to reduce the set of possibilities using physically-derived pieces of information via the methods above. Is there an existing mathematical/programmatic-based representation of this process? What's the proper name of this process? Additionally, are there more methods for extracting information that I'm not seeing?
Thanks!
-yuno

Related

Simplify sympy integral expressions

With
x, a, b, c = symbols ('x a b c')
f = Function ('f') (x)
is there a way to simplify
integrate (f, (x, a, b)) + integrate (f, (x, b, a))
and
integrate (f, (x, a, c)) + integrate (f, (x, c, b)) - integrate (f, (x, a, b))
to zero?
Reference: https://en.wikipedia.org/wiki/Integral#Conventions
The first case can be handled by using a traversal that puts the limits in canonical order:
def iss(i):
if isinstance(i, Integral):
s = 1
lim = list(i.limits)
for j, xab in enumerate(lim):
if len(xab) == 3:
x, a, b = xab
if [a,b]!=list(ordered([a,b])):
lim[j] = (x, b, a)
s *= -1
return i.func(i.function, lim).simplify()*s
return i
>>> eq = integrate (f, (x, a, b)) + integrate (f, (x, b, a))
>>> bottom_up(eq, iss)
0
For the second case there are lots of possible expressions to deal with. But to deal with the type you have shown perhaps the following will work:
def collapse_integrals(a):
from collections import defaultdict
if not a.is_Add: return a
i, d = a.as_independent(Integral)
if not d.is_Add:
return a
if i:
return i + collapse_integrals(d)
igls = defaultdict(list)
other = []
for ai in a.args:
c, i = ai.as_independent(Integral, as_Add=False)
if abs(c) != 1:
other.append(ai)
continue
if not isinstance(i,Integral) or not (len(i.limits) == 1 and len(i.limits[0])==3):
other.append(ai)
else:
igls[(c, i.function)].append(i.limits[0][1:])
for k in igls:
if len(igls[k]) > 1:
n = len(igls[k])
lims = igls[k]
cond = []
nul = (None, None)
for i in range(n):
if lims[i] == nul:continue
for j in range(i + 1, n):
if lims[i][0] == lims[j][1]:
cond.append((lims[j][0],lims[i][1]))
elif lims[i][1] == lims[j][0]:
cond.append((lims[i][0],lims[j][1]))
else:
continue
lims[i] = lims[j] = nul
if cond:
igls[k] = cond + [i for i in lims if i != nul]
c, f = k
other.extend([c*Integral(f, l) for l in igls[k]])
return Add(*other)
>>> eq = integrate (f, (x, a, c)) + integrate (f, (x, c, b)) - integrate (f, (x, a, b))
collapse_integrals(bottom_up(eq,iss))
0

How to fix tic-tac-toe two player bug

I am trying to make a tic-tac-toe game however when I try implement two players, the printed out result (current game state) is not as expected.
for example when I try to put the letter 'x' in box 1 it will add random letters/numbers in different spots. I have already tried this with only one player and it wrks perfectly.
import random
a = ' '
b = ' '
c = ' '
d = ' '
e = ' '
f = ' '
g = ' '
h = ' '
i = ' '
def gamestateboard(a, b, c, d, e, f, g, h, i):
x = [a, b, c]
y = [d, e, f]
z = [g, h, i]
print(x)
print(y)
print(z)
gamestateboard(a, b, c, d, e, f, g, h, i)
def checkwin():
if a == 0 and b == 0 and c == 0:
print('Winner')
if a == 0 and d == 0 and g == 0:
print('Winner')
if g == 0 and h == 0 and i == 0:
print('Winner')
if c == 0 and e == 0 and g == 0:
print('Winner')
if a == 0 and e == 0 and i == 0:
print('Winner')
if c == 0 and f == 0 and i == 0:
print('Winner')
for i in range(1000000):
inputs = str(input('Enter a position: '))
if i%2 == 0:
if inputs == '1':
a = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '2':
b = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '3':
c = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '4':
d = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '5':
e = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '6':
f = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '7':
g = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '8':
h = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '9':
i = 0
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
else:
if inputs == '1':
a = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '2':
b = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '3':
c = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '4':
d = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '5':
e = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '6':
f = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '7':
g = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '8':
h = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
if inputs == '9':
i = 'X'
gamestateboard(a, b, c, d, e, f, g, h, i)
checkwin()
You are using i as your loop variable but also the name of a variable you use to draw in your game world.
I recommend moving away from having these variables and using indexes.
gameworld =[ [' ',' ',' '] for i in range(3)]
def draw_world():
for i in range(3):
print(gameworld[i])
then you can ask for coordinates or divide and use the modulus to use a single value like you did before. 4 // 3 = 1 4 % 3 = 1 position 4 is at [1][1]
This means you don't need your giant if input == list.
edit: Oh yeah you probably also want to do a loop with something like
no_winner = True
while no_winner:
...
you can set no_winner to False if check_win returns true and then you game doens't go on forever
edit 2:
Almost forgot you have an indenting error with the else for i%2==0 though I'm guessing that may be just from when you copied and pasted into your question. You also never check to see if someone else has already taken a square so when your code does actually work a player can overwrite another player's move.

Equation in MATLAB and Python given different result

Currently I'm translating my MATLAB code to Python version,
function u = afterslip(A, B, C, D, E, X, Ta, Tb, Tc)
u = A*log(1+X/Ta) + B + C*log(1+X/Tb) - D*exp(-X/Tc) + E;
end
to:
from math import log,exp
def afterslip(A, B, C, D, E, Ta, Tb, Tc):
e = A*log(1+X/Ta) + B + C*log(1+X/Tb) - D*exp(-X/Tc) +
return e
But when I calculated using X=187, Ta=8, Tb=80, Tc=600, A=-27, B=-18, C=56, D=-71, and E=-18 both given different result. Anyone knows why this happened and how to fix it?
The second function misses argument X. See below.
def afterslip(A, B, C, D, E, X, Ta, Tb, Tc):
return A*log(1+X/Ta) + B + C*log(1+X/Tb) - D*exp(-X/Tc) + E

performing more complex calculations on groupby objects

I am currently looking to do some calculations on a large dataset of options where I want first to split the data according to the strike price and expiry, then perform a set of calculations shown below onto each subgroup. I have been able to separate the data using groupby to get the split I want, I also wrote the calculation i want to do which works when tested on a subgroup. The only problem I have is to combine the two together.
Here is the code I used to group my data:
grouped =df.groupby(['Expiry','Strike'])
I had a read online and they mentioned the use of the apply function but the examples only included simple functions such as summation or averages.
Here is the calculation that I would like to perform on each subgroup data, where x,y,z,u,R are columns that in each subset that is the same for all subgroups:
def p(d, S, B, c):
return d * S + B - c
def b_t(r, b_old, S, d, d_old, t):
return np.exp(r * t) * b_old + S * (d_old - d)
def e_t(d_old, S, c, r, t, b_old):
return d_old * S - c + np.exp(r * t) * b_old
P_results = []
B_results = []
E_results = []
for i,(d,S,c,t,r) in enumerate(zip(x,y,z,u,R)):
B = b_t(r, b_old, S, d, d_old, t)
P = p(d, S, B, c)
E = e_t(d_old, S, c, r, t, b_old)
print('i={},P={},B={},E={}'.format(i,P,B,E))
B_results.append(B)
P_results.append(P)
E_results.append(E)
b_old = B
d_old = d
I thought maybe if I could save each subset as a new variable dataframe then maybe it could work but I haven't been able to do that.
I hope this is clear and I think posting some data would help but I am not sure how best to upload it here.
Much appreciate your help!
UPDATE 1: Found a solution that works
grouped =df.groupby(['Expiry','Strike'])
lg = list(grouped)
P_results = []
l_results =[]
B_results = []
E_results = []
for l in range(len(lg)):
df2=lg[l][1]
d_old = df2.iloc[0, 4]
S_old = df2.iloc[0, 8]
c_old = df2.iloc[0, 10]
b_old = c_old - d_old * S_old
x = df2.iloc[1:, 4]
y = df2.iloc[1:, 8]
z = df2.iloc[1:, 10]
u = df2.iloc[1:, 9]
R = df2.iloc[1:, 7]
for i, (d, S, c, t, r) in enumerate(zip(x, y, z, u, R)):
B = b_t(r, b_old, S, d, d_old, t)
P = p(d, S, B, c)
E = e_t(d_old, S, c, r, t, b_old)
print('i={},P={},B={},E={}'.format(i, P, B, E))
l_results.append(l)
B_results.append(B)
P_results.append(P)
E_results.append(E)
b_old = B
d_old = d
BB = pd.DataFrame(np.column_stack([l_results, P_results,
E_results,B_results]),columns=['l','P','E','B'])
All I did was to transform grouped into a callable list and then call each of the sections out using a for loop then use another for loop to perform the calculations. It is not the prettiest output, I put l_results there to show which group the calculations were referring to but seems to be sufficient for now. If there is any better way please let me know!

whats wrong with this while loop in Python?

Ok so I have spent hours trying to resolve this and I feel its some simple error but I cannot find a way to resolve this.
the section I am having issues with is the second half of the code. There seems to be an infinite loop somewhere among the 2 nested while loops. If anyone is able to help, this would be great, thanks in advance.
import sympy as sym
import random
A, B, C, D, E, F, G, H, I, J = sym.symbols('A, B, C, D, E, F, G, H, I, J')
picks_a_person = [A, B, C, D, E, F, G, H, I, J] #List of people picking a name from a hat
person_gets_picked = [A, B, C, D, E, F, G, H, I, J] # List of names drawn from a hat
def re_draws(p):
n = 0
count = 0
while n < 1000: #Repeats the test 1000 times for an accurate percentage
n += 1
random.shuffle(person_gets_picked) #Chooses a random order of the list of names drawn
for i in range(p):
if person_gets_picked[i] == picks_a_person[i]: #Checks for all 'p' elements of the lists are different
count = count + 1
print("count = " + str(count)) #Returns the number of times a re-draw was not required
import numpy as np
from collections import Counter
total = []
while len(total) < 1000:
order = []
picks_a_person = [A, B, C, D, E, F, G, H, I, J]
person_gets_picked = [A, B, C, D, E, F, G, H, I, J]
while len(order) < 10:
a = person_gets_picked[random.randint(0, (len(person_gets_picked)-1))]
if a != picks_a_person[0]:
order.append(a)
person_gets_picked.remove(a)
del picks_a_person[0]
total.append(order)
Counter(np.array(total)[:,1])
While there are a lot of odd things about your code, this is where it gets into an infinite loop:
picks_a_person = [A, B, C, D, E, F, G, H, I, J]
person_gets_picked = [A, B, C, D, E, F, G, H, I, J]
while len(order) < 10:
a = person_gets_picked[random.randint(0, (len(person_gets_picked)-1))]
if a != picks_a_person[0]:
order.append(a)
person_gets_picked.remove(a)
del picks_a_person[0]
total.append(order)
Let's do some rubber duck debugging - what happens when your random.randint(0, (len(person_gets_picked)-1)) returns a number larger than 0 nine times in a row (worst case scenario)? All person_gets_picked elements except A get removed and added to the order list (which is still under 10 elements to break away from the while loop).
At that point we have a state as picks_a_person = [A] and person_gets_picked = [A]. random.randint(0, (len(person_gets_picked)-1)) will, thus, always return 0, a will always be set to A and since picks_a_person[0] == A the condition if a != picks_a_person[0] will never be evaluated as True, hence the order will never get its 10th element and therefore you got yourself an infinite loop.
It doesn't even have to be nine positive numbers in a row for this to occur - all it needs to happen is for A to remain as one of the last two picks and for random to land on the other option.
So why don't you write your whole loop as:
persons = [A, B, C, D, E, F, G, H, I, J]
persons_num = len(persons)
total = [random.sample(persons, persons_num) for _ in range(1000)]
And you're done.

Categories