Bug in substitution decryption in python - python

import random
orig=list(range(1,65))
temp_orig= [[0, 1, 2, 3, 4, 5, 6, 7],
[8, 9, 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, 30, 31],
[32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47],
[48, 49, 50, 51, 52, 53, 54, 55],
[56, 57, 58, 59, 60, 61, 62, 63]]
ip= [[40, 24, 9, 41, 42, 56, 43, 45],
[4, 23, 21, 60, 35, 6, 59, 0],
[36, 53, 32, 16, 7, 37, 17, 18],
[10, 62, 61, 38, 29, 34, 31, 25],
[54, 57, 51, 49, 39, 3, 50, 30],
[11, 46, 33, 27, 44, 15, 13, 48],
[12, 58, 1, 26, 47, 20, 28, 52],
[19, 55, 2, 63, 22, 8, 14, 5]]
ipinv=[[15, 50, 58, 37, 8, 63, 13, 20],
[61, 2, 24, 40, 48, 46, 62, 45],
[19, 22, 23, 56, 53, 10, 60, 9],
[1, 31, 51, 43, 54, 28, 39, 30],
[18, 42, 29, 12, 16, 21, 27, 36],
[0, 3, 4, 6, 44, 7, 41, 52],
[47, 35, 38, 34, 55, 17, 32, 57],
[5, 33, 49, 14, 11, 26, 25, 59]]
print "\n\nOriginal position of Bits:"
for i in range(len(ipinv)):
print "\t",temp_orig[i]
print "\n\nInitial Permutation Table"
for i in range(len(ipinv)):
print "\t",ip[i]
print "\n\nInverse Initail permutation Table"
for i in range(len(ipinv)):
print "\t",ipinv[i]
print "\nRound 1:Initial Permutation"
plaintext=list(raw_input("\n\tEnter not more than 8 char:"))
l=len(plaintext)
for i in range(8,len(plaintext)):
del plaintext[l-1+8-i]
print "\n\tPlain text:",plaintext,"\n"
for i in range(8):
plaintext[i]=list(bin(ord(plaintext[i])).zfill(8))
print "\t",plaintext[i]
ip1=temp_orig
for i in range(8):
for j in range(8):
ip1[i][j]=plaintext[(ip[i][j])/8][(ip[i][j])%8]
print "\nEnciphered list:"
for i in range(8):
print "\t",ip1[i]
print "\n73\n",ip1[7][3],"\n73"
ip1_d=temp_orig
for i in range(8):
for j in range(8):
ip1_d[i][j]=ip1[(ipinv[i][j])/8][(ipinv[i][j])%8]
print ip1[7][3],"ip1_d",[i],[j],"=ip1[",(ipinv[i][j])/8,"][",(ipinv[i][j])%8,"]"
#print "ip1_d",[i],[j],"=",ip1[(ipinv[i][j])/8][(ipinv[i][j])%8]
print "\nDeciphered list:"
for i in range(8):
print "\t",ip1_d[i]
The de sunstitution becomes wrong, just for example i tried printing ip1[7][3] and all of a sudden it changes value when i=7 and j=3 without any assignment to ip1

You do ip1=temp_orig a few times. That tells me that you probably think this copies the temp_orig list - it does not. You have to explicitly copy the list here:
ip1=[list(row) for row in temp_orig]
and so on. Your code just gives new names to temp_orig but still modifies the temp_orig list.
I think this is the most chaotic code I've seen in a while. You should start thinking more in terms of transformations of your data instead of juggling indices like this. I still have no idea what your code does or how it's supposed to work.

Related

np.take from 3D matrix given indices of second dimension

given a 3D array:
a = np.arange(3*4*5).reshape(3,4,5)
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]],
[[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29],
[30, 31, 32, 33, 34],
[35, 36, 37, 38, 39]],
[[40, 41, 42, 43, 44],
[45, 46, 47, 48, 49],
[50, 51, 52, 53, 54],
[55, 56, 57, 58, 59]]])
I would like to create the following matrix:
result =
array([[20, 21, 22, 23, 24],
[ 5, 6, 7, 8, 9],
[50, 51, 52, 53, 54],
[55, 56, 57, 58, 59]])
Using the indices idx = [1,0,2,2]
I.e, I would like to "take" per matrix, the row specified in idx, where len(idx)==a.shape[1] and np.max(idx)<a.shape[0] as idx choose from dimension 1.
Given that your array has three dimensions (x,y,z), since you want to take one value for each row in the yth direction, you can do this:
a[idx, range(a.shape[1])]
Output:
array([[20, 21, 22, 23, 24],
[ 5, 6, 7, 8, 9],
[50, 51, 52, 53, 54],
[55, 56, 57, 58, 59]])

How to format multiplication table via Python using nested list?

