Save simplify solve as decimal - sage

With this code:
x, a, b = var('x a b')
eq1 = sin(x) == a + b
solve([eq1,a==1, b==-0.1], x,a,b)
I get a non human readable:
[[a == 1, b == (-3602879701896397/36028797018963968), x == pi + 2*pi*z7004 - arctan(32425917317067571/82211366926801441775188500821661*sqrt(27403788975600480591729500273887))], [a == 1, b == (-3602879701896397/36028797018963968), x == 2*pi*z7058 + arctan(32425917317067571/82211366926801441775188500821661*sqrt(27403788975600480591729500273887))]]
How to make it output:
[[a == 1, b == -0.1, x == pi -1.11976 + 2*pi*n], [a == 1, b == b == -0.1, x == 1.11976 + 2*pi*n]]

One can try the same solve process having exact numbers when possible:
x, a, b = var('x,a,b')
for sol in solve([sin(x) == a + b, a == 1, b == -1/10], [x, a, b]):
print(sol)
with the output:
[a == 1, b == (-1/10), x == pi + 2*pi*z20314 - arctan(9/19*sqrt(19))]
[a == 1, b == (-1/10), x == 2*pi*z20376 + arctan(9/19*sqrt(19))]
From here it is easier to get the numerical values (for the involved constants) programatically. I understand that the question is a toy example for something wilder in practice, where instead of that "beautiful" -0.1 there may be some -0.8743891743127341234 - and making it exact would lead to less useful exact answers. But we have to keep in mind that == is an equality, that should be checked / checkable in that manner in the domain used (reals or complex numbers).
Alternatively, if indeed numerical solutions are wanted in a situation similar to the one described above, i would try
x, a, b = var('x,a,b')
solve([sin(x) == a + b, a == 1.0, b == -0.1], [x, a, b], algorithm='sympy')
which delivers:
[{a: 1.00000000000000, b: -0.100000000000000, x: 1.11976951499863},
{a: 1.00000000000000, b: -0.100000000000000, x: 2.02182313859116}]
and yes, we are losing the 2 pi ZZ freedom in x. But for me, sage should be used complementing the own devices, not as a machine giving answers in a best format.

Related

Update cartesianIndex

