solving equations and using values obtained in other calculations - SAGE - sage

the function solve() in SAGE returns symbolic values for the variables i solve the equations for. for e.g:
sage: s=solve(eqn,y)
sage: s
[y == -1/2*(sqrt(-596*x^8 - 168*x^7 - 67*x^6 + 240*x^5 + 144*x^4 - 60*x - 4) + 8*x^4 + 11*x^3 + 12*x^2)/(15*x + 1), y == 1/2*(sqrt(-596*x^8 - 168*x^7 - 67*x^6 + 240*x^5 + 144*x^4 - 60*x - 4) - 8*x^4 - 11*x^3 - 12*x^2)/(15*x + 1)]
My problem is that i need to use the values obtained for y in other calculations, but I cannot assign these values to any other variable. Could someone please help me with this?

(1) You should visit ask.sagemath.org, the Stack Overflow-like forum for Sage users, experts, and developers! </plug>
(2) If you want to use the values of a solve() call in something, then it's probably easiest to use the solution_dict flag:
sage: x,y = var("x, y")
sage: eqn = x**4+5*x*y+3*x-y==17
sage: solve(eqn,y)
[y == -(x^4 + 3*x - 17)/(5*x - 1)]
sage: solve(eqn,y,solution_dict=True)
[{y: -(x^4 + 3*x - 17)/(5*x - 1)}]
This option gives the solutions as a list of dictionaries instead of a list of equations. We can access the results like we would any other dictionary:
sage: sols = solve(eqn,y,solution_dict=True)
sage: sols[0][y]
-(x^4 + 3*x - 17)/(5*x - 1)
and then we can assign that to something else if we like:
sage: z = sols[0][y]
sage: z
-(x^4 + 3*x - 17)/(5*x - 1)
and substitute:
sage: eqn2 = y*(5*x-1)
sage: eqn2.subs(y=z)
-x^4 - 3*x + 17
et cetera. While IMHO the above is more convenient, you could also access the same results without solution_dict via .rhs():
sage: solve(eqn,y)[0].rhs()
-(x^4 + 3*x - 17)/(5*x - 1)

If you have unknown number of variables you can use **kwargs to pass data calculated with solve to next expressions. Here's example:
B_set is an list of variables and its filled in runtime so i dont know
names of variables and their quantity at the time of writing the code
solution = solve(system_of_equations, B_set)[0]
pretty_print(solution)
For example this gives me:
result of solving system of equations
I cant use this answer for further calculations so lets convert it to usable form
solution = {str(elem.lhs()): elem.rhs() for elem in solution}
Which gives us:
result converted to dictionary with string keys
Then we just pass this as **kwargs
approximation = approximation_function(**solution)
pretty_print(approximation)
And that converts this:
approximation without values from solution
Into this:
approximation with values from solution
Note: if you use dictionary output from solve() you still need to convert keys to string.

Related

sage math: simplify algebra expression with steps

Example:
simplify 2(3x+5)
step1: 2*3x + 2*5
step2: 6x + 2*5
solution: 6x + 10
I tried sage math: https://sagecell.sagemath.org/?q=ngzkdm
sage: x = SR.var('x')
sage: 2*(3*x+5)
6*z + 10
can any quide how this can be done
i need to show the steps. of course this a a simple case.
Searching the web for [ math software steps ] or [ math software show steps ] reveals results such as cymath, mathway, polymathlove, quickmath, symbolab, wolfram alpha, etc.
They seem to be mostly apps and websites; I could not locate
any free software for that task, though it may exist.
That is not SageMath's focus, but one could still give it a go.
Sage has "held expressions":
sage: x = SR.var('x')
sage: a = 3*x + 5
sage: b = SR(2)
sage: expr = a.mul(b, hold=True)
sage: expr
2*(3*x + 5)
One can get an expression's operator and operands.
sage: a.operator()
<function add_vararg at 0x...>
sage: a.operands()
[3*x, 5]
sage: expr.operator()
<function mul_vararg at 0x...>
sage: expr.operands()
[3*x + 5, 2]
The sum and product symbolic operators are:
sage: plus = sage.symbolic.operators.add_vararg
sage: times = sage.symbolic.operators.mul_vararg
sage: expr.operator() == times
True
sage: a.operator() == plus
True
So one could walk the expression tree and
expand any products of sums in it.
Here is a step by step expansion of the simple example
in the question, done by hand:
sage: x = SR.var('x')
sage: a = 3*x + 5
sage: b = SR(2)
sage: expr = a.mul(b, hold=True)
sage: expr
2*(3*x + 5)
sage: d, e = a.operands()
sage: d, e
(3*x, 5)
sage: print(f'{b}*{d} + {b}*{e}')
2*3*x + 2*5
sage: print(f'{b*d} + {b*e}')
6*x + 10
sage: print(b*a)
6*x + 10
One could write a function to
analyse the expression tree
detect all products one of whose factors is a sum
ask the user which expansion to perform
print the steps of the chosen expansion
repeat
It would involve a lot of trial and error to get it right.
Hopefully the hints above help a little.

