Simultaneous Equations with given conditions - python

to start off I have already solved this problem so it's not a big deal, I'm just asking to satisfy my own curiosity. The question is how to solve a series of simultaneous equations given a set of constraints. The equations are:
tau = 62.4*d*0.0007
A = (b + 1.5*d)*d
P = b + 2*d*sqrt(1 + 1.5**2)
R = A/P
Q = (1.486/0.03)*A*(R**(2.0/3.0))*(0.0007**0.5)
and the conditions are:
tau <= 0.29, Q = 10000 +- say 3, and minimize b
As I mentioned I was already able to come up with a solution using a series of nested loops:
b = linspace(320, 330, 1000)
d = linspace(0.1, 6.6392, 1000)
ansQ = []
ansv = []
anstau = []
i_index = []
j_index = []
for i in range(len(b)):
for j in range(len(d)):
tau = 62.4*d[j]*0.0007
A = (b[i] + 1.5*d[j])*d[j]
P = b[i] + 2*d[j]*sqrt(1 + 1.5**2)
R = A/P
Q = (1.486/0.03)*A*(R**(2.0/3.0))*(0.0007**0.5)
if Q >= 10000 and tau <= 0.29:
ansQ.append(Q)
ansv.append(Q/A)
anstau.append(tau)
i_index.append(i)
j_index.append(j)
This takes a while, and there is something in the back of my head saying that there must be an easier/more elegant solution to this problem. Thanks (Linux Mint 13, Python 2.7.x, scipy 0.11.0)

You seem to only have two degrees of freedom here---you can rewrite everything in terms of b and d or b and tau or (pick your two favorites). Your constraint on tau implies directly a constraint on d, and you can use your constraint on Q to imply a constraint on b.
And it doesn't look (to me at least, I still haven't finished my coffee) that your code is doing anything other than plotting some two dimensional functions over a grid you've defined--NOT solving a system of equations. I normally understand "solving" to involve setting something equal to something else, and writing one variable as a function of another variable.
It does appear you've only posted a snippet, though, so I'll assume you do something else with your data down stream.
Ok, I see. I think this isn't really a minimization problem, it's a plotting problem. The first thing I'd do is see what ranges are implied for b and d from your constraints on tau, and then use that to derive a constraint on d. Then you can mesh those points with meshgrid (as you mentioned below) and run over all combinations.
Since you're applying the constraint before you apply the mesh (as opposed to after, as in your code), you'll only be sampling the parameter space that you're interested in. In your code you generate a bunch of junk you're not interested in, and pick out the gems. If you apply your constraints first, you'll only be left with gems!
I'd define my functions like:
P = lambda b, d: b + 2*d*np.sqrt(1 + 1.5**2)
which works like
>>> import numpy as np
>>> P = lambda b, d: b + 2*d*np.sqrt(1 + 1.5**2)
>>> P(1,2)
8.2111025509279791
Then you can write another function to serve up b and d for you, so you can do something like:
def get_func_vals(b, d):
pvals.append(P(b,d))
or, better yet, store b and d as tuples in a function that doesn't return but yields:
pvals = [P(b,d) for (b,d) in thing_that_yields_b_and_d_tuples]
I didn't test this last line of code, and I always screw up these parenthesis, but I think it's right.

Related

if condition using sympy equation solver/ sympy very slow

I want to solve this equation witht the following parameters:
gamma = 0.1
F = 0.5
w = 0
A = symbols('A')
a = 1 + w**4 -w**2 + 4*(gamma**2)*w**2
b = 1 - w**2
sol = solve(a*A**2 + (9/16)*A**6 + (3/2)*b*A**4 -F**2)
list_A = []
for i in range(len(sol)):
if(type( solutions[i] )==float ):
print(sol[i])
list_A = sol[i]
However, as supposed, I am getting some real and complex values, and I want to remove the complex ones and only keep the floats. But this condition I implemented is not valid due to the type of sol[i] is either sympy.core.add.Add for complex or sympy.core.numbers.Float for floats.
My question is, how can I modify my condition so that it works for getting only the float values?
In addition, is there a way to speed it up? it is very slow if I put it in a loop for many values of omega.
this is my first time working with sympy
When it is able to validate solutions relative to assumptions on symbols, it will; so if you tell SymPy that A is real then -- if it can verify the solutions -- it will only show the real ones:
>>> A = symbols('A',real=True)
>>> sol = solve(a*A**2 + (9/16)*A**6 + (3/2)*b*A**4 -F**2)
>>> sol
[-0.437286658108243, 0.437286658108243]

(Python) Solving an equation with an unknown number, find that number with an equation

