Converting Maple to Sage - python

I have some Maple code below that I'm trying to convert to Sage (which is some kind of Python) code.
This is the Maple code
restart:
m:=15:
a:=array(1..m):
eqn:=array(1..m):
expr:=sum(a['i']*u^('i'-1),'i'=1..m)-
product((1-u^'i')^(-a['i']),'i'=1..m):
for i from 1 to m do eqn[i]:=coeff(series(expr,u=0,m+2),u,i-1);
od:
sols:=solve({seq(eqn[i],i=1..m)},{seq(a[i],i=1..m)}):
assign(sols):
print(a);
This is the output for this code:
[1, 1, 2, 4, 9, 20, 48, 115, 286, 719, 1842, 4766, 12486, 32973, 87811]
This is the Sage code I have already:
u = var('u')
m = 15
a = [var(f"a_{i}") for i in range(1,m+1)]
eqn = [var(f"e_{i}") for i in range(1,m+1)]
expr = sum(a[i]*u^(i-1) for i in range(1,m)) - product((1-u^i)^(-a[i]) for i in range(1,m))
print(expr)
for i in range(0,m):
# eqn[i] = taylor(expr,u,0,m+2).coefficients(sparse=False)[i]
When I uncomment the code in the for-loop, I get IndexError: list index out of range.
I tried the CodeGeneration tool:
CodeGeneration:-Python(i -> coeff(series(expr, u = 0, m + 2), u, i - 1), output = embed);
CodeGeneration:-Python(sols -> assign(sols), output = embed);
This however gives me
Warning, the function names {coeff, series} are not recognized in the target language
Warning, the function names {assign} are not recognized in the target language
And it gives as output thus no useful code, since coeff and series don't exist:
cg0 = lambda i: coeff(series(expr, u == 0, m + 2), u, i - 1)
cg2 = lambda sols: assign(sols)
The question is now: what are the equivalent expressions for coeff, series and assign?

To give an answer, one has to understand first what happens behind the maple code, the solve the problem more or less in an optimal manner in sage. Here is what can be done in sage, to look as close as possible to the maple way.
m = 15
r = [1..m] # range to be used in the sequel
u = var('u');
a = dict(zip(r, var('a', n=m+1, latex_name='a')[1:]))
expr = sum ( a[j]*u^(j-1) for j in r ) \
- prod( (1 - u^j)^(-a[j]) for j in r )
expr = taylor(expr, u, 0, m)
sols = solve( [ diff(expr, u, j-1).subs(u == 0) for j in r ]
, list(a.values())
, solution_dict=True)
for sol in sols:
print(sol)
And there is only one solution, and the one print is:
{a1: 1, a2: 1, a3: 2, a4: 4, a5: 9, a6: 20, a7: 48, a8: 115, a9: 286
, a10: 719, a11: 1842, a12: 4766, a13: 12486, a14: 32973, a15: 87811}
Here are some words about the decision to use the "range" list (which is a list object, not a range object)... In the maple code, a was something that accepted a[1] and a[2] and so on. These "symbols" are variables, if not specified in a different way. But there is no a[0]. My choice was to use
var('a', n=m+1, latex_name='a')
which is a list of "variables", well it is the list starting with a0, so i am taking it from a1 to the end via (slicing)
var('a', n=m+1, latex_name='a')[1:]
and then, in order to have something like a[1] pointing to a1 i am using a dictionary in sage. So i am zipping / pairing the list r with the above sliced part of the var's. Then is want the dictionary that solidifies this pairing.
Then in order to have the u-coefficients, i am using the poor man's coefficient extraction, obtained by differentiation w.r.t. u, as many times as needed, then setting the u variable to zero.
Why is the above not working "somehow" by directly "taking coefficients"? Because in sage, expr is an expression.
sage: type(expr)
<class 'sage.symbolic.expression.Expression'>
And there is no way in general to get the coefficients of such an "expression".
Instead, if we arrange to work in polynomial rings, then there is still a chance to proceed using the wanted method. Please compare the above with:
m = 15
r = [1..m] # range to be used in the sequel
R.<a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15> = \
PolynomialRing(QQ)
a = dict(zip(r, R.gens()))
S.<u> = PowerSeriesRing(R, default_prec=m)
expr = sum ( a[j]*u^(j-1) for j in r ) \
- exp( sum( -a[j]*log(1 - u^j) for j in r ) )
J = R.ideal(expr.coefficients())
J.variety() # solution(s) to the R-coefficient equations from above over QQ, base ring of R
And that J.variety() delivers...
sage: J.variety()
[{a15: 87811, a14: 32973, a13: 12486, a12: 4766, a11: 1842, a10: 719
, a9: 286, a8: 115, a7: 48, a6: 20, a5: 9, a4: 4, a3: 2, a2: 1, a1: 1}]
(Results were manually adjusted.)

