Conditional definition of matrix elements in sage - python

In Sage, trying to define a matrix with conditions for the cells by:
matrix([[(if gcd(i, j) == 0: log(radical((i+j)*i*j)) else: -1.0) for j in srange(1, 5)] for i in srange(1, 5)])
I get a syntax error:
...
matrix([[(if gcd(i, j) == _sage_const_0 : log(radical((i+j)*i*j)) else: -_sage_const_1p0 ) for j in srange(_sage_const_1 , _sage_const_5 )] for i in srange(_sage_const_1 , _sage_const_5 )])
^
SyntaxError: invalid syntax
What is the problem here? How to fix that?

Your problem is a Python one, really, not Sage per se. Python has some filtering for list comprehensions, but it doesn't look like this. See e.g. this question.
So let's try it:
matrix([[log(radical((i+j)*i*j)) if gcd(i,j)==0 else -1.0 for j in srange(1,5)] for i in srange(1,5)])
By the way, did you really want if gcd(i,j)==1? Unlikely you'll get a gcd of zero in this one!

Here is another possibility.
sage: f = lambda i, j: log(radical((i + j)*i*j)) if gcd(i,j) == 1 else -1
sage: m = matrix(SR, 4, lambda i, j: f(i + 1, j + 1))
sage: m
[ log(2) log(6) log(6) log(10)]
[ log(6) -1 log(30) -1]
[ log(6) log(30) -1 log(42)]
[log(10) -1 log(42) -1]
This uses a different syntax for matrix initialization, in which we
first specify the base ring, the matrix size, and then a function
of (i, j) for coefficients. Note that since Sage indexes rows and
columns from 0, we have to apply our function to i + 1 and j + 1.
Putting -1 for non-coprime (i, j) might work better than -1.0
for exact computations.

Related

Two number Sum program in python O(N^2)

I am used to write code in c++ but now I am trying to learn python. I came to know about the Python language and it is very popular among everyone. So I thought, let's give it a shot.
Currently I am preparing for companies interview questions and able to solve most of them in c++. Alongside which, I am trying to write the code for the same in Python. For the things which I am not familiar with, I do a google search or watch tutorials etc.
While I was writing code for my previously solved easy interview questions in python, I encountered a problem.
Code : Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Given an array of integers, print the indices of the two numbers such that they add up to a specific target.
def twoNum(*arr, t):
cur = 0
x = 0
y = 0
for i in range (len(arr) - 1):
for j in range (len(arr) - 1):
if(i == j):
break
cur = arr[i] + arr[j]
if(t == cur):
x = arr[i]
y = arr[j]
break
if(t == cur):
break
print(f"{x} + {y} = {x+y} ")
arr = [3, 5, -4, 8, 11, 1, -1, 6]
target = 10
twoNum(arr, t=target)
So here is the problem: I have defined x, y in function and then used x = arr[i] and y = arr[j] and I m printing those values.
output coming is : is 0 + 0 = 10 (where target is 10)
This is I guess probably because I am using x = 0 and y = 0 initially in the function and it seems x and y values are not updating then I saw outline section in VSCode there I saw x and y are declared twice, once at the starting of the function and second in for loop.
Can anyone explain to me what is going on here?
For reference, here is an image of the code I wrote in C++
Change this:
def twoNum(*arr, t):
to this:
def twoNum(arr, t):
* is used to indicate that there will be a variable number of arguments, see this. It is not for pointers as in C++.
Basically what you are trying to do is to write C code in python.
I would instead try to focus first on how to write python code in a 'pythonic' way first. But for your question - sloving it your way using brute force in python:
In [173]: def two_num(arr, t):
...: for i in arr:
...: for j in arr[i + 1: ]:
...: if i + j == t:
...: print(f"{i} + {j} = {t}")
...: return
Here's a way to implement a brute force approach using a list comprehension:
arr = [1,3,5,7,9]
target = 6
i,j = next((i,j) for i,n in enumerate(arr[:-1]) for j,m in enumerate(arr[i+1:],i+1) if n+m==target)
output:
print(f"arr[{i}] + arr[{j}] = {arr[i]} + {arr[j]} = {target}")
# arr[0] + arr[2] = 1 + 5 = 6
Perhaps even more pythonic would be to use iterators:
from itertools import tee
iArr = enumerate(arr)
i,j = next((i,j) for i,n in iArr for j,m in tee(iArr,1)[0] if n+m==target)
When you get to implementing an O(n) solution, you should look into dictionaries:
d = { target-n:j for j,n in enumerate(arr) }
i,j = next( (i,d[m]) for i,m in enumerate(arr) if m in d and d[m] != i )

