I have a dict made of N integer values like this:
units = {'trooper':2, 'tank':10, 'helicopter':12}
And I also have a target value... say 120.
I am trying to find all possible results of the equation:
a*units['trooper'] + b*units['tank'] + c*units['helicopter'] = 120
So the result would look something like:
60*trooper
55*trooper + 1*tank
54*trooper + 1*helicopter
And so on with all possible combinations of the N keys in the dict...
How can I go about building this ?
Searching for solutions to these kinds of problems is easiest if you know what they are called. Google for Diophantine equations.
In the Python world, you can use the Sympy package which includes a Diophantine equation solver. That package makes short work of your problem:
from sympy import symbols
from sympy.solvers.diophantine import diop_solve
trooper, tank, helicopter = symbols('trooper tank helicopter', integer=True)
print diop_solve(2*trooper + 10*tank + 12*helicopter - 120)
It outputs:
(5*t - trooper + 60, -6*t + trooper - 60, trooper)
You can also search for "ways to make change" which is another way of expressing the problem. A related problem is called called The Knapsack Problem and it is famously difficult to solve. The math behind solving general systems of linear Diophantine equations is a bit involved. Here are some resources:
http://www.math.udel.edu/~lazebnik/papers/dior1.pdf
http://www.dcc.fc.up.pt/~apt/onlinepapers/epia97_final.pdf
https://en.wikipedia.org/wiki/Diophantine_equation#System_of_linear_Diophantine_equations
http://www.math.utah.edu/~carlson/hsp2004/PythonShortCourse.pdf
Something like this would work for small values of target value:
units = {'trooper':2, 'tank':10, 'helicopter':12}
total = 120
for i in range(int(total/units['helicopter'])):
for j in range(int(total/units['tank'])):
if (total-units['helicopter']*i-units['tank']*j)%2==0 and (total-units['helicopter']*i-units['tank']*j)>0:
print ((total-units['helicopter']*i-units['tank']*j)/2,j,i)
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Let's say I have an equation:
2x + 6 = 12
With algebra we can see that x = 3. How can I make a program in Python that can solve for x? I'm new to programming, and I looked at eval() and exec() but I can't figure out how to make them do what I want. I do not want to use external libraries (e.g. SAGE), I want to do this in just plain Python.
How about SymPy? Their solver looks like what you need. Have a look at their source code if you want to build the library yourself…
There are two ways to approach this problem: numerically and symbolically.
To solve it numerically, you have to first encode it as a "runnable" function - stick a value in, get a value out. For example,
def my_function(x):
return 2*x + 6
It is quite possible to parse a string to automatically create such a function; say you parse 2x + 6 into a list, [6, 2] (where the list index corresponds to the power of x - so 6*x^0 + 2*x^1). Then:
def makePoly(arr):
def fn(x):
return sum(c*x**p for p,c in enumerate(arr))
return fn
my_func = makePoly([6, 2])
my_func(3) # returns 12
You then need another function which repeatedly plugs an x-value into your function, looks at the difference between the result and what it wants to find, and tweaks its x-value to (hopefully) minimize the difference.
def dx(fn, x, delta=0.001):
return (fn(x+delta) - fn(x))/delta
def solve(fn, value, x=0.5, maxtries=1000, maxerr=0.00001):
for tries in xrange(maxtries):
err = fn(x) - value
if abs(err) < maxerr:
return x
slope = dx(fn, x)
x -= err/slope
raise ValueError('no solution found')
There are lots of potential problems here - finding a good starting x-value, assuming that the function actually has a solution (ie there are no real-valued answers to x^2 + 2 = 0), hitting the limits of computational accuracy, etc. But in this case, the error minimization function is suitable and we get a good result:
solve(my_func, 16) # returns (x =) 5.000000000000496
Note that this solution is not absolutely, exactly correct. If you need it to be perfect, or if you want to try solving families of equations analytically, you have to turn to a more complicated beast: a symbolic solver.
A symbolic solver, like Mathematica or Maple, is an expert system with a lot of built-in rules ("knowledge") about algebra, calculus, etc; it "knows" that the derivative of sin is cos, that the derivative of kx^p is kpx^(p-1), and so on. When you give it an equation, it tries to find a path, a set of rule-applications, from where it is (the equation) to where you want to be (the simplest possible form of the equation, which is hopefully the solution).
Your example equation is quite simple; a symbolic solution might look like:
=> LHS([6, 2]) RHS([16])
# rule: pull all coefficients into LHS
LHS, RHS = [lh-rh for lh,rh in izip_longest(LHS, RHS, 0)], [0]
=> LHS([-10,2]) RHS([0])
# rule: solve first-degree poly
if RHS==[0] and len(LHS)==2:
LHS, RHS = [0,1], [-LHS[0]/LHS[1]]
=> LHS([0,1]) RHS([5])
and there is your solution: x = 5.
I hope this gives the flavor of the idea; the details of implementation (finding a good, complete set of rules and deciding when each rule should be applied) can easily consume many man-years of effort.
Python may be good, but it isn't God...
There are a few different ways to solve equations. SymPy has already been mentioned, if you're looking for analytic solutions.
If you're happy to just have a numerical solution, Numpy has a few routines that can help. If you're just interested in solutions to polynomials, numpy.roots will work. Specifically for the case you mentioned:
>>> import numpy
>>> numpy.roots([2,-6])
array([3.0])
For more complicated expressions, have a look at scipy.fsolve.
Either way, you can't escape using a library.
If you only want to solve the extremely limited set of equations mx + c = y for positive integer m, c, y, then this will do:
import re
def solve_linear_equation ( equ ):
"""
Given an input string of the format "3x+2=6", solves for x.
The format must be as shown - no whitespace, no decimal numbers,
no negative numbers.
"""
match = re.match(r"(\d+)x\+(\d+)=(\d+)", equ)
m, c, y = match.groups()
m, c, y = float(m), float(c), float(y) # Convert from strings to numbers
x = (y-c)/m
print ("x = %f" % x)
Some tests:
>>> solve_linear_equation("2x+4=12")
x = 4.000000
>>> solve_linear_equation("123x+456=789")
x = 2.707317
>>>
If you want to recognise and solve arbitrary equations, like sin(x) + e^(i*pi*x) = 1, then you will need to implement some kind of symbolic maths engine, similar to maxima, Mathematica, MATLAB's solve() or Symbolic Toolbox, etc. As a novice, this is beyond your ken.
Use a different tool. Something like Wolfram Alpha, Maple, R, Octave, Matlab or any other algebra software package.
As a beginner you should probably not attempt to solve such a non-trivial problem.
I am trying to solve simple algebraic parametrized equation sqrt(x)=sqrt(a)+1 with SymPy command solveset:
x, a = symbols("x a")
solveset(Eq(sqrt(x), sqrt(a)+1), x)
It returns as part of answer (conditional set) two solutions: 2*sqrt(a)+a+1 and -2*sqrt(a)+a+1. I can't understand how we can obtain the second one with minus sign from our equation!
Command solve in the same time gives us only solution (sqrt(a) + 1)**2, which is correct in my opinion.
What happens with solveset, any ideas?
The issue is to do with the sets you are solving over. Specifically, solveset defaults to a complex domain, resulting in extraneous solutions due to the complex square root. But by explicitly specifying a real domain and defining a and x to both be positive (as we're just dealing with reals, so can't have a or x negative), the desired solution can be extracted:
x, a = symbols('x a', positive=True)
solveset(Eq(sqrt(x), sqrt(a) + 1), x, domain=S.Reals).as_relational(x).expand()
# x = 2⋅√a + a + 1
The method that solveset uses gives two roots to consider but checksol is not able to show that the 2nd solution is not generally valid so to be safe, it returns both and shows you the condition which must be checked. If you substitute a value in for a you will obtain a set with the single concrete answer.
I have an equation and I need to solve it for a fraction.
I have more complex fomulas to solve but here is a minimal example: take the following simple function Y = X*a.
I want to solve for Y/X, so I expect Y/X =a.
Here is the code, it produces an empty set of answers
from sympy import *
X,Y,a = symbols('X Y a')
testEq = Eq(Y,X*a)
solve(testEq,Y/X)
I guess I'm misunderstanding something, any help appreciated!
The solve function can solve for sub-expressions provided they appear "as is" in the equation being solved. For example, in the following code, solve returns an empty solution for testEq but it returns the correct solution for testEq2 which is the same equation rearranged in terms of Y/X.
from sympy import *
X,Y,a = symbols('X Y a')
testEq = Eq(Y,X*a)
solve(testEq,Y/X)
testEq2 = Eq( Y/X, a )
sol = solve(testEq2,Y/X)
This is not weird or unreasonable at all. If you look at the source code of the solve function it uses code like
>>> testEq.has( Y/X ) # returns False
>>> testEq2.has( Y/X ) # returns True
to check if the symbol ( or sympy object ) that we are solving is present in the equation. If SymPy had to check for all possible ways in which the symbols of an expression can be combined into sub-expressions, the code would become extremely complicated for something which can be easily achieved in other ways ( like solving for Y and dividing by X, in this example ).
Packages for symbolic computations are there to help us handle complicated mathematical equations. But they are not a substitute for human intelligence. More often than not, we need to guide these packages to help them give the answer in a form we want while working around their limitations.
In this issue, a focus routine handles such a request once an auxiliary expression is added to the one of interest:
>>> eq = Eq(y, x*a)
>>> aux = Eq(b, y/x)
>>> focus((aux, eq), b)
{b: a}
Such a routine does not eliminate the need for human intervention, it just assists by allowing the user to state the relationship of interest and add that to the current equation(s) from which the implications are then deduced/solved.
Assume we have a function with unknown formula, given few inputs and results of this function, how can we get the function's formula.
For example we have inputs x and y and result r in format (x,y,r)
[ (2,4,8) , (3,6,18) ]
And the desired function can be
f(x,y) = x * y
As you post the question, the problem is too generic. If you want to find any formula mapping the given inputs to the given result, there are simply too many possible formulas. In order to make sense of this, you need to somehow restrict the set of functions to consider. For example you could say that you're only interested in polynomial solutions, i.e. where
r = sum a_ij * x^i * y^j for i from 0 to n and j from 0 to n - i
then you have a system of equations, with the a_ij as parameters to solve for. The higher the degree n the more such parameters you'd have to find, so the more input-output combinations you'd need to know. Variations of this use rational functions (so you divide by another polynomial), or allow some trigonometric functions, or something like that.
If your setup were particularly easy, you'd have just linear equations, i.e. r = a*x + b*y + c. As you can see, even that has three parameters a,b,c so you can't uniquely find all three of them just given the two inputs you provided in your question. And even then the result would not be the r = x*y you were aiming for, since that's technically of degree 2.
If you want to point out that r = x*y is a particularly simple formula, and you would like to look for simple formulas, then one approach would be enumerating formulas in order of increasing complexity. But if you do this without parameters (since ugly parameters will make a simple formula like a*x + b*y + c appear complex), then it's hard to guilde this enumeration towards the one you want, so you'd really have to enumerate all possible formulas, which will become infeasible very quickly.
I have derived some equations with some variables. I want to solve to an unknown variable. I am using Sympy. My code is as follows:
import sympy as syp
import math as m
#this is the unknown variable that I want to find
C0 = syp.Symbol('C0')
#Known variables
D0 = 0.874
theta2 = 10.0
fi2 = 80.0
theta1 = (theta2/180.0)*m.pi
fi1 = (fi2/180.0)*m.pi
#Definitions of 6 different equations all of them in respect to CO.
C_t = 5*m.pi*(D0+4*C0)
St123 = 1.5*theta1*(D0+2*C0)
St45 = fi1*(D0+7*C0)
l1 = syp.sqrt((0.5*(D0+4*C0)-0.5*D0*m.cos(theta1))**2 + (0.5*D0*m.sin(theta1))**2)
l2 = syp.sqrt((0.5*(D0+6*C0)-0.5*(D0+2*C0)*m.cos(theta1))**2 + (0.5*(D0+2*C0)*m.sin(theta1))**2)
l3 = syp.sqrt((0.5*(D0+8*C0)-0.5*(D0+4*C0)*m.cos(theta1))**2 + (0.5*(D0+4*C0)*m.sin(theta1))**2)
#Definition of the general relationship between the above functions. Here C0 is unknown and C_b
C_b = C_t + 6*C0 + 3*(l1+l2+l3) - 3*St123 - 3*St45
#for C_b = 10.4866, find C0
syp.solve(C_b - 10.4866, C0)
As observed, I want to solve the C_b relationship to C0. Until the last line my code works fine. When I ran the whole script it seems that takes ages to calculate the C0. I dont have any warning message but I dont have any solution either. Would anybody suggest an alternative or a possible solution? Thanks a lot in advance.
As I have mentioned in a comment this problem is numerical in nature, so it is better to try to solve it with numpy/scipy. Nonetheless it is an amusing example of how to do numerics in sympy so here is one suggested workflow.
First of all, if it was not for the relative complexity of the expressions here, scipy would have been definitely the better option over sympy. But the expression is rather complicated, so we can first simplify it in sympy and only then feed it to scipy:
>>> C_b
38.0∗C0
+3.0∗((0.17∗C0+0.076)∗∗2+(2.0∗C0+0.0066)∗∗2)∗∗0.5
+3.0∗((0.35∗C0+0.076)∗∗2+(2.0∗C0+0.0066)∗∗2)∗∗0.5
+3.0∗((2.0∗C0+0.0066)∗∗2+0.0058)∗∗0.5
+9.4
>>> simplify(C_b)
38.0∗C0
+3.0∗(4.0∗C0∗∗2+0.027∗C0+0.0058)∗∗0.5
+3.0∗(4.1∗C0∗∗2+0.053∗C0+0.0058)∗∗0.5
+3.0∗(4.2∗C0∗∗2+0.08∗C0+0.0058)∗∗0.5
+9.4
Now given that you are not interested in symbolics and that the simplification was not that good, it would be useless to continue using sympy instead of scipy, but if you insist you can do it.
>>> nsolve(C_b - 10.4866, C0, 1) # for numerical solution
0.00970963412692139
If you try to use solve instead of nsolve you will just waste a lot of resources in searching for a symbolic solution (that may not even exist in elementary terms) when a numeric one is instantaneous.