You are trying to solve algebraic equations, right?
There is a module for that:
https://docs.sympy.org/latest/modules/solvers/solvers.html
Your python code doesn't work. Is there a module, I have to import first?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'var' is not defined
Apology: This should be a comment, not an answer, I know. I don't have enough reputation yet. But I used to love Maple and would like to help.

Related

Rewriting R's density() (not really)

In response to this question, I took upon the challenge to make my understanding on R's density() function.
Since I'm pretty much very new to R, I have no ideas about vectors regarding the c() function, which made me use a list as the closest form.
I would make this function:
def density(x, bw, adjust):
bw2 = None
result = 0
if bw == "nrd0":
bw2 = 31.39367
else:
print("No such bandwidth.")
for i in range[len(x)]:
x[i] = x[i] * bw2
for i in range[len(x)]:
result = result + x[i]
return result * adjust
And I wanted to test it:
x = [1, 3, 5]
kern = density(x, "nrd0", 1)
print(kern)
And I gained 2 errors, the main one being a TypeError.
If you want to look into it further, here's the whole terminal message:
Traceback (most recent call last):
File "density.py", line 15, in <module>
kern = density(x, "nrd0", 1)
File "density.py", line 8, in density
for i in range[len(x)]:
TypeError: 'type' object is not subscriptable
How do I fix the TypeError?
for i in range[len(x)]:
x[i] = x[i] * bw2
You have range with [] while it should be (). Try to change it.
Below is an example:
l = [10, 20, 30, 40]
for i in range(len(l)):
print(l[i], end =" ")
print()

How to add a linear constraint in CPLEX Python API?

Linear program:
Decision Variables:
x[]
Maximize: Sum(i to n) (fare[i] * x[i])
subject to:
x[i] <= demand[i]
I am trying to add a linear constraint in cplex using Python, but I am not able to get the syntax correct.
fare = [400.0, 700.0, 600.0]
dmd= [2, 4, 3]
itins = []
for count in range(3):
i = Itinerary(count, 1, dmd[count], fare[count])
itins.append(i)
# problem variables
X=[] * len(itins)
def setupproblem(c):
c.objective.set_sense(c.objective.sense.maximize)
num_x = range(len(itins))
print (num_x)
varnames = ["X"+str(j) for j in range(len(itins))]
c.variables.add(names = varnames, lb=[0.0, 0, 0], ub=[10.0, 10, 10])
x = [c.variables.add(obj=fare) for i in num_x]
i_iten = range(len(itins))
c.linear_constraints.add(lin_expr = [cplex.SparsePair(ind = i_iten,
val = X[i])
for i in range(len(itins) -1 )],
senses = ["L"],
rhs = capacity,
names = ["capacity_"+str(i)
for i in i_iten])
I am getting this error:
raise CplexError(" %d: Invalid name -- '%s'\n" % tuple(self._mat))
cplex.exceptions.errors.CplexError: 1210: Invalid name -- 'X'
In cplex.SparcePair you need to specify nonzero elements under val and the corresponding variables under ind. Plus, from your linear program your right-hand side should be dmd.
c.linear_constraints.add(lin_expr = [cplex.SparsePair(ind = xname,
val = [1.0])
for xname in varnames],
senses = ["L"],
rhs = dmd,
names = ["capacity_"+str(i)
for i in i_iten])
Also I would suggest to indicate the objective function when you add variables:
c.variables.add(obj = fare, names = varnames, lb=[0.0, 0, 0], ub=[10.0, 10, 10])
c.linear_constraints.add(lin_expr=[cplex.SparsePair(ind=[xname], val=[1.0]) for xname in varn], senses=["L"] * len(varnames), rhs=dmd)
But before you add the constraints on the variables, please keep in mind that the variable names should be added to the function. I spent 4 hours going round and round to figure out what was going wrong.
This line should come first.
c.variables.add(varnames)
Thanks serge_k for your initial pointers !!