Python to R equivalent : [i for i, e in enumerate(y) if e != 0]

In Python, I have this code: [i for i, e in enumerate(y) if e != 0]
This is within defining a function. How would this be done in R?
The function I am creating is (I want "possible" to be whatever the python code translates to):
bottom11 <- function(p,remain,final) {
possible <-
seed <- min(possible)
remain[i][seed] <- remain[i][seed] + final
p[seed] <- 0
return(remain)
}
To translate [i for i, e in enumerate(y) if e != 0] into R, it helps to describe what it means in words: Get all the indexes of elements in y where the element does not equal 0.
In R, many operations are implicitly vectorised, so you can do this:
which(y != 0)
where y != 0 returns a logical vector corresponding to whether each element is equal to zero, and which returns indexes of a logical vector that are TRUE.

SymPy: Expression for Summation of Symbols in a List

I'm writing a program that evaluates the power series sum_{m=0}{oo} a[m]x^m, where a[m] is recursively defined: a[m]=f(a[m-1]). I am generating symbols as follows:
a = list(sympy.symbols(' '.join([('a%d' % i) for i in range(10)])))
for i in range(1, LIMIT):
a[i] = f_recur(a[i-1], i-1)
This lets me refer to the symbols a0,a1,...,a9 using a[0],a[1],...,a[9], and a[m] is a function of a[m-1] given by f_recur.
Now, I hope code up the summation as follows:
m, x, y = sympy.symbols('m x y')
y = sympy.Sum(a[m]*x**m, (m, 0, 10))
But, m is not an integer so a[m] throws an Exception.
In this situation, where symbols are stored in a list, how would you code the summation? Thanks for any help!
SymPy's Sum is designed as a sum with a symbolic index. You want a sum with a concrete index running through 0, ... 9. This could be Python's sum
y = sum([a[m]*x**m for m in range(10)])
or, which is preferable from the performance point of view (relevant issue)
y = sympy.Add(*[a[m]*x**m for m in range(10)])
In either case, m is not a symbol but an integer.
I have a work-around that does not use sympy.Sum:
x = sympy.symbols('x')
y = a[0]*x**0
for i in range(1, LIMIT):
y += a[i]*x**i
This does the job, but sympy.Sum is not used.
Use IndexedBase instead of Symbol:
>>> a = IndexedBase('a')
>>> Sum(x**m*a[m],(m,1,3))
Sum(a[m]*x**m, (m, 1, 3))
>>> _.doit()
a[1]*x + a[2]*x**2 + a[3]*x**3

How can I accelerate the array assignment in python?

