Magic Squares - Siamese Method - python

Is it possible to do magic squares with the Siamese/De La Loubere method without using modulo?
I would like to make odd n x n magic squares using it.

Yes, it's possible. Written on Python 3.5:
def siamese_method(n):
assert(n % 2 != 0), 'Square side size should be odd!'
square = [[0 for x in range(n)] for x in range(n)]
x = 0
y = int((n + 1) / 2 - 1)
square[x][y] = 1
for i in range(2, n * n + 1):
x_old = x
y_old = y
if x == 0:
x = n - 1
else:
x -= 1
if y == n - 1:
y = 0
else:
y += 1
while square[x][y] != 0:
if x == n - 1:
x = 0
else:
x = x_old + 1
y = y_old
square[x][y] = i
for j in square:
print(j)
siamese_method(3)
I've got following on output:
[8, 1, 6]
[3, 5, 7]
[4, 9, 2]

Related

List Indices must be integer or slices, not float

So I was creating a median calculator, and I came upon this error (the heading)
def median(x):
#finds the median of a column
if len(x) % 2 == 0:
y = len(x) / 2
medknot = x[y] + x[y][-1]
med = medknot / 2
return med
elif len(x) % 2 == 1:
y = len(x)//2
med = x[y]
return med
l1 = [5, 6, 7, 8, 9, 6, 5, 5]
print(median(l1))
What is the error in my code?
/ always returns a float, even if the result could be an integer.
>>> 1/1
1.0
Use:
y = len(x) // 2
Also, the next line doesn't make sense:
medknot = x[y] + x[y][-1]
As the output of x[y] should be a scalar. You probably want medknot = x[y] + x[y-1]
Finally, the input list should be sorted to compute a correct median.
You can also simplify the code:
def median(x):
# sort x
x = sorted(x)
y = len(x) // 2
med = x[y]
if len(x) % 2 == 0:
med = (med + x[y-1])/2
return med
print(median([1, 2, 3]))
# 2
print(median([1, 2, 3, 4]))
# 2.5
print(median([4, 1, 2, 3]))
# 2.5

Operations on Sequences - Codewars Kata - Best Performance

This is a codewars problem. The idea is given that arr = [x(1), x(2), x(3), x(4), ..., x(i), x(i+1), ..., x(m), x(m+1)] where all x(i) are positive integers. (the length (len(arr)) of this array will be a positive multiple of 4)
And let P = (x(1) ** 2 + x(2) ** 2) * (x(3) ** 2 + x(4) ** 2) * ... * (x(m) ** 2 + x(m+1) ** 2)
Find A and B such that A**2 + B**2 == P
If only one solution is found, it is already valid.
I solved, but the efficiency is low. Initially I wrote this:
[Original Method]
from math import sqrt, ceil
def solve(arr):
if len(arr) % 2 != 0: return []
n = len(arr)
P = 1
i = 0
while i < n:
P *= (arr[i]**2 + arr[i + 1]**2)
i += 2
m = ceil(sqrt(P))
for A in range(1, m):
B = sqrt(P - A**2)
if B == int(B):
return [A, int(B)]
return []
To improve the performance I tried to use the Cauchy inequality.
[Improvement but Failing]
from math import sqrt, ceil
def solve(arr):
if len(arr) % 4 != 0: return []
n = len(arr)
P = 1
for i in range(0, n, 2):
P *= (arr[i]**2 + arr[i + 1]**2)
C = 1
D = 1
for i in range(0, n, 4):
C *= (arr[i]**2 + arr[i + 1]**2) * (arr[i + 2]**2 + arr[i + 3]**2)
D *= (arr[i] * arr[i + 2] + arr[i + 1] * arr[i + 3])**2
A = int(sqrt(D))
B = int(sqrt(P - A**2))
if A ** 2 + B ** 2 == P:
return [A, B]
return []
But the code above starts having problems for high numbers. For example: arr = [3, 9, 8, 4, 6, 8, 7, 8, 4, 8, 5, 6, 6, 4, 4, 5] should result in A = 13243200 and B = 25905600, but my result is that not has A and B for this case.
I need help to improve my performance. I don't know if using the Cauchy inequality solves it, but if you have another idea it's already valid.

How can I count number of looping cycles in number factorization

