How do I optimize a simple multivariate function in economics - python

I apologize if this is simple but I have looked for over an hour and nothing has worked. I am attempting to use python to find the optimal level of L (Labor) and the output (Profit) given the objective function 5(12*L*K - 0.1*L^2*K) - 5*L - 5*K when K is fixed at 10.
I have tried to use the following code from other answers to similar questions (using the '-' to maximize).
def micro(L):
return 5(12*L*10 - 0.1*L**2*10) - 5*L - 5*10
results = minimize(-micro, 0)
I'm still new to python so I could just be completely off base. Thanks for the help!

scipy.optimize.fmin can do this:
>>> from scipy.optimize import fmin
>>> def fn(x):
... return -(-5*x*x+595*x-10)
...
>>> fmin(fn,0)
Optimization terminated successfully.
Current function value: -17651.250000
Iterations: 37
Function evaluations: 74
[59.5]
>>>

By using np.arange we create a NumPy array from 0 to 100 each time increasing by 0.1 then we plug it into the profit equation and we use np.argmax to return the index of the biggest profit witch will get us how much labor you have to do for it.
import numpy as np
def find_optimal_L():
L = np.arange(0, 100, 0.1)
profit = 5*(12*L*10 - 0.1*L**2*10) - 5*L - 5*10
return L[np.argmax(profit)], np.max(profit)
L,profit = find_optimal_L()
print(L,profit)

This is other option:
my_results = []
def micro(L):
result = 5*(12*L*10 - 0.1*L**2*10) - 5*L - 5*10
my_results.append(result)
return np.amax(my_results)
You can change the range here:
L = np.linspace(-100, 100, 1000)
micro(L)
17651.232263294325 # Output
If you want to minimise, just change the return:
return np.amin(my_results) # -109550.0 Output

Related

Total Sum of Squares (TSS) in python