I am trying to make array assignment in python, but it is very slow, is there any way to accelerate?
simi_matrix_img = np.zeros((len(annot), len(annot)), dtype='float16')
for i in range(len(annot)):
for j in range(i + 1):
score = 0
times = 0
if i != j:
x_idx = [p1 for (p1, q1) in enumerate(annot[i]) if np.abs(q1 - 1) < 1e-5]
y_idx = [p2 for (p2, q2) in enumerate(annot[j]) if np.abs(q2 - 1) < 1e-5]
for idx in itertools.product(x_idx, y_idx):
score += simi_matrix_word[idx]
times += 1
simi_matrix_img[i, j] = score/times
else:
simi_matrix_img[i, j] = 1.0
"annot" is a numpy array. Is there any way to accelerate it?
I think the indent for this line is wrong:
simi_matrix_img[i, j] = score/times
you want to perform that assignment after all the product iterations. But since it's the last assignment that takes, the results will be the same.
Here's a partial reworking of your code
def foo1(annot, simi_matrix_word):
N = annot.shape[0]
simi_matrix_img = np.zeros((N,N))
for i in range(N):
for j in range(i + 1):
if i != j:
x_idx = np.nonzero(annot[i])[0]
y_idx = np.nonzero(annot[j])[0]
idx = np.ix_(x_idx, y_idx)
# print(idx, simi_matrix_word[idx])
score = simi_matrix_word[idx].mean()
simi_matrix_img[i, j] = score
else:
simi_matrix_img[i, j] = 1.0
return simi_matrix_img
For a small test case, it returns the same thing:
annot=np.array([[1,0,1],[0,1,1]])
simi_matrix_word = np.arange(12, dtype=float).reshape(3,4)
[[ 1. 0.]
[ 7. 1.]]
That gets rid of all the inner iterations. Next step would be reduce the outer iterations. For example start with np.eye(N), and just iterate on the lower tri indices:
In [169]: np.eye(2)
Out[169]:
array([[ 1., 0.],
[ 0., 1.]])
In [170]: np.tril_indices(2,-1)
Out[170]: (array([1]), array([0]))
Note that for a 2 row annot, we are only calculating one score, at [1,0].
Replacing nonzero with boolean indexing:
def foo3(annot, simi_matrix_word):
N = annot.shape[0]
A = annot.astype(bool)
simi_matrix_img = np.eye(N,dtype=float)
for i,j in zip(*np.tril_indices(N,-1)):
score = simi_matrix_word[A[i],:][:,A[j]]
simi_matrix_img[i, j] = score.mean()
return simi_matrix_img
or this might speed up the indexing a bit:
def foo4(annot, simi_matrix_word):
N = annot.shape[0]
A = annot.astype(bool)
simi_matrix_img = np.eye(N,dtype=float)
for i in range(1,N):
x = simi_matrix_word[A[i],:]
for j in range(i):
score = x[:,A[j]]
simi_matrix_img[i, j] = score.mean()
return simi_matrix_img
Since the number of nonzero values for each row of annot can differ, the number of terms that are summed for each score also differs. That strongly suggests that further vectorization is impossible.
(1) You could use generators instead of list comprehension where possible. For example:
x_idx = (p1 for (p1, q1) in enumerate(annot[i]) if np.abs(q1 - 1) < 1e-5)
y_idx = (p2 for (p2, q2) in enumerate(annot[j]) if np.abs(q2 - 1) < 1e-5)
With this, you iterate only once over those items (in for idx in itertools.product(x_idx, y_idx)), as opposed to twice (once for constructing the list then again in said for loop).
(2) What Python are you using? If <3, I have a hunch that a significant part of the problem is you're using range(), which can be expensive in connection with really large ranges (as I'm assuming you're using here). In Python 2.7, range() actually constructs lists (not so in Python 3), which can be an expensive operation. Try achieving the same result using a simple while loop. For example, instead of for i in range(len(annot)), do:
i=0
while i < len(annot):
... do stuff with i ...
i += 1
(3) Why call len(annot) so many times? It doesn't seem like you're mutating annot. Although len(annot) is a fast O you could store the length in a var, e.g., annot_len = len(annot), and then just reference that. Wouldn't scrape much off though, I'm afraid.

Type object is not subscriptable while writing algorithm in python

I am trying to convert my algorithm into python code. The algorithm is as follows:
For i = 1 To n
For j = 1 To (m - 1)
del1 = C(i - 1, j) - C(i - 1, j - 1)
del2 = C(i - 1, j + 1) - C(i - 1, j)
If del2 = 0 Then
r = 0
Else
r = del1 / del2
End If
Next i
I tried to convert the above chunk of code step by stop. For del1 I tried to write the python code as follows:
del1 = [[C[i-1,j]-C[i-1,j-1] for j in range(1,(m-1))]for i in range [0,int(n)]]
I get the error TypeError: 'type' object is not subscriptable. Can anyone give me starting point on how to convert the above algorithm into python code ?
Edit:
C = [[0 for j in range(0,int(m))]for i in range(0)]
C = [[1 for i in range(0,int(n))]for j in range(0)]
Thanks.
Jdbaba
should be:
del1 = [[C[i-1,j]-C[i-1,j-1] for j in range(1,(m-1))]for i in range(0,int(n))]
[] -> () on the last range
The above notation will work if C is something like a numpy array that supports multi-dimensional slicing. If C is a list of lists, the following should work:
del1 = [[C[i-1][j]-C[i-1][j-1] for j in range(1,(m-1))]for i in range(0,int(n))]
It looks like you want range(0,int(n)).
In python, anything inside [] ie, square-brackets is called subscriptable -- it represents an array concept.
But, in loops we might use range, where we can have a typo of [] instead of () paranthesis.
The range value is not in a subscript format or separable elements of array.
So, the only solution is to change [] to () and run..

Categories

Resources