How could I generate random coefficients for polynomials using Sum( f(x), (x,0,b) )? - sympy

from sympy import Sum, Eq
from sympy.abc import n,x
import random
def polynomial(x):
i = 0
def random_value(i):
return random.choice([i for i in range(-10,10) if i not in [0]])
eq = Sum(random_value(i)*x**n, (n,0,random_value(i)))
display(Eq(eq,eq.doit(), evaluate=False))
polynomial(x)
polynomial(x)
With this code, the coefficients are always the same.
Also, I am not sure if the algebra evaluations are correct for b < 0 .

One way is to use IndexedBase to generate symbolic-placeholder coefficients, and then substitute them with numerical coefficients.
from sympy import Sum, Eq, Matrix, IndexedBase
from sympy.abc import n, x
import random
def polynomial(x):
# n will go from zero to this positive value
to = random.randint(0, 10)
# generate random coefficients
# It is important for them to be a sympy Matrix or Tuple,
# otherwise the substitution (later step) won't work
coeff = Matrix([random.randint(-10, 10) for i in range(to + 1)])
c = IndexedBase("c")
eq = Sum(c[n]*x**n, (n, 0, to)).doit()
eq = eq.subs(c, coeff)
return eq
display(polynomial(x))
display(polynomial(x))
Another ways is to avoid using Sum, relying instead on list-comprehension syntax and builtin sum:
def polynomial(x):
to = random.randint(0, 10)
coeff = [random.randint(-10, 10) for i in range(to + 1)]
return sum([c * x**n for c, n in zip(coeff, range(to + 1))])
display(polynomial(x))
display(polynomial(x))

You can pass a list of coefficients (with highest order coefficient first and constant last) directly to Poly and then convert that to an expression:
>>> from sympy import Poly
>>> from sympy.abc import x
>>> Poly([1,2,3,4], x)
Poly(x**3 + 2*x**2 + 3*x + 4, x, domain='ZZ')
>>> _.as_expr()
x**3 + 2*x**2 + 3*x + 4
>>> from random import randint, choice
>>> Poly([choice((-1,1))*randint(1,10) for i in range(randint(0, 10))], x).as_expr()
-3*x**4 + 3*x**3 - x**2 - 6*x + 2

Related

Distance from a point to a line : output nan?

Thank you in advance and sorry for the bad English!
(ref)Distance from a point to a line < wikipedia
https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
from sympy import *
var('a b c x y x1 y1 x2 y2 x0 y0 co si tx ty d DH')
x1=0
y1=solve([a*x+b*y+c],[y])[y].subs({x:0})
x2=solve([a*x+b*y+c],[x])[x].subs({y:0})
y2=0
d=sqrt((x1-x2)**2+(y1-y2)**2)
v=solve([co*0-si*0+tx-x1,si*0+co*0+ty-y1,co*d-si*0+tx-x2,si*d+co*0+ty-y2],[co,si,tx,ty])
A=Matrix([
[v[co],-v[si],v[tx]],
[v[si], v[co],v[ty]],
[0 , 0, 1]
])
B=Matrix([
[x0],
[y0],
[ 1]
])
AinvB=A.inv()*B
DH=simplify(AinvB[1])
print(DH)
print(float(DH.subs({a:1,b:-1,c:10,x0:0,y0:11})))
print(float(DH.subs({a:1,b:-1,c: 0,x0:0,y0: 1})))
# -c*(a*x0 + b*y0 + c)/(a*b*sqrt(c**2*(a**2 + b**2)/(a**2*b**2)))
# -0.7071067811865476
# nan
The expression you generate is not always valid for all substituted values. In the case that gives nan your expression generates 0/0 which is nan.
>>> from sympy import S, fraction, Tuple
>>> eq=S('-c*(a*x0 + b*y0 + c)/(a*b*sqrt(c**2*(a**2 + b**2)/(a**2*b**2)))')
>>> n,d=fraction(eq)
>>> Tuple(n,d).subs(dict(a=1,b=-1,c=0,x0=0,y0=1))
(0, 0)
>>> _[0]/_[1]
nan
You might be interested in using SymPy's geometric objects to help with such calculations and (in this case) compare their expressions to what you generate by other means:
>>> from sympy.abc import b,m,x,y
>>> from sympy import Point, Line
>>> d=Point(x,y).distance(Line(m*x+b-y))
>>> d
sqrt((x-(-b*m+m*y+x)/(m**2+1))**2 + (y-(b+m**2*y+m*x)/(m**2+1))**2)
>>> d.subs(y, m*x+b).simplify()
0

How to perform the multiplication rule for selecting two items without replacement?