I'm trying to calculate the total sum of squares using python.
I know that the formula of TSS is:
[enter image description here][1]
I created a code to do it:
from statistics import mean
x = ([3,1,3,1,3,13])
def tss(a):
m = mean(a)
for i in a:
i += ((i-m)**2)
return (i)
print(tss(x))
The problem is: Its keeping returning me 94, but i know that the correct answer is 102. I don't have a clue of what i did wrong. Can anybody help me?
[1]: https://i.stack.imgur.com/Alx6r.png
i is resetting each time it goes through the loop. So on the last loop your function erases all the previous sums, sets i to 13, then adds the square of the difference between 13 and the mean to i (which is now 13), returning 94. You need a different variable to track the sum, so it doesn't get lost each loop. You want:
from statistics import mean
x = ([3,1,3,1,3,13])
def tss(a):
m = mean(a)
n = 0
for i in a:
n += ((i-m)**2)
return (n)
print(tss(x))
'''
#mateen's answer is more pythonic and will perform better than a loop, but I don't think you'll get the understanding from it. Welcome to python!
If you want to keep your initial script , just do :
from statistics import mean
x = ([3, 1, 3, 1, 3, 13])
def tss(a):
total = 0
for i in a:
total = total + ((i-mean(a))**2)
return total
Without numpy:
def tss(xs):
m = sum(xs) / len(xs)
return sum((x - m)**2 for x in xs)
With numpy:
import numpy as np
def tss(x):
return ((x - np.mean(x))**2).sum()

ChiDist excel function in python

I have an excel function that i'm trying to replicate into python but struggling to replicate it. Here's the function (VBA):
Function Z(Lambda, conf) As Integer
Application.Volatile
Lambda = Application.Round(Lambda, 3)
Select Case Lambda
Case Is < 400
For i = 0 To 500
' v = Application.Poisson(i, Lambda, True)
v = Application.ChiDist(2 * Lambda, 2 * i + 2)
If v >= conf Then
Z = i
Exit Function
End If
Next
Case Else
Z = Application.NormInv(conf, Lambda, Sqr(Lambda))
End Select
End Function
In Excel if i run =z(2,95%), i get z=5
I thought I could use:
from scipy import stats
stats.chi2.cdf
but not getting far with it.
Any help is highly appreciated!
According to the ChiDist docs, (see also CHIDIST), ChiDist returns the right tail of the Χ² distribution. The corresponding function in SciPy is the sf (survival function) method of scipy.stats.chi2. In your Python code, change stats.chi2.cdf to stats.chi2.sf.
Managed to get the function working in python - thanks #Warren Weckesser for the guidance on the chi2.sf.
from scipy.stats import norm, chi2
def z(lamda_calc, prob):
if lamda_calc < 400:
z_calc = [i for i in range (0,500) if chi2.sf(2 * lamda_calc, 2 * i + 2) >=
prob][0]
else:
z_calc = int(norm.ppf(prob,lamda_calc,sqrt(lamda_calc)))
return z_calc
print
print ("z:'", z(1.4, 0.98))

Using the inverse sec function in Python

I am creating a program that calculates the optimum angles to fire a projectile from a range of heights and a set initial velocity. Within the final equation I need to utilise, there is an inverse sec function present that is causing some troubles.
I have imported math and attempted to use asec(whatever) however it seems math can not calculate inverse sec functions? I also understand that sec(x) = 1/cos(x) but when I sub 1/cos(x) into the equation instead and algebraically solve for x it becomes a non real result :/.
The code I have is as follows:
print("This program calculates the optimum angles to launch a projectile from a given range of heights and a initial speed.")
x = input("Input file name containing list of heights (m): ")
f = open(x, "r")
for line in f:
heights = line
print("the heights you have selected are : ", heights)
f.close()
speed = float(input("Input your initial speed (m/s): "))
print("The initial speed you have selected is : ", speed)
ran0 = speed*speed/9.8
print(ran0)
f = open(x, "r")
for line in f:
heights = (line)
import math
angle = (math.asec(1+(ran0/float(heights))))/2
print(angle)
f.close()
So my main question is, is there any way to find the inverse sec of anything in python without installing and importing something else?
I realise this may be more of a math based problem than a coding problem however any help is appreciated :).
Let's say we're looking for real number x whose arcsecant is angle θ. Then we have:
θ = arcsec(x)
sec(θ) = x
1 / cos(θ) = x
cos(θ) = 1 / x
θ = arccos(1/x)
So with this reasoning, you can write your arcsecant function as:
from math import acos
def asec(x):
return acos(1/x)
"I also understand that sec(x) = 1/cos(x) but when I sub 1/cos(x) ..." Do you have to use sec or asec ?
Because sec(x)= 1/cos(x) and asec(x) = acos(1/x). Be careful the notation ^-1 is ambiguous, cos^-1(x) = acos(x) is different of [cos(x)]^-1.
angle = (math.asec(1+(ran0/float(heights))))/2
asec is not defined from -1 to 1
If you have a height lower than zero, and so the result of (ran0/float(heights)) is between -2 and 0, your angle will be non real.
I don't really know if this is what you asked for, but I hope it helps.
If math is OK for you to import, then you can use:
import math
def asec(x):
if x == 0:
return 1j * math.inf
else:
return math.acos(1 / x)
For some other ways of of re-writing asec(x), feast your eyes on the relevant Wikipedia article.
Alternatively, you could use Taylor series expansions, which always come in polynomial form, so, although that is only an approximation in a neighborhood of a given point, it would not require math.
For asec(x), its Taylor expansion in a neighborhood of ±∞ (also known as Laurent series) is given by (without using math):
def asec_taylor(x, pi=3.14159265):
if x == 0:
return 1j * float('inf')
else:
return pi / 2 - 1 / x - 1 / (6 * x ** 3) - 3 / (40 * x ** 5)
You can quickly check that the farther you are from 0, the better the approximation holds:
for x in range(-10, 10):
print(x, asec(x), asec_taylor(x))
-10 1.6709637479564565 1.670963741666667
-9 1.6821373411358604 1.6821373299281108
-8 1.696124157962962 1.6961241346516926
-7 1.714143895700262 1.7141438389326868
-6 1.7382444060145859 1.7382442416666668
-5 1.7721542475852274 1.7721536583333335
-4 1.8234765819369754 1.823473733854167
-3 1.9106332362490186 1.910611139814815
-2 2.0943951023931957 2.0939734083333335
-1 3.141592653589793 2.8124629916666666
0 (nan+infj) (nan+infj)
1 0 0.32912965833333346
2 1.0471975511965979 1.0476192416666668
3 1.2309594173407747 1.2309815101851853
4 1.318116071652818 1.3181189161458333
5 1.369438406004566 1.3694389916666667
6 1.4033482475752073 1.4033484083333334
7 1.4274487578895312 1.4274488110673134
8 1.4454684956268313 1.4454685153483076
9 1.4594553124539327 1.4594553200718894
If you can try of inverse of sec then it will be same as
>>>from mpmath import *
>>> asec(-1)
mpf('3.1415926535897931')
Here are the link in where you can better understand - [http://omz-software.com/pythonista/sympy/modules/mpmath/functions/trigonometric.html]

Structuring a list of objects in python for vectorization: Can a list of structures(objects) be vectorized, or are explicit arrays required

Energy calculations in molecular simulation are inherently full of "for" loops. Traditionally coordinates for each atom/molecule were stored in arrays. arrays are fairly straightforward to vectorize, but structures are nice to code with. Treating molecules as individual objects, each with their own coordinates, and other properties, is very convenient and much clearer as far as book-keeping goes.
I am using Python version 3.6
My problem is that I cannot figure out how to vectorize calculations when I am using an array of objects... it seems that a for loop cannot be avoided. Is it necessary for me to use arrays in order to take advantage of numpy and vectorize my code?
Here is a python example which utilizes arrays (line 121 of the code), and shows a fast (numpy) and slow ( 'normal') python energy calculation.
https://github.com/Allen-Tildesley/examples/blob/master/python_examples/mc_lj_module.py
The calculation is much faster using the numpy accelerated method because it is vectorized.
How would I vectorize an energy calculation if I was not using arrays, but an array of objects, each with their own coordinates? This seems to necessitate using the slower for loop.
Here is a simple example code with a working slow version of the for loop, and an attempted vectorization that doesn't work:
import numpy as np
import time
class Mol:
num = 0
def __init__(self, r):
Mol.num += 1
self.r = np.empty((3),dtype=np.float_)
self.r[0] = r[0]
self.r[1] = r[1]
self.r[2] = r[2]
""" Alot more useful things go in here in practice"""
################################################
# #
# Main Program #
# #
################################################
L = 5.0 # Length of simulation box (arbitrary)
r_cut_box_sq = L/2 # arbitrary cutoff - required
mol_list=[]
nmol = 1000 # number of molecules
part = 1 # arbitrary molecule to interact with rest of molecules
""" make 1000 molecules (1 atom per molecule), give random coordinates """
for i in range(nmol):
r = np.random.rand(3) * L
mol_list.append( Mol( r ) )
energy = 0.0
start = time.time()
################################################
# #
# Slow but functioning loop #
# #
################################################
for i in range(nmol):
if i == part:
continue
rij = mol_list[part].r - mol_list[i].r
rij = rij - np.rint(rij/L)*L # apply periodic boundary conditions
rij_sq = np.sum(rij**2) # Squared separations
in_range = rij_sq < r_cut_box_sq
sr2 = np.where ( in_range, 1.0 / rij_sq, 0.0 )
sr6 = sr2 ** 3
sr12 = sr6 ** 2
energy += sr12 - sr6
end = time.time()
print('slow: ', end-start)
print('energy: ', energy)
start = time.time()
################################################
# #
# Failed vectorization attempt #
# #
################################################
""" The next line is my problem, how do I vectorize this so I can avoid the for loop all together?
Leads to error AttributeError: 'list' object has no attribute 'r' """
""" I also must add in that part cannot interact with itself in mol_list"""
rij = mol_list[part].r - mol_list[:].r
rij = rij - np.rint(rij/L)*L # apply periodic boundary conditions
rij_sq = np.sum(rij**2)
in_range = rij_sq < r_cut_box_sq
sr2 = np.where ( in_range, 1.0 / rij_sq, 0.0 )
sr6 = sr2 ** 3
sr12 = sr6 ** 2
energy = sr12 - sr6
energy = sum(energy)
end = time.time()
print('faster??: ', end-start)
print('energy: ', energy)
Lastly
Would any possible solutions be affected if inside the energy calculation, it was necessary to loop over each atom in each molecule where their is now more than 1 atom per molecule, and not all molecules have the same number of atoms, thus having a double for loop for molecule-molecule interactions rather than the simple pair-pair interactions currently employed.
Making use of the itertools library might be the way forward here. Suppose you wrap the energy calculation of a pair of molecules in a function:
def calc_pairwise_energy((mol_a,mol_b)):
# function takes a 2 item tuple of molecules
# energy calculating code here
return pairwise_energy
Then you can use itertools.combinations to get all the pairs of molecules and python's built in list comprehensions (the code inside [ ] on the last line below):
from itertools import combinations
pairs = combinations(mol_list,2)
energy = sum( [calc_pairwise_energy(pair) for pair in pairs] )
I've come back to this answer as I realised I hadn't properly answered your question. With what I've already posted the pairwise energy calculation function looked like this (I've made a few optimisations to your code):
def calc_pairwise_energy(molecules):
rij = molecules[0].r - molecules[1].r
rij = rij - np.rint(rij/L)*L
rij_sq = np.sum(rij**2) # Squared separations
if rij_sq < r_cut_box_sq:
return (rij_sq ** -6) - (rij_sq ** - 3)
else:
return 0.0
Whereas a vectorised implementation that does all the pairwise calculations in a single call might look like this:
def calc_all_energies(molecules):
energy = 0
for i in range(len(molecules)-1):
mol_a = molecules[i]
other_mols = molecules[i+1:]
coords = np.array([mol.r for mol in other_mols])
rijs = coords - mol_a.r
# np.apply_along_axis replaced as per #hpaulj's comment (see below)
#rijs = np.apply_along_axis(lambda x: x - np.rint(x/L)*L,0,rijs)
rijs = rijs - np.rint(rijs/L)*L
rijs_sq = np.sum(rijs**2,axis=1)
rijs_in_range= rijs_sq[rijs_sq < r_cut_box_sq]
energy += sum(rijs_in_range ** -6 - rijs_in_range ** -3)
return energy
This is much faster but there is still plenty to optimise here.
If you want to calculate energies with coordinates as inputs, I'm assuming you're looking for pair-wise distances. For this, you should look into the SciPy library. Specifically, I would look at scipy.spatial.distance.pdist. The documentation can be found here.

Converting recursive algorithm to Iterative

I have done the Recursive function in Python that works:
def Rec(n):
if (n<=5):
return 2*n
elif (n>=6):
return Rec(n-6)+2*Rec(n-4)+4*Rec(n-2)
print (Rec(50))
But I can't think of an iterative one
I am sure I will need to use a loop and possibly have 4 variables to store the previous values, imitating a stack.
For your particular question, assuming you have an input n, the following code should calculate the function iteratively in python.
val = []
for i in range(6):
val.append(2*i)
for i in range(6,n+1):
val.append( val[i-6] + 2*val[i-4] + 4*val[i-2] )
print(val[n])
I get this answer:
$ python test.py
Rec(50) = 9142785252232708
Kist(50) = 9142785252232708
Using the code below. The idea is that your function needs a "window" of previous values - Kn-6, Kn-4, Kn-2 - and that window can be "slid" along as you compute new values.
So, for some value like "14", you would have a window of K8, K9, ... K13. Just compute using those values, then drop K8 since you'll never use it again, and append K14 so you can use it in computing K15..20.
def Rec(n):
if (n<=5):
return 2*n
elif (n>=6):
return Rec(n-6)+2*Rec(n-4)+4*Rec(n-2)
def Kist(n):
if n <= 5:
return 2 * n
KN = [2*n for n in range(6)]
for i in range(6, n+1):
kn = KN[-6] + 2 * KN[-4] + 4 * KN[-2]
KN.append(kn)
KN = KN[-6:]
return KN[-1]
print("Rec(50) =", Rec(50))
print("Kist(50) =", Kist(50))

Categories