I have a function like this:
def objective(x, y, z, q):
theta1 = f(x, y)
theta2 = f(x, z)
rho = q - (theta1 + theta2)
return rho * x
and I would like to find the value of x that maximizes the objective function, knowing that x must be between two boundaries b1, b2.
My first guess was to iterate from b1 through b2 to find which value of x maximizes the objective function but I guess there are more efficient ways to do this.
What is the most efficient way to find the value of x that maximizes the objective function in this case ?
I know I could use scipy.optimize.maximize, but I can't find a way to use it to maximize the objective function with respect to just x.
Assuming that x is a scalar variable and you already know the values of y, z and q, you could do something like this:
from scipy.optimize import minimize
# bound: b1 <= x <= b2
bounds = [(b1, b2)]
# given values for y, q, and z
y0 = 1.0
z0 = 1.0
q0 = 1.0
# (feasible) initial guess
x0 = (b2 - b1) / 2.0
res = minimize(lambda x: -1.0*objective(x, y0, z0, q0), x0=x0, bounds=bounds)
Note that maximizing the function obj(x) is the equivalent to minimizing -1.0*obj(x).
Assume the following function:
f(x) = x * cos(x-4)
With x = [-2.5, 2.5] this function crosses 0 at f(0) = 0 and f(-0.71238898) = 0.
This was determined with the following code:
import math
from scipy.optimize import fsolve
def func(x):
return x*math.cos(x-4)
x0 = fsolve(func, 0.0)
# returns [0.]
x0 = fsolve(func, -0.75)
# returns [-0.71238898]
What is the proper way to use fzero (or any other Python root finder) to find both roots in one call? Is there a different scipy function that does this?
fzero reference
I once wrote a module for this task. It's based on chapter 4.3 from the book Numerical Methods in Engineering with Python by Jaan Kiusalaas:
import math
def rootsearch(f,a,b,dx):
x1 = a; f1 = f(a)
x2 = a + dx; f2 = f(x2)
while f1*f2 > 0.0:
if x1 >= b:
return None,None
x1 = x2; f1 = f2
x2 = x1 + dx; f2 = f(x2)
return x1,x2
def bisect(f,x1,x2,switch=0,epsilon=1.0e-9):
f1 = f(x1)
if f1 == 0.0:
return x1
f2 = f(x2)
if f2 == 0.0:
return x2
if f1*f2 > 0.0:
print('Root is not bracketed')
return None
n = int(math.ceil(math.log(abs(x2 - x1)/epsilon)/math.log(2.0)))
for i in range(n):
x3 = 0.5*(x1 + x2); f3 = f(x3)
if (switch == 1) and (abs(f3) >abs(f1)) and (abs(f3) > abs(f2)):
return None
if f3 == 0.0:
return x3
if f2*f3 < 0.0:
x1 = x3
f1 = f3
else:
x2 =x3
f2 = f3
return (x1 + x2)/2.0
def roots(f, a, b, eps=1e-6):
print ('The roots on the interval [%f, %f] are:' % (a,b))
while 1:
x1,x2 = rootsearch(f,a,b,eps)
if x1 != None:
a = x2
root = bisect(f,x1,x2,1)
if root != None:
pass
print (round(root,-int(math.log(eps, 10))))
else:
print ('\nDone')
break
f=lambda x:x*math.cos(x-4)
roots(f, -3, 3)
roots finds all roots of f in the interval [a, b].
Define your function so that it can take either a scalar or a numpy array as an argument:
>>> import numpy as np
>>> f = lambda x : x * np.cos(x-4)
Then pass a vector of arguments to fsolve.
>>> x = np.array([0.0, -0.75])
>>> fsolve(f,x)
array([ 0. , -0.71238898])
In general (i.e. unless your function belongs to some specific class) you can't find all the global solutions - these methods usually do local optimization from given starting points.
However, you can switch math.cos() with numpy.cos() and that will vectorize your function so it can solve for many values at once, e.g. fsolve(func, np.arange(-10,10,0.5)).
Let us assume I have a set of differential equations to be integrated with scipy odeint. Now my goal is to find the steady-state (I chose initial conditions such that this state exists). At the moment I have implemented something like
cond = True
while cond:
x = integrate(interval = [0,t], steps = 200)
if var(x[-22::]) < maxvar:
cond = False
return mean(x)
else:
t*= 2
Do you have a more efficient approach?
If you are using odeint, then you already have your differential equations written as a function f(x, t) (or possibly f(x, t, *args)). If your system is autonomous (i.e. f does not actually depend on t), you can find an equilibrium by solving f(x, 0) == 0 for x. You can use, for example, scipy.optimize.fsolve to solve for the equilibrium.
The following is an example. It uses the "Coupled Spring Mass System" example from the scipy cookbook. scipy.optimize.fsolve is used to find the equilibrium solution x1 = 0.5, y1 = 0, x2 = 1.5, y2 = 0.
from scipy.optimize import fsolve
def vectorfield(w, t, p):
"""
Defines the differential equations for the coupled spring-mass system.
Arguments:
w : vector of the state variables:
w = [x1, y1, x2, y2]
t : time
p : vector of the parameters:
p = [m1, m2, k1, k2, L1, L2, b1, b2]
"""
x1, y1, x2, y2 = w
m1, m2, k1, k2, L1, L2, b1, b2 = p
# Create f = (x1', y1', x2', y2'):
f = [y1,
(-b1 * y1 - k1 * (x1 - L1) + k2 * (x2 - x1 - L2)) / m1,
y2,
(-b2 * y2 - k2 * (x2 - x1 - L2)) / m2]
return f
if __name__ == "__main__":
# Parameter values
# Masses:
m1 = 1.0
m2 = 1.5
# Spring constants
k1 = 8.0
k2 = 40.0
# Natural lengths
L1 = 0.5
L2 = 1.0
# Friction coefficients
b1 = 0.8
b2 = 0.5
# Pack up the parameters and initial conditions:
p = [m1, m2, k1, k2, L1, L2, b1, b2]
# Initial guess to pass to fsolve. The second and fourth components
# are the velocities of the masses, and we know they will be 0 at
# equilibrium. For the positions x1 and x2, we'll try 1 for both.
# A better guess could be obtained by solving the ODEs for some time
# interval, and using the last point of that solution.
w0 = [1.0, 0, 1.0, 0]
# Find the equilibrium
eq = fsolve(vectorfield, w0, args=(0, p))
print "Equilibrium: x1 = {0:.1f} y1 = {1:.1f} x2 = {2:.1f} y2 = {3:.1f}".format(*eq)
The output is:
Equilibrium: x1 = 0.5 y1 = 0.0 x2 = 1.5 y2 = 0.0
Referring to your comments, I don't see any better way:
In this case where you know approximately where the system will settle.
(This is fairly easy to predict in some systems, like a pendulum, or a charging capacitor), and that it will settle, the fastest way I know is to check if
(p[0] * x[i] + p[1] * x[i-1] ... + p[n] * x[i-n] - mean(x[i-0:n]) )< epsilon)
The difficulty is determining the size of epsilon, the parameters p[0:n] to tune this detection.
Clearly you are already using this window method:
epsilon = varmax
p[0:n] = 1
n = 22
and have optimized it by removing the parameters for the filter, and simply using the variance.
For many systems (where settling looks like 1 order differential equations) the filter parameters turn out to look like this:
p[0] = n/2
p[n] = n/2
p[1:n-1] = 0
meaning you can make stuff go faster if you replace the calculation of state variance with this simple test:
if( abs(x[-22] - x[0]) > epsilon)
This will not detect correctly if small disturbances are still present, since we don't know your system, that's difficult to talk about...
Assume the following function:
f(x) = x * cos(x-4)
With x = [-2.5, 2.5] this function crosses 0 at f(0) = 0 and f(-0.71238898) = 0.
This was determined with the following code:
import math
from scipy.optimize import fsolve
def func(x):
return x*math.cos(x-4)
x0 = fsolve(func, 0.0)
# returns [0.]
x0 = fsolve(func, -0.75)
# returns [-0.71238898]
What is the proper way to use fzero (or any other Python root finder) to find both roots in one call? Is there a different scipy function that does this?
fzero reference
I once wrote a module for this task. It's based on chapter 4.3 from the book Numerical Methods in Engineering with Python by Jaan Kiusalaas:
import math
def rootsearch(f,a,b,dx):
x1 = a; f1 = f(a)
x2 = a + dx; f2 = f(x2)
while f1*f2 > 0.0:
if x1 >= b:
return None,None
x1 = x2; f1 = f2
x2 = x1 + dx; f2 = f(x2)
return x1,x2
def bisect(f,x1,x2,switch=0,epsilon=1.0e-9):
f1 = f(x1)
if f1 == 0.0:
return x1
f2 = f(x2)
if f2 == 0.0:
return x2
if f1*f2 > 0.0:
print('Root is not bracketed')
return None
n = int(math.ceil(math.log(abs(x2 - x1)/epsilon)/math.log(2.0)))
for i in range(n):
x3 = 0.5*(x1 + x2); f3 = f(x3)
if (switch == 1) and (abs(f3) >abs(f1)) and (abs(f3) > abs(f2)):
return None
if f3 == 0.0:
return x3
if f2*f3 < 0.0:
x1 = x3
f1 = f3
else:
x2 =x3
f2 = f3
return (x1 + x2)/2.0
def roots(f, a, b, eps=1e-6):
print ('The roots on the interval [%f, %f] are:' % (a,b))
while 1:
x1,x2 = rootsearch(f,a,b,eps)
if x1 != None:
a = x2
root = bisect(f,x1,x2,1)
if root != None:
pass
print (round(root,-int(math.log(eps, 10))))
else:
print ('\nDone')
break
f=lambda x:x*math.cos(x-4)
roots(f, -3, 3)
roots finds all roots of f in the interval [a, b].
Define your function so that it can take either a scalar or a numpy array as an argument:
>>> import numpy as np
>>> f = lambda x : x * np.cos(x-4)
Then pass a vector of arguments to fsolve.
>>> x = np.array([0.0, -0.75])
>>> fsolve(f,x)
array([ 0. , -0.71238898])
In general (i.e. unless your function belongs to some specific class) you can't find all the global solutions - these methods usually do local optimization from given starting points.
However, you can switch math.cos() with numpy.cos() and that will vectorize your function so it can solve for many values at once, e.g. fsolve(func, np.arange(-10,10,0.5)).
I am trying to implement the Karatsuba multiplication algorithm in c++ but right now I am just trying to get it to work in python.
Here is my code:
def mult(x, y, b, m):
if max(x, y) < b:
return x * y
bm = pow(b, m)
x0 = x / bm
x1 = x % bm
y0 = y / bm
y1 = y % bm
z2 = mult(x1, y1, b, m)
z0 = mult(x0, y0, b, m)
z1 = mult(x1 + x0, y1 + y0, b, m) - z2 - z0
return mult(z2, bm ** 2, b, m) + mult(z1, bm, b, m) + z0
What I don't get is: how should z2, z1, and z0 be created? Is using the mult function recursively correct? If so, I'm messing up somewhere because the recursion isn't stopping.
Can someone point out where the error is?
NB: the response below addresses directly the OP's question about
excessive recursion, but it does not attempt to provide a correct
Karatsuba algorithm. The other responses are far more informative in
this regard.
Try this version:
def mult(x, y, b, m):
bm = pow(b, m)
if min(x, y) <= bm:
return x * y
# NOTE the following 4 lines
x0 = x % bm
x1 = x / bm
y0 = y % bm
y1 = y / bm
z0 = mult(x0, y0, b, m)
z2 = mult(x1, y1, b, m)
z1 = mult(x1 + x0, y1 + y0, b, m) - z2 - z0
retval = mult(mult(z2, bm, b, m) + z1, bm, b, m) + z0
assert retval == x * y, "%d * %d == %d != %d" % (x, y, x * y, retval)
return retval
The most serious problem with your version is that your calculations of x0 and x1, and of y0 and y1 are flipped. Also, the algorithm's derivation does not hold if x1 and y1 are 0, because in this case, a factorization step becomes invalid. Therefore, you must avoid this possibility by ensuring that both x and y are greater than b**m.
EDIT: fixed a typo in the code; added clarifications
EDIT2:
To be clearer, commenting directly on your original version:
def mult(x, y, b, m):
# The termination condition will never be true when the recursive
# call is either
# mult(z2, bm ** 2, b, m)
# or mult(z1, bm, b, m)
#
# Since every recursive call leads to one of the above, you have an
# infinite recursion condition.
if max(x, y) < b:
return x * y
bm = pow(b, m)
# Even without the recursion problem, the next four lines are wrong
x0 = x / bm # RHS should be x % bm
x1 = x % bm # RHS should be x / bm
y0 = y / bm # RHS should be y % bm
y1 = y % bm # RHS should be y / bm
z2 = mult(x1, y1, b, m)
z0 = mult(x0, y0, b, m)
z1 = mult(x1 + x0, y1 + y0, b, m) - z2 - z0
return mult(z2, bm ** 2, b, m) + mult(z1, bm, b, m) + z0
Usually big numbers are stored as arrays of integers. Each integer represents one digit. This approach allows to multiply any number by the power of base with simple left shift of the array.
Here is my list-based implementation (may contain bugs):
def normalize(l,b):
over = 0
for i,x in enumerate(l):
over,l[i] = divmod(x+over,b)
if over: l.append(over)
return l
def sum_lists(x,y,b):
l = min(len(x),len(y))
res = map(operator.add,x[:l],y[:l])
if len(x) > l: res.extend(x[l:])
else: res.extend(y[l:])
return normalize(res,b)
def sub_lists(x,y,b):
res = map(operator.sub,x[:len(y)],y)
res.extend(x[len(y):])
return normalize(res,b)
def lshift(x,n):
if len(x) > 1 or len(x) == 1 and x[0] != 0:
return [0 for i in range(n)] + x
else: return x
def mult_lists(x,y,b):
if min(len(x),len(y)) == 0: return [0]
m = max(len(x),len(y))
if (m == 1): return normalize([x[0]*y[0]],b)
else: m >>= 1
x0,x1 = x[:m],x[m:]
y0,y1 = y[:m],y[m:]
z0 = mult_lists(x0,y0,b)
z1 = mult_lists(x1,y1,b)
z2 = mult_lists(sum_lists(x0,x1,b),sum_lists(y0,y1,b),b)
t1 = lshift(sub_lists(z2,sum_lists(z1,z0,b),b),m)
t2 = lshift(z1,m*2)
return sum_lists(sum_lists(z0,t1,b),t2,b)
sum_lists and sub_lists returns unnormalized result - single digit can be greater than the base value. normalize function solved this problem.
All functions expect to get list of digits in the reverse order. For example 12 in base 10 should be written as [2,1]. Lets take a square of 9987654321.
» a = [1,2,3,4,5,6,7,8,9]
» res = mult_lists(a,a,10)
» res.reverse()
» res
[9, 7, 5, 4, 6, 1, 0, 5, 7, 7, 8, 9, 9, 7, 1, 0, 4, 1]
The goal of the Karatsuba multiplication is to improve on the divide-and conquer multiplication algorithm by making 3 recursive calls instead of four. Therefore, the only lines in your script that should contain a recursive call to the multiplication are those assigning z0,z1 and z2. Anything else will give you a worse complexity. You can't use pow to compute bm when you haven't defined multiplication yet (and a fortiori exponentiation), either.
For that, the algorithm crucially uses the fact that it is using a positional notation system. If you have a representation x of a number in base b, then x*bm is simply obtained by shifting the digits of that representation m times to the left. That shifting operation is essentially "free" with any positional notation system. That also means that if you want to implement that, you have to reproduce this positional notation, and the "free" shift. Either you chose to compute in base b=2 and use python's bit operators (or the bit operators of a given decimal, hex, ... base if your test platform has them), or you decide to implement for educational purposes something that works for an arbitrary b, and you reproduce this positional arithmetic with something like strings, arrays, or lists.
You have a solution with lists already. I like to work with strings in python, since int(s, base) will give you the integer corresponding to the string s seen as a number representation in base base: it makes tests easy. I have posted an heavily commented string-based implementation as a gist here, including string-to-number and number-to-string primitives for good measure.
You can test it by providing padded strings with the base and their (equal) length as arguments to mult:
In [169]: mult("987654321","987654321",10,9)
Out[169]: '966551847789971041'
If you don't want to figure out the padding or count string lengths, a padding function can do it for you:
In [170]: padding("987654321","2")
Out[170]: ('987654321', '000000002', 9)
And of course it works with b>10:
In [171]: mult('987654321', '000000002', 16, 9)
Out[171]: '130eca8642'
(Check with wolfram alpha)
I believe that the idea behind the technique is that the zi terms are computed using the recursive algorithm, but the results are not unified together that way. Since the net result that you want is
z0 B^2m + z1 B^m + z2
Assuming that you choose a suitable value of B (say, 2) you can compute B^m without doing any multiplications. For example, when using B = 2, you can compute B^m using bit shifts rather than multiplications. This means that the last step can be done without doing any multiplications at all.
One more thing - I noticed that you've picked a fixed value of m for the whole algorithm. Typically, you would implement this algorithm by having m always be a value such that B^m is half the number of digits in x and y when they are written in base B. If you're using powers of two, this would be done by picking m = ceil((log x) / 2).
Hope this helps!
In Python 2.7: Save this file as Karatsuba.py
def karatsuba(x,y):
"""Karatsuba multiplication algorithm.
Return the product of two numbers in an efficient manner
#author Shashank
date: 23-09-2018
Parameters
----------
x : int
First Number
y : int
Second Number
Returns
-------
prod : int
The product of two numbers
Examples
--------
>>> import Karatsuba.karatsuba
>>> a = 1234567899876543211234567899876543211234567899876543211234567890
>>> b = 9876543211234567899876543211234567899876543211234567899876543210
>>> Karatsuba.karatsuba(a,b)
12193263210333790590595945731931108068998628253528425547401310676055479323014784354458161844612101832860844366209419311263526900
"""
if len(str(x)) == 1 or len(str(y)) == 1:
return x*y
else:
n = max(len(str(x)), len(str(y)))
m = n/2
a = x/10**m
b = x%10**m
c = y/10**m
d = y%10**m
ac = karatsuba(a,c) #step 1
bd = karatsuba(b,d) #step 2
ad_plus_bc = karatsuba(a+b, c+d) - ac - bd #step 3
prod = ac*10**(2*m) + bd + ad_plus_bc*10**m #step 4
return prod