python notation form textbook

I have a code snipped from my algorithms text book and i'm have a hard time understanding it.
K(0) = 0
for w = 1 to W
K(w) = max{K(w - w_i)+vi:w_i<=w}
return K(W)
i'm confused as to whats happening on line 3 what does the colon mean here? can this be written in a different way?
This doesn't look like python. It seems that K is supposed to be an array, but indices are indicated by square brackets in python, so K[0] = 0
And the for w = 1 to W doesn't work in python at all, it would be more like this: for w in range(1, W+1):
As for what the pseudo code does: It looks like for each element of K, it calculates the maximum of all previous values and adds vi.
for w in range(1, W+1):
K[w] = max(K[w - w_i] + vi for w_i in range(1, w+1))
But vi doesn't seem to change, so for positive vi, this produces simply a linearly ascending array (i.e. [0, 2, 4, 6, ... for vi = 2), and for negative it just repeats vi over and over: [0, -3, -3, -3, ... for vi = -3
Since it returns only the last value of the array, it could be simplified to
return W*vi if vi>0 else vi

How to solve multivariate inequalities with python and sympy?

I'm quite new using python and Sympy... And got a problem to solve multivariate inequalities using sympy.
Let's say I have a lot of functions in a file which look like this :
cst**(sqrt(x)/2)/cst
exp(sqrt(cst*x**(1/4)))
log(log(sqrt(cst + exp(x))))
(y**(1/4) + y)**cst
sqrt(y/log(x))/cst
sqrt(cst**log(cst) + x)
(y**2)**(x/4)
sqrt(y*sqrt(cst**y))
log(sqrt(2)*sqrt(cst)*x)
I need to derivate them, set the value of the constant and check if, for each functions f,
df/dx > 0
df/dy < 0
With x in [0, +oo) and y in [0, 1].
To derivate i use :
dx = diff(f, x)
dy = diff(f, y)
Then when i try :
cst = 2 #(for example)
solve(dx > 0)
I got this error :
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/sympy/solvers/solvers.py", line 634, in solve
symbols=symbols)
File "/usr/local/lib/python2.7/dist-packages/sympy/solvers/inequalities.py", line 374, in reduce_inequalities
raise NotImplementedError("only univariate inequalities are supported")
NotImplementedError: only univariate inequalities are supported
But if i try that :
x=Symbol('x', real=True, postive=True, nonzero=True)
y=Symbol('y', real=True, postive=True, nonzero=True)
solve(x**2+y > 0)
I got :
True
Which is good and workable answer.
Is there anyway to solve multivariate inequalities and always get an workable answer?
For example I would like to get :
solve(x**2-y>0)
Or(x>-sqrt(y), x>sqrt(y))
When trying to solve this with SymPy you get a pretty clear error message: NotImplementedError: only univariate inequalities are supported. Be aware that this means that the SymPy team will be very happy if you contribute an algorithm that solves this problem.
Now that it is clear that sympy.solve is not powerful enough you can try another approach. Recently (in 0.7.2) an implicit plotting routine was added to sympy that can plot where an expression evaluates to True. Regretfully it is only a numeric solution, not a symbolic one that you can get from solve but it might be enough:
From the image you can see that there is only a single line where the expression changes sign, so solving for expr==0 might give you what you want. And this is indeed the case:
There is a multivariate inequality solver in mystic, which is built on top of sympy. It uses optimization and the (mathematical) mapping of sets to provide this feature. It's not perfect, but works for many cases.
>>> equations = '''
... 2*A + 3*B >= C
... A*B > D
... C < 4*A
... D == 0
... '''
>>>
>>> import mystic.symbolic as ms
>>> var = list('ABCD')
>>> eqns = ms.simplify(equations, variables=var)
>>> print eqns
D == 0
B > 0
A > C/4
A >= -3*B/2 + C/2
A > D/B
>>>
>>> # generate a constraints function, which maps one space to another
>>> constrain = ms.generate_constraint(ms.generate_solvers(eqns, var))
>>> solution = constrain([1,2,3,4])
>>> print solution
[1, 2, 3, 0]
>>> # here's the solution...
>>> dict(zip(var,solution))
{'A': 1, 'C': 3, 'B': 2, 'D': 0}
>>>
>>> A=1; C=3; B=2; D=0
>>> 2*A + 3*B >= C
True
>>> A*B > D
True
>>> C < 4*A
True
>>> D == 0
True
>>>
Let's do it again, with the suggested test:
>>> equations = """x**2 - y >= 0
... x + y = 0
... """
>>> eqns = ms.simplify(equations, variables=var)
>>> constrain = ms.generate_constraint(ms.generate_solvers(eqns, var))
>>> solution = constrain([1,3])
>>> solution
[-3, 3]
>>> dict(zip(var, solution))
{'y': 3, 'x': -3}
>>> y=3; x=-3
>>> x**2 - y >= 0
True
>>> x+y == 0
True
>>>
mystic uses a combination of sympy and numerical optimization to simplify inequalities; and when presented with an initial guess solution, can (most of the time, but not always) generate a valid solution to the equations. mystic won't actually solve the inequalities per se, but it will (usually) generate a valid solution to the inequalities.

