sympy: rearrange equation in terms of a variable - sympy

How can I make sympy keep the variable (and equals sign) after solving for a variable?
a,b = symbols('a b')
res = solveset( Eq(a+3,b), a)
print(res) #FiniteSetb-3
I want res to still be an equation, printing a = b - 3, but the above returns FiniteSetb-3.
Creating a new equation from the result does not work, implying that a is still in there(?).
res = Eq(a, solveset( Eq(a+3,b), a))
print(res) #False
Thanks

Related

Simplify a repetitive pattern using monads

I'm actually not sure this is doable with monads or that it should be done with them and I'm looking for a solution rather than solve it with monads if monads are not the solution.
Let's say I have the following code (simplified but the idea is here):
module IM = Map.Make (Int)
let f k v m =
if IM.mem k m then (m, true)
else (IM.add k v m, false)
let a =
let m = IM.empty in
let m, res = f 0 "Zero" m in
if res then
let m, res = f 1 "One" m in
if res then f 2 "Two" m else (m, res)
else (m, res)
I'm repeating multiple times:
let value, boolean = function application to value and other values in
if boolean then another function application to the new value and other values (not the same as the first one)
else the result
This means that these functions don't necessarily have the same type but they all return a a IM.t * bool (a being the same type for every function)
I wondered if it was possible to create an inline operator that would allow me to do it.
I tried something like:
module EqMonad = struct
let ( let* ) (t, res) f2 = if res then f2 t else (t, false)
let return t = t
end
But it'll obviously not work because f2 takes more than one argument but needs to receive t as its last argument.
I guess I could summarize my problem like this:
Is it possible to have monads wrapping variadic functions?
Your solution works (with return corrected to be the monadic return) and is a restricted version of the error monad:
let return x = x, true
let a =
let m = IM.empty in
let* m = f 0 "Zero" m in
let* m = f 1 "One" m in
let* m = f 2 "Two" m in
return m
However, since the control flow never depends on the value of m, this is a sign that it might simpler to use a regular function:
let rec add_first_fresh m l = match l with
| [] -> None
| (k,v):: q ->
if IM.mem k m then add_first_fresh m q
else Some (IM.add k v m)
let a = add_first_fresh IM.empty
[0, "Zero";
1, "One";
2, "Two"
]

Rewrite sympy equations to 0 right hand side

Does anyone know how I can rewrite all sympy equations to have zero right hand side?
I have a list of equations, each a string, that I would like to feed into "linear_eq_to_matrix".
My list looks somehting like
eqs = ['x+y =2', 'x = y']
In order to use "linear_eq_to_matrix", I need 2 things:
Reformulate the equations to have zero right hand side.
Change the string format of the equations. This can be done with sympy.sympify.
My code needs to look something like
eqns = [x + y - 2,
x - y]
A, b = linear_eq_to_matrix(eqns, [x, y])
I am not sure how to perform 1) above in order to get "eqns".
edit: I found out how to transform a string to a sympy expression.
I think I solved it:
eqsString = ['x+y =2', 'x = y']
eqs = [sym.Eq(*map(sym.sympify, eq.split('='))) for eq in eqsString]
x, y = symbols('x, y')
A, b = linear_eq_to_matrix(eqs, [x, y])
A, b
Which gives
(Matrix([
[1, 1],
[1, -1]]), Matrix([
[2],
[0]]))

How to update a variable in multiple lists (Python 3.6)

I am having a scope issue, and I know how I would solve this in Java, but Python is giving me some issues. Say I have a code as follows:
a = 1
b = 2
c = 3
list1 = [a,b,c]
list2 = [b,c]
b += 1
print list1
print list2
This code does not change the value inside the lists, and there is an easy workaround for the simple example I've given, but the code I am trying to write has 10+ lists that all have different meanings and are used in different ways, but need to communicate with each other and have all the same values for a,b,c. I need to be able to change the variable a,b,c and have all the lists update as well, is there any other way besides writing out the update for each list?
You cannot store the integers by reference, such that incrementing the value in one place causes all other values to be updated. This is because ints are immutable, so changing their value causes a reference change.
>>> a = 5
>>> b = 1
>>> x = [a, b]
>>> id(b)
140508116572264
>>> id(x[1])
140508116572264
>>> b += 1
>>> id(b)
140508116572240
You can see the id of b changes after the increment, so the "b" in the loop and the "b" outside aren't the same.
What you can do, is define a wrapper class for your ints.
class MyInteger:
def __init__(self, value):
self.value = value
Now, build your lists with your MyIntegers:
a = MyInteger(1)
b = MyInteger(2)
c = MyInteger(3)
list1 = [a, b, c]
list2 = [b, c]
Now, when you increment the value of b, you can see the changes are reflected in the lists.
print([x.value for x in list1])
b.value += 1
print([x.value for x in list1])
This prints:
[1, 2, 3]
[1, 3, 3]

How to concat the list of sequential strings including partially same string

For example, this is the list of strings.
a = 'abcdefg'
b = 'efghij'
c = 'ij234235'
d = 'def'
e = 'efg'
f = 'fg'
str_list = [a, b, c, d, e, f]
I expect that the result would be ['abcdefghij234235', 'defg']
The concatenation should be executed sequentially and the common strings are not fixed
How can I get the result?
Th solution using numpy.intersect1d and itertools.chain.from_iterable() functions:
import numpy as np, itertools
str_list = [list(a), list(b), list(c), list(d), list(e), list(f)]
result = []
for k,a in enumerate(str_list):
if len(result) == 0:
result.append((str_list[k],))
if k+1 == len(str_list): break
common = ''.join(np.intersect1d(str_list[k],str_list[k+1]))
if common and common[-1] == ''.join(str_list[k])[-1] and common[0] in ''.join(str_list[k+1])[0]:
result[-1] += (str_list[k+1][len(common):],)
else:
result.append((str_list[k+1],))
result = [''.join(list(itertools.chain.from_iterable(t))) for t in result]
print(result)
The output:
['abcdefghij234235', 'defg']

Ocaml : function that two integers and returns the list of all integers in the range

This function takes two integers and returns the list of all integers in the range [a,b]
This is the solution that I wrote.
let rec range_rec l a b =
if (a=b) then l#[b]
else range_rec (l#[a], a+1, b);;
let range a b = range_rec [] a b;;
I'm hitting an error "Error: This expression has type int list * int * int but an expression was expected of type int". Can someone throw some light on why am I getting this error?
Thanks.
It should look like this:
let rec range_rec l a b =
if a = b then l # [b]
else range_rec (l # [a]) (a + 1) b;;
let range a b = range_rec [] a b;;
What I've done:
Changed loop to range_rec
Changed (l#[a], a+1, b) to (l # [a]) (a + 1) b. The first is a triplet and the second is 3 arguments to a curried function.
Notice that if (a = b) then can be written as if a = b then.
Last, the function can be made more efficient by using :: instead of # by looping "backwards". For example like gasche have shown.
The l # [elem] operation is terrible from a performance perspective : as a # b is linear in the length of a, adding an element to the end of list is linear in the length of the list, making your whole range_rec definition quadratic in |b-a|. The way to go is to change your code so that you can use the constant-time elem::l operation instead.
let rec range a b =
if a > b then []
else a :: range (a + 1) b
You may make additional optimizations such as making it tail-recursive, but at least the complexity of this solution is right.
To improve on the solution already suggested by gasche, this can be made tail-recursive.
let int_range a b =
let rec int_range_rec l a b =
if a > b then l
else int_range_rec (b :: l) a (b - 1)
in (int_range_rec [] a b);;