I making a code (for fun and practice) to balance chemical equations. I want to try and balance N + A so it = Z
N = 2
A = 2
Z = 6
if N + A != Z:
print('X')
balancer = ???
The balancer should be 3 so that if I make an equation e.g (balancer x N) + A = Z it would be true. How would I make the balancer be three with out directly inputing it.
Thanks :)
You can to do the basic algebra by hand:
(balancer * N) + A = Z
(balancer * N) = Z - A # subtract A from both sides
balancer = (Z - A) / N # divide both sides by N
… and then it's trivial to turn that into code—that last line actually is the valid Python code, with no changes.
Or, if you want Python to do this for you, just by specifying (balancer * N) + A = Z as an equation… Python doesn't have anything built in to do that, but there are algebra libraries like SymPy to do.
You'll really want to work through the whole tutorial, but briefly…
First, you have to first tell it that your variables are variables:
>>> from sympy import symbols, solve, Eq
>>> A, N, Z, balancer = symbols('A N Z balancer')
Then, build an equation. The left side can just be (balancer * N) + a and Z, but you can't just put an = or == between them; you have to use Eq:
>>> equation = Eq((balancer * N) + A, Z)
Now you can substitute in the values for your variables:
>>> equation.subs(dict(N=2, A=2, Z=6))
Eq(2*balancer + 2, 6)
And finally, solve for valid solutions:
>>> solve(equation.subs(dict(N=2, A=2, Z=6))
[2]
Or, if you'd prefer to solve it algebraically and then substitute, instead of the other way around:
>>> solve(equation, 'balancer')
[(-A + Z)/N]
>>> [s.subs(dict(N=2, A=2, Z=6)) for s in solve(equation, 'balancer')]
[2]
You need a condition to test whether the left side, N + A, is greater than or less than than the right side, Z. You could use (N + A) - Z, yielding -2, which tells you that you're missing two atoms. From there you'll need to write some logic to determine which atoms it is that you're missing.
With simple variables pointing to integers, there's no way to intuitively predict which atoms you'll need to add. Presumably you're working from an equation, though, so I'd suggest you look into a regex solution to that parse that. Something like this:
>>> import re
>>> m = re.findall('(\d*)((?:[A-Z][a-z]?\d*)+)', '2CH4 + O2')
>>> for n, molecule in m:
... print(n or 1, molecule)
...
2 CH4
1 O2
And then parse the atoms similarly from there.

Solving a system of Quadratic Equations

I am doing a cryptography program in Python.
It consists in reading a random phrase, like HELLO. Then it assigns it's respective ASCII values like:
H = 72, E = 79.
Then, using Pythagoras' Theorem, it creates two numbers C1 and C2, like this:
C1 = sqrt(A^2 + (A+B)^2);
C2 = sqrt(B^2 + (A+B)^2)
where, in this case A = H and B = E. That would be the encryption part, but I am having problems solving the system, which will act as the decryptor.
How can I solve this system using python?
C1 = sqrt(A^2 + (A+B)^2);
C2 = sqrt(B^2 + (A+B)^2);
Of course only C1 and C2 are known.
Do I need a new module? Which one?
If you're only talking about using the two characters for encryption, that's not a good idea.
That only gives 65,536 possible variants (two ASCII characters was mentioned but I'll assume a full 8-bit octet, so 256 multiplied by 256), it's easy enough to brute-force this. First, we know that every value of A and B generates a unique pair C1/C2, as per the following program which generates no duplicates:
lookup = {}
for a in range(256):
for b in range(256):
c1s = a*a + (a+b)*(a+b)
c2s = b*b + (a+b)*(a+b)
lkey = "%d:%d"%(c1s,c2s)
lookup[lkey] = 1
print(len(lookup)) # gives 65536 (256 squared)
Also, since both A and B are integers, so too will be C12 and C22.
So the first step is to work out the squares of the values you're given (since sqrt is a potentially expensive operation), taking into account the possibility of floating point inaccuracies:
c1s = int(c1 * c1 + 0.1)
c2s = int(c2 * c2 + 0.1)
Then, simply brute-force the solution:
for a in range(256):
for b in range(256):
if c1s != a*a + (a+b)*(a+b):
continue
if c2s == b*b + (a+b)*(a+b):
print(a,b)
sys.exit(0)
print("No solution")
On my machine, searching for the slowest solution (both a and b set to 255), it takes just a smidgeon over six hundredths of a second.
But you should keep in mind that, if an attacker has the C1/C2 values, they too can get the results that fast. And, even if they don't have it, the fact that there are only 64K possibilities means that they can try every possible value in a little over one and a quarter hours. So I wouldn't be using this method to store anything that's valuable for very long :-)

Find root of a function in a given interval

I am trying to find the root of a function between by [0, pi/2], all algorithms in scipy have this condition : f(a) and f(b) must have opposite signs.
In my case f(0)*f(pi/2) > 0 is there any solution, I precise I don't need solution outside [0, pi/2].
The function:
def dG(thetaf,psi,gamma) :
return 0.35*((cos(psi))**2)*(2*sin(3*thetaf/2+2*gamma)+(1+4*sin(gamma)**2)*sin(thetaf/2)-‌​sin(3*thetaf/2))+(sin(psi)**2)*sin(thetaf/2)
Based on the comments and on #Mike Graham's answer, you can do something that will check where the change of signs are. Given y = dG(x, psi, gamma):
x[y[:-1]*y[1:] < 0]
will return the positions where you had a change of sign. You can an iterative process to find the roots numerically up to the error tolerance that you need:
import numpy as np
from numpy import sin, cos
def find_roots(f, a, b, args=[], errTOL=1e-6):
err = 1.e6
x = np.linspace(a, b, 100)
while True:
y = f(x, *args)
pos = y[:-1]*y[1:] < 0
if not np.any(pos):
print('No roots in this interval')
return roots
err = np.abs(y[pos]).max()
if err <= errTOL:
roots = 0.5*x[:-1][pos] + 0.5*x[1:][pos]
return roots
inf_sup = zip(x[:-1][pos], x[1:][pos])
x = np.hstack([np.linspace(inf, sup, 10) for inf, sup in inf_sup])
There is a root only if, between a and b, there are values with different signs. If this happens there are almost certainly going to be multiple roots. Which one of those do you want to find?
You're going to have to take what you know about f to figure out how to deal with this. If you know there is exactly one root, you can just find the local minimumn. If you know there are two, you can find the minimum and use that's coordinate c to find one of the two roots (one between a and c, the other between c and what used to be called b).
You need to know what you're looking for to be able to find it.

Solving a difficult (polynomial?) equation in Python

I am new to programming (Python is my first language) but I love to design algorithms. I am currently working on a system of equations (integers) and I cannot find any references to solving my particular problem.
Let me explain.
I have an equation (a test, if you will):
raw_input == [(90*x + a) * y] + z
where a is some constant.
My problem is, the variable z counts in a manner very similar to a Fibonacci sequence, and the variable x is the step of z. So what I mean by this (for a Fibonacci sequence) is that at the first term of the z sequence, x = 0, and at the second term of the z sequence, x = 1. I need to solve for y.
The exact process for determining z is as follows
where c and d are constants:
#at x = 0
temp = (c+(90*x)) * (d+(90*x))
temp/90 = z(0)
#at x = 1
new_temp = (c+(90*x)) * (d + (90*x))
new_temp/90 = z(1)
#for all the rest of the values of z (and x), use:
j = z(# x=1) - z(# x=0)
k = j + 180
l = z(# x=1) + k
print "z(# x=1) - z(# x=0) = j"
print "j + 180 = k"
print "k + z(1) = l"
repeat until z > raw_input
this creates the spread of z values by the relation:
j = z(# x=n) - z(# x=n-1)
k = j + 180
l = k + z(# x = n)
I need to scan through (skip) the values of z < x to test for the condition of a whole-number solution for y.
Does this seem possible?
It seems your best approach would be to recast the given equation as a recurrence relation and then either define a recursive function to determine the values you desire to compute or find the closed form solution to the relation. For more information on recurrence relations see:
Any decent book on Combinatorics
Wikipedia: Recurrence relation. Particularly, the sections:
2.1: Linear homogeneous recurrence relations with constant coefficients
2.2: Rational generating function
3.1: Solving recurrence relations, General Methods
Though the general methods for solving recurrence relations are reasonably able, the most powerful technique is the z-transform: 3.3: Solving with z-transforms
3.5: Solving non-homogeneous recurrence relations. The techniques and discussion in the rest of the article are mostly suited for pure applications, but may occasionally find practical uses as well.
WolframMathWorld: Recurrence equation
Finally, in my experience, such problems are best tackled with mathematical numerical analysis software such as MatLab, Octave,or Mathematica. At the very least, with these you have a platform which enables rapid deployment and testing.
All I've done is translate your psuedo-code into Python. Maybe it can be of some help. Perhaps you should have a look at the Python tutorial if you haven't already.
# python 2.7
# raw_input returns string - convert to int
upper_bound = int(raw_input('Upper bound: '))
def z(x):
'A function to calculate z from x.'
# c and d are constants
c = 5
d = 2
# integer division here
return (c + 90*x)*(d + 90*x)/90
# the value of z_0
z0 = z_x = z(0)
# a list to hold the z values z_0, z_1, ...
# the list includes z_0 (when x = 0)
zs = [z0]
x = 1
while z_x < upper_bound:
z_x = z(x)
zs.append(z_x)
j = zs[x] - zs[x - 1]
k = j + 180
l = zs[x] + k
print j, k, l
x += 1

Categories

Resources