I'm using Python to create a 12*12 multiplication table.
The table is held in memory in a nested list multi_table, where:
multi_table[0][0] holds “X”
The first row holds the number i for every position i
The first column holds the number j for every position j
each product i*j is stored in position multi_table[i][j].
The multiplication table is shown in Figure 1 below.
Figure 1: Multiplication Table
Umm, what is the question? By how to format do you mean how to generate this nested list?
If so, how about:
n = 12
table = [['X'] * (n+1) for _ in range(n+1)]
for i in range(1, n+1):
table[i][0] = i
for j in range(1, n+1):
table[0][j] = j
table[i][j] = i*j
table
[['X', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
[1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
[2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24],
[3, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36],
[4, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48],
[5, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60],
[6, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72],
[7, 7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84],
[8, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96],
[9, 9, 18, 27, 36, 45, 54, 63, 72, 81, 90, 99, 108],
[10, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
[11, 11, 22, 33, 44, 55, 66, 77, 88, 99, 110, 121, 132],
[12, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144]]

Modifying a part of the main diagonal of a 2d-numpy array

I'm having problems with the following task.
Assume we have a matrix, looking like this:
Mat = np.array([
[11, 12, 13, 14, 15], \
[21, 22, 23, 24, 25], \
[31, 32, 33, 34, 35], \
[41, 42, 43, 44, 45], \
[51, 52, 53, 54, 55]])
What I want to do is to replace the entries 22, 33 and 44 with something different that I calculated before. I know I could do this with for loops but I think there has to be a more elegant way.
I have something like this in mind:
Subselect the main diagonal from [1,1] to [-2,-2] and save it as an array.
Modify this array in the desired manner.
Save the modified array as part of the main diagonal of the matrix.
I found the np.diagonal() to get the diagonal and got so far:
Mat = np.array([
[11, 12, 13, 14, 15], \
[21, 22, 23, 24, 25], \
[31, 32, 33, 34, 35], \
[41, 42, 43, 44, 45], \
[51, 52, 53, 54, 55]])
print(Mat)
snipA = Mat.diagonal()
snipB = snipA[1:len(snipA)-1]
print(snipA)
print(snipB)
There are two problems now. First, I cannot modify snipB in any way. I get the error: "output array is read-only". Second, how can I save a modified snipB into the matrix again?
Any help is appreciated.
You can index and modify a part of the diagonal like so:
>>> subdiag = np.arange(1, len(mat)-1)
>>> mat[subdiag, subdiag]
array([22, 33, 44])
>>> mat[subdiag, subdiag] = 0
>>> mat
array([[11, 12, 13, 14, 15],
[21, 0, 23, 24, 25],
[31, 32, 0, 34, 35],
[41, 42, 43, 0, 45],
[51, 52, 53, 54, 55]])
>>>
>>> mat[subdiag, subdiag] = [22, 33, 44]
>>> mat
array([[11, 12, 13, 14, 15],
[21, 22, 23, 24, 25],
[31, 32, 33, 34, 35],
[41, 42, 43, 44, 45],
[51, 52, 53, 54, 55]])
You can also do this with einsum since numpy 1.10
np.einsum('ii->i', mat)[1:-1] = 0
mat
array([[11, 12, 13, 14, 15],
[21, 0, 23, 24, 25],
[31, 32, 0, 34, 35],
[41, 42, 43, 0, 45],
[51, 52, 53, 54, 55]])

How to select subarrays in numpy 1D array with minimal, average and maximal area values?

def distancesplit(self):
img = np.asarray(Image.open("testtwo.tif").convert('L'))
img = 1 * (img < 127)
areasplit = np.split(img.ravel(), 24) # here we are splitting converted to 1D array
for i in areasplit:
area = (i == 0).sum()
print area
How to select subarrays in areasplit with minimal, average and maximal area values?
For max:
areasplit[argmax(sum(areasplit==0, axis=0)), :]
replace argmax with argmin for min: have you considered there may be several array meet you criteria?
Example:
>>> from numpy import *
>>> a=array(range(81))
>>> b=split(a, 9)
>>> b#be careful it is a list of arrays not just an array
[array([0, 1, 2, 3, 4, 5, 6, 7, 8]), array([ 9, 10, 11, 12, 13, 14, 15, 16, 17]), \
array([18, 19, 20, 21, 22, 23, 24, 25, 26]), array([27, 28, 29, 30, 31, 32, 33, 34, 35]), \
array([36, 37, 38, 39, 40, 41, 42, 43, 44]), array([45, 46, 47, 48, 49, 50, 51, 52, 53]), \
array([54, 55, 56, 57, 58, 59, 60, 61, 62]), array([63, 64, 65, 66, 67, 68, 69, 70, 71]), \
array([72, 73, 74, 75, 76, 77, 78, 79, 80])]
>>> b=array(split(a, 9)) #I prefer to use b.reshape((-1,9)) over split()., which returns an array.
>>> b#now it is an array
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8],
[ 9, 10, 11, 12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23, 24, 25, 26],
[27, 28, 29, 30, 31, 32, 33, 34, 35],
[36, 37, 38, 39, 40, 41, 42, 43, 44],
[45, 46, 47, 48, 49, 50, 51, 52, 53],
[54, 55, 56, 57, 58, 59, 60, 61, 62],
[63, 64, 65, 66, 67, 68, 69, 70, 71],
[72, 73, 74, 75, 76, 77, 78, 79, 80]])
>>> b[argmax(sum(b, axis=1)), :]
array([72, 73, 74, 75, 76, 77, 78, 79, 80])
>>> b[argmin(sum(b, axis=1)), :]
array([0, 1, 2, 3, 4, 5, 6, 7, 8])
>>> b[argwhere(median(b)==median(b, axis=1)).flatten(),:] #be careful there may be several matching sub-arrays
array([[36, 37, 38, 39, 40, 41, 42, 43, 44]])
>>> b[argwhere(mean(b)==mean(b, axis=1)).flatten(),:]
array([[36, 37, 38, 39, 40, 41, 42, 43, 44]])