Project Euler #45: How is my logic wrong?

From Project Euler, problem 45:
Triangle, pentagonal, and hexagonal numbers are generated by the following formulae:
Triangle T_(n)=n(n+1)/2 1, 3, 6, 10, 15, ...
Pentagonal P_(n)=n(3n−1)/2 1, 5, 12, 22, 35, ...
Hexagonal H_(n)=n(2n−1) 1, 6, 15, 28, 45, ...
It can be verified that T_(285) = P_(165) = H_(143) = 40755.
Find the next triangle number that is also pentagonal and hexagonal.
[ http://projecteuler.net/problem=45 ]
Now to solve them I took three variables and equated the equations to A.
n(n + 1)/2 = a(3a - 1)/2 = b(2b - 1) = A
A = number at which the threee function coincide for values of n, a, b
Resultant we get 3 equations with n and A. Solving with quarditic formula, we get 3 equations.
(-1 + sqrt(1 + 8*A ) )/2
( 1 + sqrt(1 + 24*A) )/6
( 1 + sqrt(1 + 8*A ) )/4
So my logic is to test for values of A at which the three equation give a natural +ve value. So far it works correct for number 40755 but fails to find the next one upto 10 million.
(Edit): Here is my code in python
from math import *
i=10000000
while(1):
i = i + 1
if(((-1+sqrt(1+8*i))/2).is_integer()):
if(((1+sqrt(1+24*i))/6).is_integer()):
if(((1+sqrt(1+8*i))/4).is_integer()):
print i
break
How is my logic wrong? (Apologies for a bit of maths involved. :) )
Given that:
all hexagonals are also triangulars
heapq.merge is quite handy for the task at hand (efficient and saves code)
then this:
import heapq
def hexagonals():
"Simplified generation of hexagonals"
n= 1
dn= 5
while 1:
yield n
n+= dn
dn+= 4
def pentagonals():
n= 1
dn= 4
while 1:
yield n
n+= dn
dn+= 3
def main():
last_n= 0
for n in heapq.merge(hexagonals(), pentagonals()):
if n == last_n:
print n
last_n= n
main()
produces 1, 40755 and the other number you're seeking in almost no time, and a few seconds later a 14-digit number. Just stop the program when you think you burned enough electricity.
In case you want to avoid “opaque” libraries, use the following main (essentially the same algorithm, only spelled out):
def main():
hexagonal= hexagonals()
pentagonal= pentagonals()
h= next(hexagonal)
p= next(pentagonal)
while 1:
while p < h:
p= next(pentagonal)
if p == h:
print p
h= next(hexagonal)
Times look similar, but I didn't bother to benchmark.
Your logic is not wrong, your program just takes a long time to run (by my estimate it should provide an answer in about an hour). I know the answer and tested your program by setting i to a value just below it. Your program then popped out the right answer at once.
Heed the advice of ypercube.
simplest way to implement is to make 3 generators for each sequence and route them in
heapq.merge
and then if you find 3 same consecitive keys you got solution
Simplest way to find this is usnig
itertools.groupby

Categories