I am stuck in a problem. I want to update my cartesian index.
I have a matrix (x) 200x6 that is binary. 1 if assigned, 0 otherwise. I want to find the cartesian index of when x is 1 in the first 3 columns and in the last 3 elements.
I have the following code:
index_right = findall( x -> x == 1, sol.x_assignment[:,1:3])
index_left = findall( x -> x == 1, sol.x_assignment[:,4:6])
index_left
However index_right is correct, index_left is wrong as it returns index between 1,2,3 instead of 4,5,6
CartesianIndex(2, 1)
CartesianIndex(3, 1)
CartesianIndex(10, 2)
CartesianIndex(11, 1)
Expected output:
CartesianIndex(2, 4)
CartesianIndex(3, 4)
CartesianIndex(10, 5)
CartesianIndex(11, 4)
How can I update index_left to add +3 in the second index for all?
One solution could be
index_left = findall( x -> x == 1, sol.x_assignment[:,4:6])
index_left = map(x -> x + CartesianIndex(0, 3), index_left)
I think you can also use ==(1) in place of x -> x + 1, looks a bit nicer :)
index_left = findall(==(1), sol.x_assignment[:,4:6])
and the inplace version of map should work too
map!(x -> x + CartesianIndex(0, 3), index_left, index_left).
An alternative could be first finding all the indices with 1 and then filtering afterwards, so smth like
full_index = findall(==(1), sol.x_assignment)
and then
left_index = filter(x -> x[2] <= 3, full_index)
right_index = filter(x -> x[2] > 3, full_index)
Assuming your x is:
using Random;Random.seed!(0);
x = rand(Bool, (5,6))
The first set can be found as:
findall(isone, #view x[:, 1:3])
For the second set you need to shift the results hence you want:
findall(isone, #view x[:, 4:6]) .+ Ref( CartesianIndex(0,3))
If you are searching for different value eg. 2 use ==(2) rather than a lambda as this is faster.
Similarly #view allows to avoid unnecessary allocations.

Triangle distribution ifelse statement

I am trying to make my own function of the triangle distribution that should return the probability, similar to the one in triangle package. The problem I have is how to incorporate the if statement of lower.tail (that should compute the lower tail) and log.p (that should compute the logarithm of the density). Is there anyone who knows how to solve this?
Thanks.
The function I have:
ptriangle3 <- function(q, a, b, c, lower.tail = T, log.p = F){
if (!all(a <= c && c <= b && a < b)) stop("Villkoren måste uppfyllas: a <= c <= b and a < b!")
ifelse(q > a & q < b,
ifelse(q <= c,
((q-a)^2)/((b-a)*(c-a)),
1-((b-q)^2)/((b-a)*(b-c))),
ifelse(q <= a,
0,
1))
}

I want to use mathematica so solve a system of 3 diferential equations but it is giving some errors

I am trying to solve this system of eqs
dw(v,t)/dt =2g(v,t) w(t,v)
g(t,v)= Pi/2 (v^2)d g0(v,t)/dt
d go(v,t)/dt + d/dv[dw/dt *1/v^3)]=0
initial conditions
f0= (a/(Pi)^0.5)*e^[v^2/ve^2] + (b/(Pi)^0.5)*e^[(v - u)^2/ve^2]
a^2 + b^2 = 1
f0=go(v,0)
w(v,0)=0
This is my code
Here I am initializing some variables and defining f0 that is g(v,t=0).
a = 0.5;
b = (3^0.5)/2;
ve = 1;
u = 1;
f0[v_] = (a/(Pi)^0.5)Exp[v^2/ve^2] + (b/(Pi)^0.5)Exp[(v - u)^2/ve^2];
u1 = Log[((1 - a^2)/a^2)^0.5]/(2*u) + u/2;
u2 = 3u/2 - Log[((1 - a^2)/a^2)^0.5]/(2u);
f0[u1]
f0[u2]
Here I am using a system of 3 eqs for 3 functions and equating g(v,0)=f0
sol = NDSolve[{
D[go[v, t], t] + D[D[w[v, t], t], v]/(v^3) + (-3v^(-4))D[w[v, t], t] == 0,
g[v, t] == Pi/2 (v^2) D[go[v, t], v],
go[v, 0] == f0[v],
D[w[v, t], t] == 2g[v, t]w[v, t],
w[v, 0] == 0},
{go[v, t], W[v, t]},
{v, u1, u2},
{t, 0, 10000000000}]
And it is returning errors like
The PDE is convection dominated and the result may not be stable.
Adding artificial diffusion may help
"No DirichletCondition or Robin-type NeumannValue was specified for
{g}; the result may not be unique"
The PDE is convection dominated and the result may not be stable.
Adding artificial diffusion may help.

How to approach this type of problem in permutation and combination?

Altitudes
Alice and Bob took a journey to the mountains. They have been climbing
up and down for N days and came home extremely tired.
Alice only remembers that they started their journey at an altitude of
H1 meters and they finished their wandering at an alitude of H2
meters. Bob only remembers that every day they changed their altitude
by A, B, or C meters. If their altitude on the ith day was x,
then their altitude on day i + 1 can be x + A, x + B, or x + C.
Now, Bob wonders in how many ways they could complete their journey.
Two journeys are considered different if and only if there exist a day
when the altitude that Alice and Bob covered that day during the first
journey differs from the altitude Alice and Bob covered that day during
the second journey.
Bob asks Alice to tell her the number of ways to complete the journey.
Bob needs your help to solve this problem.
Input format
The first and only line contains 6 integers N, H1, H2, A, B, C that
represents the number of days Alice and Bob have been wandering,
altitude on which they started their journey, altitude on which they
finished their journey, and three possible altitude changes,
respectively.
Output format
Print the answer modulo 10**9 + 7.
Constraints
1 <= N <= 10**5
-10**9 <= H1, H2 <= 10**9
-10**9 <= A, B, C <= 10**9
Sample Input
2 0 0 1 0 -1
Sample Output
3
Explanation
There are only 3 possible journeys-- (0, 0), (1, -1), (-1, 1).
Note
This problem comes originally from a hackerearth competition, now closed. The explanation for the sample input and output has been corrected.
Here is my solution in Python 3.
The question can be simplified from its 6 input parameters to only 4 parameters. There is no need for the beginning and ending altitudes--the difference of the two is enough. Also, we can change the daily altitude changes A, B, and C and get the same answer if we make a corresponding change to the total altitude change. For example, if we add 1 to each of A, B, and C, we could add N to the altitude change: 1 additional meter each day over N days means N additional meters total. We can "normalize" our daily altitude changes by sorting them so A is the smallest, then subtract A from each of the altitude changes and subtract N * A from the total altitude change. This means we now need to add a bunch of 0's and two other values (let's call them D and E). D is not larger than E.
We now have an easier problem: take N values, each of which is 0, D, or E, so they sum to a particular total (let's say H). This is the same at using up to N numbers equaling D or E, with the rest zeros.
We can use mathematics, in particular Bezout's identity, to see if this is possible. Some more mathematics can find all the ways of doing this. Once we know how many 0's, D's, and E's, we can use multinomial coefficients to find how many ways these values can be rearranged. Total all these up and we have the answer.
This code finds the total number of ways to complete the journey, and takes it modulo 10**9 + 7 only at the very end. This is possible since Python uses large integers. The largest result I found in my testing is for the input values 100000 0 100000 0 1 2 which results in a number with 47,710 digits before taking the modulus. This takes a little over 8 seconds on my machine.
This code is a little longer than necessary, since I made some of the routines more general than necessary for this problem. I did this so I can use them in other problems. I used many comments for clarity.
# Combinatorial routines -----------------------------------------------
def comb(n, k):
"""Compute the number of ways to choose k elements out of a pile of
n, ignoring the order of the elements. This is also called
combinations, or the binomial coefficient of n over k.
"""
if k < 0 or k > n:
return 0
result = 1
for i in range(min(k, n - k)):
result = result * (n - i) // (i + 1)
return result
def multcoeff(*args):
"""Return the multinomial coefficient
(n1 + n2 + ...)! / n1! / n2! / ..."""
if not args: # no parameters
return 1
# Find and store the index of the largest parameter so we can skip
# it (for efficiency)
skipndx = args.index(max(args))
newargs = args[:skipndx] + args[skipndx + 1:]
result = 1
num = args[skipndx] + 1 # a factor in the numerator
for n in newargs:
for den in range(1, n + 1): # a factor in the denominator
result = result * num // den
num += 1
return result
def new_multcoeff(prev_multcoeff, x, y, z, ag, bg):
"""Given a multinomial coefficient prev_multcoeff =
multcoeff(x-bg, y+ag, z+(bg-ag)), calculate multcoeff(x, y, z)).
NOTES: 1. This uses bg multiplications and bg divisions,
faster than doing multcoeff from scratch.
"""
result = prev_multcoeff
for d in range(1, ag + 1):
result *= y + d
for d in range(1, bg - ag + 1):
result *= z + d
for d in range(bg):
result //= x - d
return result
# Number theory routines -----------------------------------------------
def bezout(a, b):
"""For integers a and b, find an integral solution to
a*x + b*y = gcd(a, b).
RETURNS: (x, y, gcd)
NOTES: 1. This routine uses the convergents of the continued
fraction expansion of b / a, so it will be slightly
faster if a <= b, i.e. the parameters are sorted.
2. This routine ensures the gcd is nonnegative.
3. If a and/or b is zero, the corresponding x or y
will also be zero.
4. This routine is named after Bezout's identity, which
guarantees the existences of the solution x, y.
"""
if not a:
return (0, (b > 0) - (b < 0), abs(b)) # 2nd is sign(b)
p1, p = 0, 1 # numerators of the two previous convergents
q1, q = 1, 0 # denominators of the two previous convergents
negate_y = True # flag if negate y=q (True) or x=p (False)
quotient, remainder = divmod(b, a)
while remainder:
b, a = a, remainder
p, p1 = p * quotient + p1, p
q, q1 = q * quotient + q1, q
negate_y = not negate_y
quotient, remainder = divmod(b, a)
if a < 0:
p, q, a = -p, -q, -a # ensure the gcd is nonnegative
return (p, -q, a) if negate_y else (-p, q, a)
def byzantine_bball(a, b, s):
"""For nonnegative integers a, b, s, return information about
integer solutions x, y to a*x + b*y = s. This is
equivalent to finding a multiset containing only a and b that
sums to s. The name comes from getting a given basketball score
given scores for shots and free throws in a hypothetical game of
"byzantine basketball."
RETURNS: None if there is no solution, or an 8-tuple containing
x the smallest possible nonnegative integer value of
x.
y the value of y corresponding to the smallest
possible integral value of x. If this is negative,
there is no solution for nonnegative x, y.
g the greatest common divisor (gcd) of a, b.
u the found solution to a*u + b*v = g
v " "
ag a // g, or zero if g=0
bg b // g, or zero if g=0
sg s // g, or zero if g=0
NOTES: 1. If a and b are not both zero and one solution x, y is
returned, then all integer solutions are given by
x + t * bg, y - t * ag for any integer t.
2. This routine is slightly optimized for a <= b. In that
case, the solution returned also has the smallest sum
x + y among positive integer solutions.
"""
# Handle edge cases of zero parameter(s).
if 0 == a == b: # the only score possible from 0, 0 is 0
return (0, 0, 0, 0, 0, 0, 0, 0) if s == 0 else None
if a == 0:
sb = s // b
return (0, sb, b, 0, 1, 0, 1, sb) if s % b == 0 else None
if b == 0:
sa = s // a
return (sa, 0, a, 1, 0, 1, 0, sa) if s % a == 0 else None
# Find if the score is possible, ignoring the signs of x and y.
u, v, g = bezout(a, b)
if s % g:
return None # only multiples of the gcd are possible scores
# Find one way to get the score, ignoring the signs of x and y.
ag, bg, sg = a // g, b // g, s // g # we now have ag*u + bg*v = 1
x, y = sg * u, sg * v # we now have a*x + b*y = s
# Find the solution where x is nonnegative and as small as possible.
t = x // bg # Python rounds toward minus infinity--what we want
x, y = x - t * bg, y + t * ag
# Return the information
return (x, y, g, u, v, ag, bg, sg)
# Routines for this puzzle ---------------------------------------------
def altitude_reduced(n, h, d, e):
"""Return the number of distinct n-tuples containing only the
values 0, d, and e that sum to h. Assume that all these
numbers are integers and that 0 <= d <= e.
"""
# Handle some impossible special cases
if n < 0 or h < 0:
return 0
# Handle some other simple cases with zero values
if n == 0:
return 0 if h else 1
if 0 == d == e: # all step values are zero
return 0 if h else 1
if 0 == d or d == e: # e is the only non-zero step value
# If possible, return # of tuples with proper # of e's, the rest 0's
return 0 if h % e else comb(n, h // e)
# Handle the main case 0 < d < e
# --Try to get the solution with the fewest possible non-zero days:
# x d's and y e's and the rest zeros: all solutions are given by
# x + t * bg, y - t * ag
solutions_info = byzantine_bball(d, e, h)
if not solutions_info:
return 0 # no way at all to get h from d, e
x, y, _, _, _, ag, bg, _ = solutions_info
# --Loop over all solutions with nonnegative x, y, small enough x + y
result = 0
while y >= 0 and x + y <= n: # at most n non-zero days
# Find multcoeff(x, y, n - x - y), in a faster way
if result == 0: # 1st time through loop: no prev coeff available
amultcoeff = multcoeff(x, y, n - x - y)
else: # use previous multinomial coefficient
amultcoeff = new_multcoeff(amultcoeff, x, y, n - x - y, ag, bg)
result += amultcoeff
x, y = x + bg, y - ag # x+y increases by bg-ag >= 0
return result
def altitudes(input_str=None):
# Get the input
if input_str is None:
input_str = input('Numbers N H1 H2 A B C? ')
# input_str = '100000 0 100000 0 1 2' # replace with prev line for input
n, h1, h2, a, b, c = map(int, input_str.strip().split())
# Reduce the number of parameters by normalizing the values
h_diff = h2 - h1 # net altitude change
a, b, c = sorted((a, b, c)) # a is now the smallest
h, d, e = h_diff - n * a, b - a, c - a # reduce a to zero
# Solve the reduced problem
print(altitude_reduced(n, h, d, e) % (10**9 + 7))
if __name__ == '__main__':
altitudes()
Here are some of my test routines for the main problem. These are suitable for pytest.
# Testing, some with pytest ---------------------------------------------------
import itertools # for testing
import collections # for testing
def brute(n, h, d, e):
"""Do alt_reduced with brute force."""
return sum(1 for v in itertools.product({0, d, e}, repeat=n)
if sum(v) == h)
def brute_count(n, d, e):
"""Count achieved heights with brute force."""
if n < 0:
return collections.Counter()
return collections.Counter(
sum(v) for v in itertools.product({0, d, e}, repeat=n)
)
def test_impossible():
assert altitude_reduced(0, 6, 1, 2) == 0
assert altitude_reduced(-1, 6, 1, 2) == 0
assert altitude_reduced(3, -1, 1, 2) == 0
def test_simple():
assert altitude_reduced(1, 0, 0, 0) == 1
assert altitude_reduced(1, 1, 0, 0) == 0
assert altitude_reduced(1, -1, 0, 0) == 0
assert altitude_reduced(1, 1, 0, 1) == 1
assert altitude_reduced(1, 1, 1, 1) == 1
assert altitude_reduced(1, 2, 0, 1) == 0
assert altitude_reduced(1, 2, 1, 1) == 0
assert altitude_reduced(2, 4, 0, 3) == 0
assert altitude_reduced(2, 4, 3, 3) == 0
assert altitude_reduced(2, 4, 0, 2) == 1
assert altitude_reduced(2, 4, 2, 2) == 1
assert altitude_reduced(3, 4, 0, 2) == 3
assert altitude_reduced(3, 4, 2, 2) == 3
assert altitude_reduced(4, 4, 0, 2) == 6
assert altitude_reduced(4, 4, 2, 2) == 6
assert altitude_reduced(2, 6, 0, 2) == 0
assert altitude_reduced(2, 6, 2, 2) == 0
def test_main():
N = 12
maxcnt = 0
for n in range(-1, N):
for d in range(N): # must have 0 <= d
for e in range(d, N): # must have d <= e
counts = brute_count(n, d, e)
for h, cnt in counts.items():
if cnt == 25653:
print(n, h, d, e, cnt)
maxcnt = max(maxcnt, cnt)
assert cnt == altitude_reduced(n, h, d, e)
print(maxcnt) # got 25653 for N = 12, (n, h, d, e) = (11, 11, 1, 2) etc.

Sage's (or Maxima's) solve gives a bad answer for diff(p, x) == 0?

I am using Sage to (within a script) solve a simple equation in two variables:
sage: x, y = var("x y")
sage: p = x*y + x/y + 1/x
sage: diff(p, x)
y + 1/y - 1/x^2
sage: diff(p, y)
x - x/y^2
sage: solve([diff(p,x)==0, diff(p,y)==0], [x,y])
[[x == 0, y == 0], [x == -1/2*sqrt(2), y == 1],
[x == 1/2*sqrt(2), y == 1], [x == -1/2*I*sqrt(2), y == -1],
[x == 1/2*I*sqrt(2), y == -1]]
For some reason, Sage returns a solution that isn't a solution at all, here [x == 0, y == 0] can easily be seen NOT to be an answer of [y + 1/y - 1/x^2 == 0, x - x/y^2 == 0].
Is this a bug? a known bug? or am I doing something wrong?
UPDATE: rephrased the title, and I am wondering, worst case, how can I substitute the solutions back in the system to manually check if the equations are verified?
PS: I would post this on AskSage, but it is currently down.
Well, looks like Maxima's solve function is returning the spurious solution [x = 0, y = 0]. I see that Maxima's to_poly_solve is better behaved here.
p : x*y + x/y + 1/x;
load (to_poly_solve);
[dpx, dpy] : [diff (p, x), diff (p, y)];
to_poly_solve ([dpx, dpy], [x, y]);
=> %union([x = -1/sqrt(2),y = 1],[x = 1/sqrt(2),y = 1],
[x = -%i/sqrt(2),y = -1],[x = %i/sqrt(2),y = -1])
for xy in args (%) do print (subst (xy, [dpx, dpy]));
=>
[0,0]
[0,0]
[0,0]
[0,0]
I don't know how to call to_poly_solve from Sage, although I'm pretty sure it's possible.
Hope this helps. Good luck & have fun.

Resources