I'm experimenting with sympy to reproduce an example where a box has three marbles:
Red
White
Blue
Two marbles will be drawn at random without replacement.
Q: What is the chance of drawing the Red marble and then the White marble?
I have been able to calculate this using the multiplication rule by hard-coding P() instances wrapping the initial distribution before the first marble is selected and then the distribution before the second marble is selected:
from sympy.stats import DiscreteUniform, density, P
from sympy import symbols, Eq
# Coloured marbles
R, W, B = symbols('R W B')
# Select first marble without replacement
PFirstSelection = P(Eq(DiscreteUniform('FirstSeletion', (R, W, B)), R))
# Select second marble - Red is not longer available because it was selected without replacement
PSecondSelection = P(Eq(DiscreteUniform('SecondSelection', (W, B) ), W))
print(PFirstSelection)
# 1/3
print(PSecondSelection)
# 1/2
# Multiplication rule
print(PFirstSelection * PSecondSelection)
# 1/6
Is there a better way that I can achieve this with sympy?
In this case you'd better to use combination functions.
DiscreteUniform seems not for changing elements after creation.
from sympy.functions.combinatorial.numbers import nC, nP
print(1 / nP(3, 2)) # 1/6
If you don't care about order,
print(nP(2, 2) / nP(3, 2)) # 1/3
Edited. (and also modified for python3)
For N of M things, you can simply do like below
from sympy.functions.combinatorial.numbers import nC, nP
def pickProb(candidates, picks, ordered=False):
picks_num = len(picks)
numerator = nP(picks_num, picks_num) if ordered else 1
denominator = nP(len(candidates), picks_num)
return numerator / denominator
print(pickProb('RWB', 'RW')) # 1/6
print(pickProb('RWBrwba', 'Ra')) # 1/42
print(pickProb('RWBrwba', 'RWa')) # 1/210
print(pickProb('RWBrwba', 'RWa', ordered=True)) # 1/35
And combination functions can also handle duplicates, like 'R', 'R', 'W', 'B'.
from operator import mul
from sympy.functions.combinatorial.numbers import nC, nP
def pickProb(candidates, picks):
picks_num = len(picks)
c_counts = {}
for c in candidates:
c_counts[c] = c_counts[c] + 1 if c in c_counts else 1
p_counts = {}
for p in picks:
p_counts[p] = p_counts[p] + 1 if p in p_counts else 1
combinations = reduce(mul, [nP(c_counts[x], p_counts[x]) for x in p_counts.keys()], 1)
denominator = nP(len(candidates), picks_num) / combinations
return 1 / denominator
print(pickProb('RWBra', 'RWa')) # 1/60
print(pickProb('RRRWa', 'RWa')) # 1/20
print(pickProb('RRRWa', 'RRa')) # 1/10
But DiscreteUniform cannot, because this case is not "uniform".
from sympy.stats import DiscreteUniform, density, P, Hypergeometric
from sympy import Symbol, Eq
deck = DiscreteUniform('M', 'RRWB')
print(density(deck).dict) # {W: 1/4, R: 1/4, B: 1/4}
print(P(Eq(deck, Symbol('R')))) # 1/4
I think you're using correctly sympy, but you can improve your way to use python (eg., more generic, more functional, more generic, no hardcoding).
For instance:
from sympy.stats import DiscreteUniform, density, P
from sympy import symbols, Eq
from itertools import accumulate
def ToSet(value):
return set(value.split(' '))
def ProbaOfPick(pickSet, fromSet, operationTag):
return P(Eq(DiscreteUniform(operationTag, symbols(fromSet)), symbols(pickSet)))
def PickWithoutReplacement(allset, picklist, probaFunc):
currentSet = allset
probaSeq = []
operationSeq = []
for pick in picklist:
operationTag = "picking: " + pick
newP = probaFunc(pick, currentSet, operationTag)
operationSeq.append(operationTag + " from " + str(currentSet))
probaSeq.append(newP)
currentSet -= set(pick)
return (operationSeq, probaSeq)
allset = ToSet('R W B Y Ma G1 G2')
picks = 'R', 'W', 'G2'
operationSeq, probaSeq = PickWithoutReplacement(allset, picks, ProbaOfPick)
probas = list(accumulate(probaSeq, lambda a, b: a*b))
for op in operationSeq:
print(op)
print(probas)
Also your can change uniform distribution to anything non-uniform.
EDIT: dependency injection (ProbaOfPick -> probaFunc) added.
This code is only a starter.
Result:
picking: R from {'G2', 'Ma', 'Y', 'B', 'R', 'G1', 'W'}
picking: W from {'G2', 'Ma', 'Y', 'B', 'G1', 'W'}
picking: G2 from {'G2', 'Ma', 'Y', 'B', 'G1'}
[1/7, 1/42, 1/210]
Next steps: allow to pick more than 1 each step, allow non uniform probability distribution, etc

How to solve this differential equation in sympy?

