Collect coefficients of non-square matrix in sympy - python-3.x

Given three vectors, a(1,4), b(1, 4), c(4,1). I want to do the following
a = MatrixSymbol('a', 1, 4)
b = MatrixSymbol('a', 1, 4)
c = MatrixSymbol('c', 4, 1)
expr = a*c + b*c
c_coeff = .... # How to get the value of (a+b) here
I tried using coeff and collect but it fails because the C matrix is not square.

If it is linear then
>>> from sympy.solvers.solveset import linear_coeffs
>>> linear_coeffs(expr, c)
[a + b, 0]
note that 0 is the constant term; if you added MatrixSymbol('d', 1, 1) to expr the 2nd element would be d; you named 'b' as 'a' in your example; I named it 'b' to get the output shown above.

Related

How to Sort a table of strings according to the order defined by another table of strings (Lua)

I have 2 lua tables:
OrderTbl = {'Hello', 'Question', 'Answer', 'Bye'}
UnsortedTbl = {'Question', 'Bye, 'Bye', 'Question', 'Hello', 'Something'}
How to sort UnsortedTbl in order given by OrderTbl? (Fields not found in OrderTbl are placed in the end of result table, unsorted)
I have translated a sample of code from Java, and it works with numbers. Here it is:
function first(arr, low, high, x, n)
if high >= low then
-- (low + high)/2
local mid = low + math.floor((high - low) / 2)
if (mid == 1 or x > arr[mid - 1]) and arr[mid] == x then
return mid
end
if x > arr[mid] then return first(arr, (mid + 1), high, x, n) end
return first(arr, low, (mid - 1), x, n)
end
return nil
end
-- Sort A1 according to the order
-- defined by A2
function sortAccording(A1, A2)
local m=#A1
local n=#A2
-- The temp array is used to store a copy
-- of A1{} and visited{} is used to mark the
-- visited elements in temp{}.
local temp = {}
local visited = {}
for i = 1, m do
temp[i] = A1[i]
visited[i] = 0
end
-- Sort elements in temp
table.sort(temp)
-- for index of output which is sorted A1{}
local ind = 0
-- Consider all elements of A2{}, find them
-- in temp{} and copy to A1{} in order.
for i = 1, n do
-- Find index of the first occurrence
-- of A2[i] in temp
local f = first(temp, 1, m, A2[i], m+1)
-- If not present, no need to proceed
if not f then
-- continue
else
-- Copy all occurrences of A2[i] to A1{}
j = f
while j < m and temp[j] == A2[i] do
A1[ind] = temp[j]
ind = ind + 1
visited[j] = 1
j = j + 1
end
end
end
-- Now copy all items of temp{} which are
-- not present in A2{}
for i = 1, m do
if visited[i] == 0 then
ind = ind + 1
A1[ind] = temp[i]
end
end
end
function printArray(arr)
for i = 1, #arr do
print(arr[i] .. " ")
end
end
-- Driver program to test above function.
local A1 = {2, 1, 2, 5, 7, 1, 9, 3, 6, 8, 8}
local A2 = {2, 1, 4, 3, 6, 5, 8, 7}
sortAccording(A1, A2)
printArray(A1)
I don't quite understand how to make it work with strings. Could you help me?
You can use the form of table.sort that accepts a custom comparator:
local OrderTbl = {'Hello', 'Question', 'Answer', 'Bye'}
local UnsortedTbl = {'Question', 'Bye', 'Bye', 'Question', 'Hello', 'Something', 'Else'}
-- convert the order to hash that can be easily queried
for idx, val in ipairs(OrderTbl) do OrderTbl[val] = idx end
local maxIdx = #OrderTbl + 1 -- this will mark "missing" elements
-- pass a custom comparator that will check OrderTbl
table.sort(UnsortedTbl, function(a, b)
local pa = OrderTbl[a] or maxIdx -- desired index of a
local pb = OrderTbl[b] or maxIdx -- desired index of b
if pa == pb then return a < b end -- sort by name
return pa < pb -- sort by index
end)

Rotate String to find Hamming distance equal to K

We are given 2 binary strings (A and B) both of length N and an integer K.
We need to check if there is a rotation of string B present where hamming distance between A and the rotated string is equal to K. We can just remove one character from front and put it at back in single operation.
Example : Let say we are given these 2 string with values as A="01011" and B="01110" and also K=4.
Note : Hamming distance between binary string is number of bit positions in which two corresponding bits in strings are different.
In above example answer will be "YES" as if we rotate string B once it becomes "11100", which has hamming distance of 4, that is equal to K.
Approach :
For every rotated string of B
check that hamming distance with A
if hamming distance == K:
return "YES"
return "NO"
But obviously above approach will execute in O(Length of string x Length of string) times. Is there better approach to solve this. As we don't need to find the actual string, I am just wondering there is some better algorithm to get this answer.
Constraints :
Length of each string <= 2000
Number of test cases to run in one file <=600
First note that we can compute the Hamming distance as the sum of a[i]*(1-b[i]) + b[i]*(1-a[i]) for all i. This simplifies to a[i] + b[i] - 2*a[i]*b[i]. Now in O(n) we can compute the sum of a[i] and b[i] for all i, and this doesn't change with bit rotations, so the only interesting term is 2*a[i]*b[i]. We can compute this term efficiently for all bit rotations by noting that it is equivalent to a circular convolution of a and b. We can efficiently compute such convolutions using the Discrete Fourier transform in O(n log n) time.
For example in Python using numpy:
import numpy as np
def hdist(a, b):
return sum(bool(ai) ^ bool(bi) for ai, bi in zip(a, b))
def slow_circular_hdist(a, b):
return [hdist(a, b[i:] + b[:i]) for i in range(len(b))]
def circular_convolution(a, b):
return np.real(np.fft.ifft(np.fft.fft(a)*np.fft.fft(b[::-1])))[::-1]
def fast_circular_hdist(a, b):
hdist = np.sum(a) + np.sum(b) - 2*circular_convolution(a, b)
return list(np.rint(hdist).astype(int))
Usage:
>>> a = [0, 1, 0, 1, 1]
>>> b = [0, 1, 1, 1, 0]
>>> slow_circular_hdist(a, b)
[2, 4, 2, 2, 2]
>>> fast_circular_hdist(a, b)
[2, 4, 2, 2, 2]
Speed and large correctness test:
>>> x = list((np.random.random(5000) < 0.5).astype(int))
>>> y = list((np.random.random(5000) < 0.5).astype(int))
>>> s = time.time(); slow_circular_hdist(x, y); print(time.time() - s)
6.682933807373047
>>> s = time.time(); fast_circular_hdist(x, y); print(time.time() - s)
0.008500814437866211
>>> slow_circular_hdist(x, y) == fast_circular_hdist(x, y)
True

Python multiprocessing - "outer product" of arguments

I'm doing a numerical simulation with multiple input parameters. Some of these parameters are static, while some are arrays of numbers I want to run my function at. For example, I may want to simulate the following set of parameters
a = 1
b = np.arange(1, 11)
c = np.arange(20, 31)
d = 1
Which would mean running
simulate(a = 1, b = 1, c = 20, d = 1)
simulate(a = 1, b = 1, c = 21, d = 1)
...
simulate(a = 1, b = 1, c = 30, d = 1)
simulate(a = 1, b = 2, c = 20, d = 1)
...
i.e. 100 calls to simulate(). I want to use multithreading to speed this up. I tried using multiprocessing's pool.map(), but the requirement for the structure of the input parameters requires instantiating a length-100 array containing lists of a, b, c, and d, e.g. [[1, 1, 20, 1], [1, 1, 21, 1] ...
In actuality I have enough parameters and am varying in enough dimensions that I run out of memory trying to generate the input array for pool.map().
What I'd like is to have a function map_wrapper() such that
a = 1
b = np.arange(1, 11)
c = np.arange(20, 31)
d = 1
map_wrapper(simulation, [a, b, c, d])
Is equivalent to the 100 calls of simulation() listed above, or a way of using map() or similar in the same way.
Here's a minimal example showing how to build a generator that yields args for a multiprocessing function:
import multiprocessing as mp
def gen_args():
for a in range(4):
for b in range(4,8):
for c in range(8,12):
yield (a,b,c)
def foo(a, b, c):
return a + b + c
if __name__ == '__main__':
with mp.Pool() as p:
res = p.starmap(foo, gen_args())
This will generate 64 tasks, but the arguments are calculated on the fly as needed rather than all at once at the beginning. Keep in mind you'll still need the space for the output list. Using the chunksize argument for starmap may or may not improve execution speed (test it both ways to find out), but it will increase memory usage somewhat, as it pulls multiple sets of args at a time for each worker function to work on.

Printing fibonacci series using lists in python

I am relatively a noobie in programming and trying to learn python. I was trying to implement a Fibonacci series into a list within 10.
fibo= [0,1]
for k in range(11):
i= fibo[-1]
j = fibo[-2]
k= fibo[i]+fibo[j]
fibo.append(k)
k=+1
print(fibo)
Not sure what I did wrong? Any help is really appreciated!
Output:
[0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
You can use this code to print fibonacci series upto N.
N = int(input()) # Length of fibonacci series
fibo = [0, 1]
a = fibo[0]
b = fibo[1]
for each in range(2, N):
c = a + b
a, b = b, c
fibo.append(c)
print(fibo[:N])
OUTPUT
N = 10
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
I can see few issues here:
fibo = [0,1]
# Your loop should start at index 2, otherwise
# you will try to access fibo[-2] and fibo[-1] with k=0
# and fibo[-1] and fibo[0] with k=1
# Also, if you only want 10 values, you should change 11
# to 10 since fibo already has two values.
# for k in range(11):
for k in range(2, 10):
# You don't want the content of fibo, but the indexes!
# i = fibo[-1]
# j = fibo[-2]
i = k - 1
j = k - 2
# You are already using k, so you need to use an other variable
# k = fibo[i] + fibo[j]
v = fibo[i] + fibo[j]
fibo.append(v)
# You don't need k+=1 because it will be incremented
# according to range(2, 10). The loop will start with
# k = 2 and it will stop when k = 9
# k += 1
print(fibo)
Your code did not crash because you technically can access fibo[-1] and fibo[-2]. It will respectively return the last value of your array, and the value before the last one.

String concatenation queries

I have a list of characters, say x in number, denoted by b[1], b[2], b[3] ... b[x]. After x,
b[x+1] is the concatenation of b[1],b[2].... b[x] in that order. Similarly,
b[x+2] is the concatenation of b[2],b[3]....b[x],b[x+1].
So, basically, b[n] will be concatenation of last x terms of b[i], taken left from right.
Given parameters as p and q as queries, how can I find out which character among b[1], b[2], b[3]..... b[x] does the qth character of b[p] corresponds to?
Note: x and b[1], b[2], b[3]..... b[x] is fixed for all queries.
I tried brute-forcing but the string length increases exponentially for large x.(x<=100).
Example:
When x=3,
b[] = a, b, c, a b c, b c abc, c abc bcabc, abc bcabc cabcbcabc, //....
//Spaces for clarity, only commas separate array elements
So for a query where p=7, q=5, answer returned would be 3(corresponding to character 'c').
I am just having difficulty figuring out the maths behind it. Language is no issue
I wrote this answer as I figured it out, so please bear with me.
As you mentioned, it is much easier to find out where the character at b[p][q] comes from among the original x characters than to generate b[p] for large p. To do so, we will use a loop to find where the current b[p][q] came from, thereby reducing p until it is between 1 and x, and q until it is 1.
Let's look at an example for x=3 to see if we can get a formula:
p N(p) b[p]
- ---- ----
1 1 a
2 1 b
3 1 c
4 3 a b c
5 5 b c abc
6 9 c abc bcabc
7 17 abc bcabc cabcbcabc
8 31 bcabc cabcbcabc abcbcabccabcbcabc
9 57 cabcbcabc abcbcabccabcbcabc bcabccabcbcabcabcbcabccabcbcabc
The sequence is clear: N(p) = N(p-1) + N(p-2) + N(p-3), where N(p) is the number of characters in the pth element of b. Given p and x, you can just brute-force compute all the N for the range [1, p]. This will allow you to figure out which prior element of b b[p][q] came from.
To illustrate, say x=3, p=9 and q=45.
The chart above gives N(6)=9, N(7)=17 and N(8)=31. Since 45>9+17, you know that b[9][45] comes from b[8][45-(9+17)] = b[8][19].
Continuing iteratively/recursively, 19>9+5, so b[8][19] = b[7][19-(9+5)] = b[7][5].
Now 5>N(4) but 5<N(4)+N(5), so b[7][5] = b[5][5-3] = b[5][2].
b[5][2] = b[3][2-1] = b[3][1]
Since 3 <= x, we have our termination condition, and b[9][45] is c from b[3].
Something like this can very easily be computed either recursively or iteratively given starting p, q, x and b up to x. My method requires p array elements to compute N(p) for the entire sequence. This can be allocated in an array or on the stack if working recursively.
Here is a reference implementation in vanilla Python (no external imports, although numpy would probably help streamline this):
def so38509640(b, p, q):
"""
p, q are integers. b is a char sequence of length x.
list, string, or tuple are all valid choices for b.
"""
x = len(b)
# Trivial case
if p <= x:
if q != 1:
raise ValueError('q={} out of bounds for p={}'.format(q, p))
return p, b[p - 1]
# Construct list of counts
N = [1] * p
for i in range(x, p):
N[i] = sum(N[i - x:i])
print('N =', N)
# Error check
if q > N[-1]:
raise ValueError('q={} out of bounds for p={}'.format(q, p))
print('b[{}][{}]'.format(p, q), end='')
# Reduce p, q until it is p < x
while p > x:
# Find which previous element character q comes from
offset = 0
for i in range(p - x - 1, p):
if i == p - 1:
raise ValueError('q={} out of bounds for p={}'.format(q, p))
if offset + N[i] >= q:
q -= offset
p = i + 1
print(' = b[{}][{}]'.format(p, q), end='')
break
offset += N[i]
print()
return p, b[p - 1]
Calling so38509640('abc', 9, 45) produces
N = [1, 1, 1, 3, 5, 9, 17, 31, 57]
b[9][45] = b[8][19] = b[7][5] = b[5][2] = b[3][1]
(3, 'c') # <-- Final answer
Similarly, for the example in the question, so38509640('abc', 7, 5) produces the expected result:
N = [1, 1, 1, 3, 5, 9, 17]
b[7][5] = b[5][2] = b[3][1]
(3, 'c') # <-- Final answer
Sorry I couldn't come up with a better function name :) This is simple enough code that it should work equally well in Py2 and 3, despite differences in the range function/class.
I would be very curious to see if there is a non-iterative solution for this problem. Perhaps there is a way of doing this using modular arithmetic or something...

Resources