Is it possible to solve the puzzle using python? - python

The puzzle
I tried to solve puzzle with the below program.
It is a 4x4 cross math puzzle.
Is there any way to solve quickly
def puzzleTwo (a):
if(a[0] + a[1] - a[2] + a[3] == 19):
#print ("1 equation Success")
if(a[4] - a[5] - a[6] - a[7] == -31):
#print ("2 equation Success")
if(a[8] - a[9] / a[10] + a[11] == 8):
#print ("3 equation Success")
if(a[12] - a[13] / a[14] + a[15] == 1):
#print ("4 equation Success")
if(a[0] + a[4] + a[8] + a[12] == 23):
#print ("5 equation Success")
if(a[1] - a[5] + a[9] - a[13] == -3):
#print ("6 equation Success")
if(a[2] - a[6] / a[10] + a[14] == 5):
#print ("7 equation Success")
if(a[3] + a[7] - a[11] + a[15] == 22):
print (a)
return
from sympy.utilities.iterables import multiset_permutations
import numpy as np
a = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])
for p in multiset_permutations(a):
puzzleTwo(p)

The following code uses backtracking algorithm to find a solution in ~3 minutes on Windows 10 PC with i7 CPU 920 # 2.67 MHz
Code
def condition(a):
' Apply conditions individually to allow immediate backtracking when a condition is not met '
if len(a)==4:
return (a[0] + a[1] - a[2] + a[3]) == 19
elif len(a) == 8:
return (a[4] - a[5] - a[6] - a[7]) == -31
elif len(a) == 11:
return (a[6] % a[10]) == 0 and (a[9] % a[10]) == 0
elif len(a)==12:
return (a[8] - a[9] // a[10] + a[11]) == 8
elif len(a) == 13:
return (a[0] + a[4] + a[8] + a[12]) == 23
elif len(a) == 14:
return (a[1] - a[5] + a[9] - a[13]) == -3
elif len(a) == 15:
return (a[2] - a[6] // a[10] + a[14]) == 5 and (a[13] % a[14]) == 0
elif len(a) == 16:
return (a[3] + a[7] - a[11] + a[15]) == 22 and (a[12] - a[13] // a[14] + a[15]) == 1
elif len(a) > 16:
return False # array exceeds max length
else:
return True # not one of the lengths to try conditions
def solve(answer = None):
' Uses backtracking to find solve 4x4 math grid problem '
if answer is None:
answer = ()
if condition(answer):
# satisfies conditions so far
if len(answer) == 16:
# satisfies all conditions
yield answer
else:
# Expand on solution since satisfies conditions so far
for i in range(1, 17):
# Try adding one of the numbers 1 to 17 to current answer
yield from solve(answer + (i,))
from time import time
tstart = time()
print(f'Solution: {next(solve(), None))}') # get first solution
# use list(solve()) to get all solutions
print(f'Elapsed time {time()-tstart}')
Output
Solution: (1, 6, 1, 13, 6, 14, 14, 9, 15, 16, 2, 1, 1, 11, 11, 1)
Elapsed time 189.32917761802673
Explanation
Trying all multiset_permutations of numbers of length 16 is infeasible since there are too many (i.e. 16^16 = 2^64 ~ 18e18).
Idea is to create arrays of increasing size (i.e. 0 to 16 length), but abort early if the array will not satisfy conditions (i.e. backtracking).
To be able to abort early (i.e. backtracking) we:
Split conditions up so we can apply based upon the size of the array (i.e. condition function)
We add the condition that one number will be divisible by another for the division (i.e. if we have x/y then we need x % y == 0)
We use integer division throughout (i.e. x // y)

Related

Write an algorithm for the sequence

Calculate the n member of the sequence given by the formulas
a[2 * n] = a[n] + 1
a[2 * n + 2] = a[2 * n + 1] - a[n]
a[0] = a[1] = 1
n > 0
I've tried a lot of variants, but I can't find correct one.
n = int(input())
a = [0 for i in range(n + 3)]
a[0] = a[1] = 1
i = 1
while i * 2 + 2 < n + 3:
a[2 * i] = a[i] + 1;
a[2 * i + 1] = a[2 * i + 2] + a[i]
a[2 * i + 2] = a[2 * i + 1] - a[i]
i += 1
print(a[n])
We should first compute the expected output for the first few numbers to let us have an idea what the sequence is like first,
a[0] = a[1] = 1
Substitute n = 1 in the first recurrence relation gives
a[2] = a[1] + 1 = 2
Substitute n = 1 in the second recurrence relation gives
a[4] = a[3] - a[1]
But a[4] = a[2] + 1 = 3 according to the first recurrence relation, so 3 = a[3] - 1, which gives a[3] = 4
We have a = {1, 1, 2, 4, 3, ... }
Your program gives a = {1, 1, 2, 1, 3, ...}
What went wrong in your program?
We notice that when i = 1, the line a[2 * i + 1] = a[2 * i + 2] + a[i] evaluates to a[3] = a[4] + a[1]. However, at that time, a[4] is not evaluated yet, causing an incorrect output.
The issue, therefore, lies in how you order your statements in the while loop. Make sure that statements in your loop only make use of values that will not be changed later.
How should we do that?
if we manipulate the second recurrence relation as follows:
a[2 * i + 2] = a[2 * i + 1] - a[i]
a[2 * i + 1] = a[2 * (i + 1)] + a[i]
Using the first recurrence relation, we have
a[2 * i + 1] = a[i + 1] + 1 + a[i]
which should resolve the issue since 2 * n + 1 > n + 1 for all positive n.
After modifying the second statement, you check that every element in a is computed and you should be done.
Note
One more thing to note is that the third statement is redundant since the first statement covers all even elements in a already.
In fact, a more efficient approach, in particular a logarithmic solution exist2 if you only have to calculated the nth member of the sequence.
I found decision
n = int(input())
k = n if n % 2 == 0 else n + 1
a = [None for i in range(k + 1)]
a[0] = a[1] = 1
def fill_list(a):
while None in a:
i = 1
while i * 2 <= k:
if a[i] != None:
a[2 * i] = a[i] + 1
i += 1
i = 1
while i * 2 + 2 <= k:
if a[i * 2 + 2] != None and a[i] != None:
a[i * 2 + 1] = a[i * 2 + 2] + a[i]
i += 1
fill_list(a)
print(a[n])
Your second formula gives a[2n+2] = a[2n+1] - a[n]. That can be rewritten: a[2n+1] = a[2n+2] + a[n] which is a[n+1] + a[n] + 1 from the first formula.
We can use this to write a simple dynamic programming algorithm that runs in linear time:
def A(n):
a = [1] * (n+1)
for i in range(2, n+1):
if i%2 == 0:
a[i] = a[i//2] + 1
else:
a[i] = a[i//2] + a[i//2+1] + 1
return a[n]
However, we can note that we can solve this in logarithmic time, by noting that we can compute both a[n] and a[n+1] from a[n//2] and a[n//2+1].
If n is even, then a[n]=a[n//2]+1 and a[n+1]=a[n//2]+a[n//2+1]+1.
And if n is odd, then a[n]=a[n//2]+a[n//2+1]+1 and a[n+1]=a[n//2+1]+1.
These are just applications of the formulas we have already.
This gives us this solution:
def A2(n):
if n == 0:
return 1, 1
if n == 1:
return 1, 2
a, b = A2(n//2)
if n % 2 == 0:
return a+1, a+b+1
else:
return a+b+1, b+1
Note that this returns 2 values, but for all n, A(n) == A2(n)[0].

How can I store a very little value (approximately 10^(-32)) in numpy array?

I have to store little numbers in a numpy array. At the and, min should be around 10^(-32). It returns with the proper value if it is up to 10^(-14). Is there any way to fix this problem? Thanks for the answers!
import numpy as np
import math
def Modify(array):
maxIndex = np.argmax(array)
for j in range(array.shape[0]):
if (j == maxIndex):
if (j == (len(array)-1)):
nextIndex = (j + 1) % array.shape[0]
prevIndex = (j - 1) % array.shape[0]
array[nextIndex] = (array[prevIndex]) + (array[nextIndex]) - (array[j])
new_array = np.delete(array, [prevIndex, (j % array.shape[0])])
elif (j == 0):
nextIndex = (j + 1) % array.shape[0]
prevIndex = (j - 1) % array.shape[0]
array[prevIndex] = (array[prevIndex]) + (array[nextIndex]) - (array[j])
new_array = np.delete(array, [(j % array.shape[0]), nextIndex])
elif (j != 0 and j % 2 == 0):
nextIndex = (j + 1) % array.shape[0]
prevIndex = (j - 1) % array.shape[0]
array[j] = (array[prevIndex]) + (array[nextIndex]) - (array[j])
new_array = np.delete(array, [prevIndex, nextIndex])
elif(j != (len(array)-1) and j % 2 !=0 ):
nextIndex = (j + 1) % array.shape[0]
prevIndex = (j - 1) % array.shape[0]
array[j] = (array[prevIndex]) + (array[nextIndex]) - (array[j])
new_array = np.delete(array, [prevIndex, nextIndex])
return new_array
if name == "main":
a=10000
i=0
m=0
e = 0
E = 0
k=0
min=1
for i in range(a):
chain = np.random.uniform(0, 1, 256)
chain = chain.astype('float64')
for k in range(len(chain)):
chain[k] = math.log(chain[k])
while (chain.shape[0] > 4):
chain = Modify(chain)
chain[0] = math.exp(chain[0])
chain[1] = math.exp(chain[1])
chain[2] = math.exp(chain[2])
chain[3] = math.exp(chain[3])
chain[2] = chain[0] + chain[2]
E=-math.sqrt((chain[1]**2)+(chain[3]**2)+(chain[2]**2)+2*chain[1]*chain[3])
e=-math.sqrt((chain[1]**2)+(chain[3]**2)+(chain[2]**2)-2*chain[1]*chain[3])
m = abs(e-E)
if m < min:
min=m
print(min)
The underlying problem here is not about storing numbers that small, but rather about the finite precision of floating-point numbers (which is a bit less than 16 decimal digits for 64-bit floats). If the (true) relative difference between e and E is smaller than this precision, e - E will evaluate to zero. This is called "catastrophic cancellation."
A simple and effective way to get around this is to expand e - E in a power series about 2*chain[1]*chain[3] = 0 and take the first non-zero term. If we pull out the common terms between e and E into separate variables, we have
term_1 = chain[1]**2 + chain[3]**2 + chain[2]**2
term_2 = 2*chain[1]*chain[3]
E = -math.sqrt(term_1 + term_2)
e = -math.sqrt(term_1 - term_2)
m = abs(e - E)
The first non-zero term in the series works out to term_2 / sqrt(term_1). The next term is of order (term_2/term_1)^3, so we can safely truncate the series before that if (term_2/term_1)^2 < 1e-16 (16 decimal digits), or term_2 / term_1 < 1e-8. If the ratio is larger than that, our approximation might be slightly off, but at that point the normal e - E works just fine.
The final code (with some extra numpy simplifications):
if __name__ == "__main__":
a = 10000
min = 1
for i in range(a):
chain = np.log(np.random.uniform(0, 1, 256))
while chain.shape[0] > 4:
chain = Modify(chain)
chain = np.exp(chain)
chain[2] = chain[2] + chain[0]
term_1 = chain[1]**2 + chain[3]**2 + chain[2]**2
term_2 = 2 * chain[1] * chain[3]
e = -math.sqrt(term_1 - term_2)
E = -math.sqrt(term_1 + term_2)
m = abs(e - E)
if abs(term_2 / term_1) < 1e-8:
# use power series approximation for e - E instead
# we only need the first term: the next term is O(term_2/term_1)^2
# smaller, which is less than machine epsilon
m = term_2 / math.sqrt(term_1)
if m < min:
min = m
print(min)

Is this colidity challenge (Zinc 2018) test case wrong?

I just randomly picked up this challenge...
The question and report can be found here: https://app.codility.com/demo/results/training3NRM6P-HSG/
For test case N = 100,000, all performances are different., it says: got 166661666700000 expected 665533373
For N = 100,000 all different performance should not it be: C(100000, 3) = int(len(A) * (len(A) - 1) * (len(A) - 2) / 3 / 2), how is the 665533373 calculated?
Paste my solution here for reading convenience:
def solution(A):
# write your code in Python 3.6
if not A or len(A) < 3:
return 0
if len(set(A)) == len(A):
return int(len(A) * (len(A) - 1) * (len(A) - 2) / 3 / 2)
check = {}
def bt(path, nxt):
if len(path) == 3:
t = tuple(path)
if t not in check:
check[t] = None
return
if len(path) > 3:
return
for i in range(nxt, len(A)):
if i > nxt and A[i] == A[i-1]:
continue
path.append(A[i])
bt(path, i + 1)
path.pop()
bt([], 0)
return len(check)
Look closer at the question! It clearly says that, "since the answer can be very large, provide it modulo 10^9 + 7 (1,000,000,007)".
Your answer, 166661666700000 % (10^9 + 7) = 665533373, which is the expected result.
So all you need to do theoretically is edit the last line of your code like so:
return len(check) % (10**9 + 7)

Backtracing the longest palindromic subsequence

I modified the code from Geeks for Geeks to backtrace the actual subsequence, not only its length. But when I backtrace and get to the end where I can put an arbitrary character to the middle of the palindrome, I find my solution to be sloppy and not 'Pythonic'. Can someone please help me?
This piece smells particularly bad(if it works correctly at all):
if length_matrix[start][end] == 1 and substr_length >= 0:
middle = sequence[start]
Here is the forward pass:
def calc_subsequence_lengths(sequence):
n = len(sequence)
# Create a table to store results of subproblems
palindrome_lengths = np.zeros((n, n))
# Strings of length 1 are palindrome of length 1
np.fill_diagonal(palindrome_lengths, 1)
for substr_length in range(2, n + 1):
for i in range(n - substr_length + 1):
j = i + substr_length - 1
if sequence[i] == sequence[j] and substr_length == 2:
palindrome_lengths[i][j] = 2
elif sequence[i] == sequence[j]:
palindrome_lengths[i][j] = palindrome_lengths[i + 1][j - 1] + 2
else:
palindrome_lengths[i][j] = max(palindrome_lengths[i][j - 1],
palindrome_lengths[i + 1][j])
return palindrome_lengths
And here is the traceback:
def restore_palindrome(length_matrix, sequence):
palindrome_left = ''
middle = ''
n, n = np.shape(length_matrix)
# start in the north-eastern corner of the matrix
substr_length, end = n - 1, n-1
# traceback
while substr_length > 0 and end > 1:
start = end - substr_length
# if possible, go left
if length_matrix[start][end] == (length_matrix[start][end - 1]):
substr_length -= 1
end -= 1
# the left cell == current - 2, but the lower is the same as current, go down
elif length_matrix[start][end] == (length_matrix[start + 1][end]):
substr_length -= 1
# both left and lower == current - 2, go south-west
else:
palindrome_left += sequence[start]
substr_length -= 2
end -= 1
if length_matrix[start][end] == 1 and substr_length >= 0:
middle = sequence[start+1]
result = ''.join(palindrome_left) + middle + ''.join(palindrome_left[::-1])
return result, int(length_matrix[0][n-1])
Update
First off, the problem is to calculate the longest non-contiguous palindromic sequence (as stated in the article I referred to). For the sequence BBABCBCAB, the output should be BABCBAB
Secondly, as I have pointed out, I'm building upon an existing DP solution which works in O(N^2) time and space. It calculates the length just fine, so I need to backtrace the actual palindrome in the most elegant way, not sacrificing efficiency for elegance.

how to diff / align Python lists using arbitrary matching function?

I'd like to align two lists in a similar way to what difflib.Differ would do except I want to be able to define a match function for comparing items, not just use string equality, and preferably a match function that can return a number between 0.0 and 1.0, not just a boolean.
So, for example, say I had the two lists:
L1 = [('A', 1), ('B', 3), ('C', 7)]
L2 = ['A', 'b', 'C']
and I want to be able to write a match function like this:
def match(item1, item2):
if item1[0] == item2:
return 1.0
elif item1[0].lower() == item2.lower():
return 0.5
else:
return 0.0
and then do:
d = Differ(match_func=match)
d.compare(L1, L2)
and have it diff using the match function. Like difflib, I'd rather the algorithm gave more intuitive Ratcliff-Obershelp type results rather than a purely minimal Levenshtein distance.
I just wrote this implementation of Needleman-Wunsch and it seems to do what I want:
def nw_align(a, b, replace_func, insert, delete):
ZERO, LEFT, UP, DIAGONAL = 0, 1, 2, 3
len_a = len(a)
len_b = len(b)
matrix = [[(0, ZERO) for x in range(len_b + 1)] for y in range(len_a + 1)]
for i in range(len_a + 1):
matrix[i][0] = (insert * i, UP)
for j in range(len_b + 1):
matrix[0][j] = (delete * j, LEFT)
for i in range(1, len_a + 1):
for j in range(1, len_b + 1):
replace = replace_func(a[i - 1], b[j - 1])
matrix[i][j] = max([
(matrix[i - 1][j - 1][0] + replace, DIAGONAL),
(matrix[i][j - 1][0] + insert, LEFT),
(matrix[i - 1][j][0] + delete, UP)
])
i, j = len_a, len_b
align_a = ""
align_b = ""
while (i, j) != (0, 0):
if matrix[i][j][1] == DIAGONAL:
align_a += a[i - 1]
align_b += b[j - 1]
i -= 1
j -= 1
elif matrix[i][j][1] == LEFT:
align_a += "-"
align_b += b[j - 1]
j -= 1
else: # UP
align_a += a[i - 1]
align_b += "-"
i -= 1
return align_a[::-1], align_b[::-1]
I recently ran across a discussion of an algorithm called patience diff that sounds rather simple. You could try implementing that yourself, and then of course you can have it use whatever comparison algorithm you like.

Categories

Resources