I want to solve this differential equation in sympy:
f'(x) = f(x+1)
I try this:
from sympy import *
x = symbols("x")
f = Function("f")
f_ = Derivative(f,x)
dsolve(f_(x) - f(x+1), f(x))
but get an error: "'Derivative' object is not callable".
When I replace "f_(x)" by "f_", I get a different error: "TypeError: doit() missing 1 required positional argument: 'self'".
What is the correct syntax for this?
You have to differentiate after providing an argument.
The following works for me:
from sympy import *
x = symbols("x")
f = Function("f")
f_ = Derivative(f(x),x)
dsolve(f_ - f(x+1), f(x))
Sidenote: Solution to your actual problem
What you have is essentially a DDE, just with the time pointing in the wrong direction. The typical form of the DDE would be g'(t) = −g(t−1). With this module of mine, we can solve this numerically:
from jitcdde import y, t, jitcdde
from numpy import arange
f = [-y(0,t-1)]
DDE = jitcdde(f)
DDE.constant_past([1.0])
DDE.step_on_discontinuities()
times = arange(0,1000,0.1) + DDE.t
solution = [(time,DDE.integrate(time)[0]) for time in times]
It seems that no matter how we initialise the past, the solutions eventually converge to something of the form exp(a·t)·sin(b·t) with some constants a and b specified below. In fact if instead of DDE.constant_past([1.0]) we use
a = -0.318131477176434
b = 1.33723563936212
DDE.past_from_function([exp(a*t)*sin(b*t)])
the solution matches exp(a·t)·sin(b·t) extremely well.
Something tells me we're on a hiding to nowhere. This is not a useful answer.
>>> from sympy import *
>>> f = Function('f')
>>> var('x')
x
>>> Eq(f(x).diff(x,x)-f(x+1))
Eq(-f(x + 1) + Derivative(f(x), x, x), 0)
>>> dsolve(_,f(x))
Eq(f(x), C1 + x*(C2 + Integral(f(x + 1), x)) - Integral(x*f(x + 1), x))
>>> latex(_)
'f{\\left (x \\right )} = C_{1} + x \\left(C_{2} + \\int f{\\left (x + 1 \\right )}\\, dx\\right) - \\int x f{\\left (x + 1 \\right )}\\, dx'
As a graphic (having tried various ways of putting the mathematical representation here.)

Trying to divide by solution of odeint

I am using odeint in python to solve something (the Friedmann equation for a matter only universe) and it gives me the values of a that i want. However, how do i get it to return/plot (da/dt)/a? i.e how can divide the values for the function for the derivative by the corresponding values of the solution?
This is my attempted code: (ignore the earlier bits i.e the figure 1 plot; its the part with H i'm concerned about)
import numpy as np
import matplotlib.pyplot as plt
import scipy as sp
from scipy.integrate import odeint
t_0 = 0.0004
a_0 = 0.001
omega_m = 1.0 #for EdS
H_0 = 1./13.7
#the function for EdS universe
def Friedmann(a, t):
dadt = H_0 * (omega_m)**(1./2.) * a**(-1./2.)
return dadt
t = np.linspace(t_0,13.7,101)
a = odeint(Friedmann, a_0, t)
a = np.array(a).flatten()
plt.figure(1)
plt.subplot(211)
plt.plot(t, a)
plt.title("Einstein-de Sitter Universe")
plt.xlabel("t")
plt.ylabel("a")
#comparing to analytic solution
an = (((3. / 2.) * (H_0 * omega_m**(1./2.)) * (t - t_0)) + a_0**(3. / 2.))**(2. / 3.)
an = np.array(an).flatten()
plt.figure(1)
plt.subplot(212)
plt.plot(t, a, t, an, "+")
H = [x/y for x, y in zip(Friedmann(a, t), a)]
plt.figure(2)
plt.plot(t, H)
plt.show()
Any help is much appreciated.

Defining a range for a symbol in Sympy

In Sympy it is possible to define constraints on what values a symbol may take
x = symbols('x', real=True)
Is it possible to say that a symbol should take values only in a certain range, say -1 < x < 1? The reason why I am interested in this is because I am trying to get sympy to automatically simplify expressions like the one below
expr = sqrt(1+x) * sqrt((1-x)*(1+x)) / sqrt(1-x)
Running simplify(expr) yields no simplification, whereas when -1<x<1 the simplified result should be 1+x. How do I get sympy to simplify expressions like the one above?
Although a single symbol can't hold that assumption, an expression can. Let's define an expression that has the desired range:
>>> p = Symbol('p', positive=True)
>>> neg1to1 = (p - 1)/(p + 1)
Now replace x with that value and simplify
>>> asp = expr.subs(x, neg1to1).simplify(); asp
2*p/(p + 1)
Now restore x from the relationship between it and neg1to1:
>>> p_as_x = solve(neg1to1 - x, p)[0]
>>> asp.subs(p, p_as_x).simplify()
x + 1
You could turn this into a function to allow for any range for x:
>>> def simplify_assuming_range(expr, x, lo, hi):
... from sympy import Dummy, solve
... p = Dummy(positive=True)
... xr = (p - 1)/(p + 1)*(hi - lo) + lo
... rx = solve(xr - x, p)[0]
... return expr.subs(x, xr).simplify().subs(p, rx).simplify()
...
>>> simplify_assuming_range(expr,x,-1,1)
x + 1
Using targeted expansion with force can help:
>>> expand(expr, power=True, force=True, mul=False)
x + 1
The expand docstring will tell about each of those options.