python equivalent to clojure's partition-all?

looking for something in python's standard lib or a syntax trick.
for non-clojure programmers, partition-all should have these semantics:
partition_all(16, lst) == [lst[0:16], lst[16:32], lst[32:48], lst[48:60]]
assuming len(lst) == 60
There is no such function in Python. You can do this:
from itertools import islice
def chunkwise(n, iterable):
it = iter(iterable)
while True:
chunk = list(islice(it, n))
if not chunk:
break
yield chunk
print list(chunkwise(3, range(10)))
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
Adding a third "step size" parameter to the range built-in function gets you pretty close:
>>> range(0,60,16)
[0, 16, 32, 48]
You can create tuples for the upper and lower bounds from there:
>>> [(i, i+16) for i in range(0, 60, 16)]
[(0, 16), (16, 32), (32, 48), (48, 64)]
Or create the actual ranges if you need them:
>>> [range(i, i+16) for i in range(0, 60, 16)]
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47], [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63]]
Naturally you can parameterize the 0, 60, and 16 into your own function if you need to.
I don't think there is a partition_all like function in the standard library so I'm afraid you are writing your own. However looking at https://github.com/clojure/clojure/blob/b578c69d7480f621841ebcafdfa98e33fcb765f6/src/clj/clojure/core.clj#L5599 I'm thinking you could implement it in Python like this:
>>> from itertools import islice
>>> lst = range(60)
>>> def partition_all(n, lst, step=None, start=0):
... step = step if step is not None else n
... yield islice(lst, start, n)
... while n < len(lst):
... start, n = start + step, n + step
... yield islice(lst, start, n)
...
>>>
>>> for partition in partition_all(16, lst):
... l = list(partition)
... print len(l), l
...
16 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
16 [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
16 [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]
12 [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
>>>
The recipes section of the itertools documentation has a grouper function that does what you want.
from itertools import zip_longest
def grouper(iterable, n, fillvalue=None):
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)
Beware that there's also a recipe for "partition", but that does something different.
I believe I have a shorter answer which does not require importing any libraries.
Here is a one-liner for you:
>>> lst = list(range(60))
>>> [lst[i * 16: (i + 1) * 16] for i in range(len(lst) / size + int((len(lst) % 16) > 0)))
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47], [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]]
Now as a function (assumes that you work with a list):
def partition(lst, size):
assert(size >= 0)
if not lst: return ()
return (lst[i * size: (i + 1) * size] for i in range(len(lst) / size + int((len(lst) % size) > 0)))
>>> partition(list(range(78)), 17)
<generator object <genexpr> at 0x7f284e33d5a0>
>>> list(partition(list(range(78)), 17))
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33], [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50], [51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67], [68, 69, 70, 71, 72, 73, 74, 75, 76, 77]]
>>> list(partition(range(16), 4))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]
>>> print list(partition(range(0), 4))
[]
EDIT: New solution based on Triptych's answer:
def partition(lst, size):
assert(size >= 0)
if not lst: return ()
return (lst[i: i + size] for i in range(0, len(lst), size))
>>> partition(list(range(78)), 17)
<generator object <genexpr> at 0x025F5A58>
>>> list(partition(list(range(78)), 17))
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33], [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50], [51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67], [68, 69, 70, 71, 72, 73, 74, 75, 76, 77]]
>>> list(partition(list(range(16)), 17))
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]]
>>> list(partition(list(range(16)), 4))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]
>>> list(partition([], 17))
[]
>>>

Categories

Resources