How do you simplify the difference between functions of x in R with respect to a Calculus context?

First of all, this looks like a fair amount of Calculus, so I predict that it would get forwarded to Cross-Validated by someone who thinks that this is TL;DR. But I think this is a programming question, so here me out.
Imagine that I have the following functions in terms of x: f(x), g(x), h(x) ...
f(x) = 2x^2 + 4x - 30
g(x) = x^2 - x + 12
h(x) = f(x) - g(x) = (2x^2 + 4x - 30) - (x^2 - x + 12) = x^2 + 5*x - 42
Note: If I were to compute g(x) - f(x) here I would get a different polynomial, but I would get the same roots so it doesn't really matter because if I took the coefficients from g(x) - f(x), then polyroot() would return the same x-intercept intersection points as f(x) = g(x).
I am able to resolve h(x) = (2x^2 + 4x - 30) - (x^2 - x + 12), but I can't resolve it to x^2 + 5*x - 42 which is just a more simplified version of the same function of h(x). But I need it in this form to compute the intersections of these functions where I need the coefficients of the difference function. Then I would use the points of intersection to compute the difference integral over the greater function minus the smaller function over the range where the functions intersect, and this difference integral is simply the area between the functions.
So my goal is to compute the area between two intersecting functions.
My problem is that I want to automate the whole process, and I want to simply the h(x) difference function to 1*x^2 + 5*(x) - 42, where the coefficients of this polynomial function in increasing order are -42, 5, 1 in that order.
So let's just write the code:
fx <- function(x){2*x^2 + 4*x - 30}
gx <- function(x){1*x^2 - 1*x + 12}
hx <- function(x){fx - gx} # doesn't work because I can't pass it to curve(hx)
hx <- function(x){(2*x^2 + 4*x - 30) - (1*x^2 - 1*x + 12)} # works
but it is not in the form that I want.
> hx
function(x){(2*x^2 + 4*x - 30) - (1*x^2 - 1*x + 12)}
<bytecode: 0x000000001c0bfc10>
Errors:
> curve(hx)
Error in expression(fx) - expression(gx) :
non-numeric argument to binary operator
See this is why I need the coefficients.
> z <- polyroot(c(-42, 5, 1)) # polyroot functions give you the x-intercepts of a polynomial function.
> z
[1] 4.446222-0i -9.446222+0i
Of course I could just compute "x^2 + 5*x - 42" on pen and paper, but they say that programmers always want to find the most efficient algorithmic process with the least amount of work.
Now I need to see which function is greater than the other, over the given range. Two ways visually or incrementally. (This is for the Calculus II part.)
x = seq(from = -9.4, to = 4.4, by = 0.2)
fx_range = 2*x^2 + 4*x - 30
> table(fx_range >= gx_range)
FALSE
70
> table(gx_range >= fx_range)
TRUE
70
It looks like the g(x) function is greater than or equal to the f(x) function over the range of the intersection points. So should evalulate the integral of g(x) - f(x) according to calculus. I was just doing f(x) - g(x) earlier for the polyroot function.
Areabetween curves = (from -9.446222 to 4.446222) ∫[g(x) - f(x)]dx
= (from -9.446222 to 4.446222) ∫[(x^2 - x + 12) - (2*x^2 + 4*x - 30)]
gx_minus_fx = function(x){(x^2 - x + 12) - (2*x^2 + 4*x - 30)}
Area = integrate(gx_minus_fx, lower = -9.446222, upper = 4.446222)
Area
446.8736 with absolute error < 5e-12 # This is exactly what I wanted to compute!
Now let's graphically check if I was supposed to subtract g(x) - f(x):
> curve(fx, main = "Functions with their Intersection Points", xlab = "x", ylab = "Functions of x", from = -9.446222, to = 4.446222)
> curve(gx, col = "red", add = TRUE)
> legend("topright", c("f(x) = 2x^2 + 4x - 30", "g(x) = x^2 - x + 12"), fill = c("black", "red"))
Yeah, I did it right!
So again, what I would like help with is figuring out how I could simplify
h(x) = f(x) - g(x) to x^2 + 5*x - 42.
This appears to be an algebraic problem. I showed that I could do high-level Calculus 2 in R, and I would just like to know if there is a way that I can automate this whole process for the h(x) function.
Thank you!!!