I want to factor a number and count the number of times each prime number is multiplied to get the desired one. For example 200=2*2*2*5*5 which would give me [[2,3],[5,2].
This is what I wrote:
def factor(N):
f = []
k = 2
c = 0
while k <= N:
if N % k == 0:
while N % k == 0:
b = N / k
N = b
c += 1
f.append([k, c])
else:
k += 1
return f
n = factor(200)
print(n)
output:
[[2, 3], [5, 5]]
expected output:
[[2, 3], [5, 2]] # come from 200 = 2x2x2x5x5
Move the counter on the first loop, like on the code below.
def factor(N):
f = []
k = 2
while k <= N:
c = 0
if N % k == 0:
while N % k == 0:
b = N/k
N = b
c += 1
f.append([k, c])
else:
k += 1
return f
n = factor(200)
print(n)
You need to reset your count (c) after adding to the resulting array.
You should also stop the loop when your factor reaches the square root of the number (or the square of the factor is higher than the number):
Here's a generator version of the prime factor function that does not need to store the prime factors in memory:
def primeFactors(N):
prime = 2
while N >= prime * prime:
power = 0
while N % prime == 0:
power += 1
N //= prime
if power: yield (prime,power)
prime += 1 + (prime&1)
if N>1: yield (N,1)
print(*primeFactors(200)) # (2, 3) (25, 1)
print(*primeFactors(360324)) # (2, 2) (3, 2) (10009, 1)
print(*primeFactors(2485335125)) # (5, 3) (7, 6) (13, 2)
print(*primeFactors(882635521699397)) # (149, 2) (3413, 3)
print(*primeFactors(5196703574764221304787)) # (4733, 1) (101611, 1) (119923, 1) (90104863, 1)
print(*primeFactors(13059300506111507933977974861361)) # (17, 4) (5521, 7)
def factor(N):
f = []
k = 2
while k <= N:
c = 0
if N%k == 0:
while N%k == 0:
b = N/k
N = b
c += 1
f.append([k, c])
else:
k += 1
c = 0 **#You have to reset the counter here..**
return f
n = factor(200)
print(n)

How to add elliptic curve points in python?

I'm trying to implement a simple elliptic curve encryption program but I can't get the expected output of doubling and adding a Point P till 12P .The curve equation isy^2 = x^3 +ax + b mod p. According to this site 3P = [10, 6] when P = [5, 1] while I get 3p = [10, 5]. The equations I use can be found on Wikipedia.
P = [5, 1]
prime = 17
a = 2
b = 2
def gcdExtended(a, b):
if a == 0:
return b, 0, 1
gcd, x1, y1 = gcdExtended(b % a, a)
x = y1 - (b // a) * x1
y = x1
return gcd, x, y
def double_point(point: list):
x = point[0]
y = point[1]
s = ((3*(x**2)+a) * (gcdExtended(2*y, prime)[1])) % prime
newx = (s**2 - x - x) % prime
newy = (s * (x - newx) - y) % prime
return [newx, newy]
def add_points(P: list, Q: list):
x1 = P[0]
y1 = P[1]
x2 = Q[0]
y2 = Q[1]
s = ((y2 - y1) * ((gcdExtended(x2-x1, prime))[1] % prime)) % prime
newx = (s**2 - x1 - x2) % prime
newy = (s * (x1 - newx) - y1) % prime
return [newx, newy]
Q = P
index = 2
while True:
if Q[0] == P[0] and Q[1] == P[1]:
print("doubling")
Q = double_point(P)
else:
print("adding")
Q = add_points(Q, P)
if index == 12 :
break
print(f"{index}P = {Q}")
index += 1
If the point [5,1] is added successively, the following sequence is obtained:
1P = [ 5, 1]
2P = [ 6, 3]
3P = [10, 6]
4P = [ 3, 1]
5P = [ 9, 16]
6P = [16, 13]
7P = [ 0, 6]
8P = [13, 7]
9P = [ 7, 6]
10P = [ 7, 11]
11P = [13, 10]
12P = [ 0, 11]
13P = [16, 4]
14P = [ 9, 1]
15P = [ 3, 16]
16P = [10, 11]
17P = [ 6, 14]
18P = [ 5, 16]
19P = point at infinity
This can be verified e.g. here.
The problem in the posted code is that the method to determine the modular inverse, gcdExtended(a, b), is only valid for positive a and b. While in double_point and add_points b has the value prime (= 17 > 0), a can take negative values.
gcdExtended generally returns wrong values for negative a:
The modular inverse of 5 or -12 is 7: 5 x 7 mod17 = 35 mod17 = 1 and 7 x (-12) mod17 = -84 mod17 = 85 mod17 = 1.
The gcdExtended returns for these values: gcdExtended(5, 17)[1] = 7 (which is true) and gcdExtended(-12, 17)[1] = -7 (which is false).
To allow negative values for a, e.g. the following methods can be defined, see here:
def sign(x):
return 1 if x >= 0 else -1
def gcdExtendedGeneralized(a, b):
gcd, x1, y1 = gcdExtended(abs(a), b)
return gcd, (sign(a) * x1) % b, y1 % b
Replacing gcdExtended with gcdExtendedGeneralized in double_point and add_points provides the correct values (note that the current implementation does not consider the point at infinity).
You interchanged P and Q in add_points. Also a small simplification in your calculation of s:
def add_points(P: list, Q: list):
x1 = P[0]
y1 = P[1]
x2 = Q[0]
y2 = Q[1]
#s = ((y2 - y1) * ((gcdExtended(x2-x1, prime))[1] % prime)) % prime
s = (y2-y1) * (gcdExtended(x2-x1, prime)[1] % prime)
newx = (s**2 - x1 - x2) % prime
newy = (s * (x1 - newx) - y1) % prime
return [newx, newy]
Q = P
index = 2
while True:
if Q[0] == P[0] and Q[1] == P[1]:
print("doubling")
Q = double_point(P)
else:
print("adding")
Q = add_points(P, Q)
if index == 12 :
break
print(f"{index}P = {Q}")
index += 1
which results in
doubling
2P = [6, 3]
adding
3P = [10, 6]
adding
4P = [3, 1]
adding
5P = [9, 16]
adding
6P = [16, 13]
adding
7P = [0, 6]
adding
8P = [13, 8]
adding
9P = [8, 7]
adding
10P = [8, 10]
adding
11P = [13, 9]
adding

I kept getting "ModuleNotFoundError: No module named 'error'"

I was given an outline of this code from my teacher, however I kept getting ModuleNotFoundError: No module named 'error'. I know that I need a module named error, however when I couldn't find a code for a module named error.
I am trying to solve this question:
Solve the tridiagonal equations Ax = b by Doolittle’s decomposition method, where:
A = [6 2 0 0 0
−1 7 2 0 0
0 −2 8 2 0
0 0 3 7 −2
0 0 0 3 5]
b = [2
−3
4
−3
1].
Here is the code that I was using:
from numpy import argmax, dot, zeros, array, asarray, tril, triu
def swapRows(v,i,j):
if len(v.shape) == 1: v[i],v[j] = v[j],v[i]
else:
temp = v[i].copy()
v[i] = v[j]
v[j] = temp
def swapCols(v,i,j):
temp = v[:,j].copy()
v[:,j] = v[:,i]
v[:,i] = temp
import error
def LUdecomp(a,tol=1.0e-9):
n = len(a)
seq = array(range(n))
# Set up scale factors
s = zeros(n)
for i in range(n):
s[i] = max(abs(a[i,:]))
for k in range(0,n-1):
# Row interchange, if needed
p = argmax(abs(a[k:n,k])/s[k:n]) + k
if abs(a[p,k]) < tol: error.err('Matrix is singular')
if p != k:
swapRows(s,k,p)
swapRows(a,k,p)
swapRows(seq,k,p)
# Elimination
for i in range(k+1,n):
if a[i,k] != 0.0:
lam = a[i,k]/a[k,k]
a[i,k+1:n] = a[i,k+1:n] - lam*a[k,k+1:n]
a[i,k] = lam
return a,seq
def LUsolve(a,b,seq):
n = len(a)
# Rearrange constant vector; store it in [x]
x = b.copy()
for i in range(n):
x[i] = b[seq[i]]
# Solution
for k in range(1,n):
x[k] = x[k] - dot(a[k,0:k],x[0:k])
x[n-1] = x[n-1]/a[n-1,n-1]
for k in range(n-2,-1,-1):
x[k] = (x[k] - dot(a[k,k+1:n],x[k+1:n]))/a[k,k]
return x
A = asarray( [ [ 6, 2, 0, 0, 0 ],
[ -1, 7, 2, 0, 0 ],
[ 0, -2, 8, 2, 0 ],
[ 0, 0, 3, 7, -2 ],
[ 0, 0, 0, 3, 5 ] ], dtype=float ) A_orig = A.copy() b = asarray( [ 2, -3, 4, -3, 1 ], dtype=float ) b_orig = b.copy()
A,seq = LUdecomp(A) # A is overwritten as L\U L = tril( A, -1 ) # extract L for ii in range(L.shape[0]): L[ii,ii] = 1.0 # add in 1's on the diagonal U = triu( A, 0 ) # extract U print ("L = ") print (L) print ("U = ") print (U) if False:
print ("A[seq,:]= ")
print (A_orig[seq,:])
print ("LU= ")
print (dot(L,U))
x = LUsolve(A,b,seq) print ("Solution= ", x)
If your intention is to throw an error at some point, then you can reach that without the import error statement. Raising an exception might be a solution.
See the documentation on errors and exceptions.
You can remove import error and edit
if abs(a[p,k]) < tol: error.err('Matrix is singular')
in LUdecomp() as follows:
if abs(a[p,k]) < tol:
raise Exception('Matrix is singular')

Categories

Resources