Numerically stable evaluation of sqrt(x+a) - sqrt(x)

Is there an elegant way of numerically stable evaluating the following expression for the full parameter range x,a >= 0?
f(x,a) = sqrt(x+a) - sqrt(x)
Also is there any programming language or library that does provide this kind of function? If yes, under what name? I have no specific problem using the above expression right now, but encountered it many times in the past and always thought that this problem must have been solved before!
Yes, there is! Provided that at least one of x and a is positive, you can use:
f(x, a) = a / (sqrt(x + a) + sqrt(x))
which is perfectly numerically stable, but hardly worth a library function in its own right. Of course, when x = a = 0, the result should be 0.
Explanation: sqrt(x + a) - sqrt(x) is equal to (sqrt(x + a) - sqrt(x)) * (sqrt(x + a) + sqrt(x)) / (sqrt(x + a) + sqrt(x)). Now multiply the first two terms to get sqrt(x+a)^2 - sqrt(x)^2, which simplifies to a.
Here's an example demonstrating the stability: the troublesome case for the original expression is where x + a and x are very close in value (or equivalently when a is much smaller in magnitude than x). For example, if x = 1 and a is small, we know from a Taylor expansion around 1 that sqrt(1 + a) should be 1 + a/2 - a^2/8 + O(a^3), so sqrt(1 + a) - sqrt(1) should be close to a/2 - a^2/8. Let's try that for a particular choice of small a. Here's the original function (written in Python, in this case, but you can treat it as pseudocode):
def f(x, a):
return sqrt(x + a) - sqrt(x)
and here's the stable version:
def g(x, a):
if a == 0:
return 0.0
else:
return a / ((sqrt(x + a) + sqrt(x))
Now let's see what we get with x = 1 and a = 2e-10:
>>> a = 2e-10
>>> f(1, a)
1.000000082740371e-10
>>> g(1, a)
9.999999999500001e-11
The value we should have got is (up to machine accuracy): a/2 - a^2/8 - for this particular a, the cubic and higher order terms are insignificant in the context of IEEE 754 double-precision floats, which only provide around 16 decimal digits of precision. Let's compute that value for comparison:
>>> a/2 - a**2/8
9.999999999500001e-11

Can I substitute using a symbolic equation in Sage?

I am using the following map in Sage:
f = lambda x: sgn(x)*sgn(x);
which evaluates to f(x) = 0 for x=0 and f(x)=1 for x!=0;
In symbolic results, sgn(x)^2, sgn(x)^4 and sgn(x)^8, etc. are being treated as unequal, even though they are equal for all values of x. Is there a way that I can substitute something like:
sgn(x)^2 == sgn(x)^4 == sgn(x)^8
for all occurrences of these relations, and for all symbolic values of x?
I could create a new substitution rule for every symbol, e.g.
result.subs(sgn(c)^2 == sgn(c)^4).subs(sgn(d)^2 == sgn(d)^4)...
and so on, but that seems hard to control.
This is perhaps a dumb question for me to ask... is the nature of your result one that you could just factor?
sage: f(x) = sgn(x)^2
sage: f
x |--> sgn(x)^2
sage: Z = (1+f)^3
sage: Z = Z.expand()
sage: Z
x |--> sgn(x)^6 + 3*sgn(x)^4 + 3*sgn(x)^2 + 1
sage: Z.factor()
x |--> (sgn(x)^2 + 1)^3
In which case it makes your question moot, hopefully:
sage: Z.subs(sgn(x)^2==x)
x |--> (x + 1)^3
not that that is your subs, just as an example.
Apparently Sage allows for the use of wildcards in substitution (here's the example that tipped me off). So I did something like:
var('a,b,c,d,e,f');
w = SR.wild(0);
result = f(a,b,c,d,e,f).subs(sgn(w)^4 == sgn(w)^2).subs(sgn(w)^8 == sgn(w)^2);
And it worked! Much easier.

Simplify expression

I have an expressions like:
a*b*c + d*e + f - g*h*h + i*a
In other words: terms can be either added or subtracted, and each term is a product of some of the symbols.
Is there a way to come up with a minimal/simpler expression, basically the reverse of expand? I tried simplify and factor but I cannot get them to work. For example:
a**4 - 4*a**3*b + 6*a**2*b**2 - 4*a*b**3 - a + b**4
should turn into:
(a - b)**4 - a
but it stays unchanged when using the said commands.
PS: If this is something what SymPy simply cannot do, could you please suggest an alternative which does this?
See sympy factor simple relationship. SymPy's factor only knows how to factor the entire expression, but if you know the term you want to rewrite things in terms of, you can use a trick with subs, like:
>>> expr = a**4 - 4*a**3*b + 6*a**2*b**2 - 4*a*b**3 - a + b**4
>>> expr.subs(a, x + b).expand()
-b + x**4 - x
>>> expr.subs(a, x + b).expand().subs(x, a - b)
-a + (a - b)**4
Basically, let x = a - b, so that a = x + b. Then replace a with x + b, expand things out, and replace it back.
For your more complicated example, SymPy is actually smart enough to replace a*b in an expression correctly:
>>> expr = (a*b - c*d)**2 - a
>>> expr = expr.expand()
>>> expr
a**2*b**2 - 2*a*b*c*d - a + c**2*d**2
>>> expr.subs(a*b, x + c*d)
-a + c**2*d**2 - 2*c*d*(c*d + x) + (c*d + x)**2
>>> expr.subs(a*b, x + c*d).expand()
-a + x**2
>>> expr.subs(a*b, x + c*d).expand().subs(x, a*b - c*d)
-a + (a*b - c*d)**2
Another possible approach to this problem would be to try using factor on subsets of the terms in an expression (itertools.combinations could be useful here). For instance, to try factoring all combinations of all terms but one from your original expression:
>>> args = Add.make_args(expr)
>>> for comb in combinations(args, len(args) - 1):
... print(factor(Add(*comb)) + Add(*(set(args) - set(comb))))
...
a**4 - 4*a**3*b + 6*a**2*b**2 - 4*a*b**3 - a + b**4
a**4 - 4*a**3*b + 6*a**2*b**2 - 4*a*b**3 - a + b**4
a**4 - 4*a**3*b + 6*a**2*b**2 - 4*a*b**3 - a + b**4
a**4 - 4*a**3*b + 6*a**2*b**2 - 4*a*b**3 - a + b**4
-a + (a - b)**4
a*(a**3 - 4*a**2*b + 6*a*b**2 - 4*b**3 - 1) + b**4
You could check not isinstance(factored_expr, Add) to filter out the ones that aren't factored.
If you know the function in advance, then you can use more powerful software packages such as Maple to reduce the expression before putting it into your computer code. There is a optimization package in Maple, which reduces the expression into sub-expressions such that it takes advantage of repeated operations in the expression. Also you can factorize very complicated expressions in a much reliable way.
In addition such software also can create programming code as output, which you can directly paste in your program. If you do not have access to Maple or Mathematica software, you can also use a free (but powerful) software called maxima. http://maxima.sourceforge.net/

Resources