Modify variables inside a for loop within a function - scope

In the following function
function foo(g)
a = [g * sqrt(i) for i in 1:4]
b = [g * i ^ 2 for i in 1:4]
for j in [a, b]
j /= sum(j)
println(j)
end
return a, b
end
foo(2)
I expect the printed values to agree with the returned values. Instead, the returned values do not reflect the division performed in line 5. The result is
[0.16270045344786252, 0.2300931878702196, 0.2818054517861928, 0.32540090689572504]
[0.03333333333333333, 0.13333333333333333, 0.3, 0.5333333333333333]
([2.0, 2.8284271247461903, 3.4641016151377544, 4.0], [2, 8, 18, 32])
I saw a discussion on the Julia forum where a user was having similar issues in a REPL session. But the suggested solution was to either wrap the for loop in a function, which I have already done, or to write the equivalent of global j \= sum(j) in place of line 5, which doesn't change the result.
Similar suggestions appear in this SE question: Changing variable in loop [Julia]
How can I batch modify a and b before returning them?

You need to vectorize the division and use a Float64 arg:
function foo(g)
a = [g * sqrt(i) for i in 1:4]
b = [g * i ^ 2 for i in 1:4]
for j in [a, b]
j ./= sum(j)
println(j)
end
return a, b
end
And now:
julia> foo(2.0)
[0.16270045344786252, 0.2300931878702196, 0.2818054517861928, 0.32540090689572504]
[0.03333333333333333, 0.13333333333333333, 0.3, 0.5333333333333333]
([0.16270045344786252, 0.2300931878702196, 0.2818054517861928, 0.32540090689572504], [0.03333333333333333, 0.13333333333333333, 0.3, 0.5333333333333333])
Now the tricky explanation
when you pass an Int argument than in your code a is a Vector of Float64s and b is a Vector of Ints. Look what happens when you combine them:
julia> [[1.0,2.0],[1,2]]
2-element Array{Array{Float64,1},1}:
[1.0, 2.0]
[1.0, 2.0]
Julia brings all data to common Float64 and in your case you loose the reference information!
j =/ sum(j) is a linear algebra division and it allocates a new object. You want to have an element wise operation so you needed to vectorize.

Related

How does this code of list comprehension with multiple variables assigned works

I have a list of strings. I need to parse and convert the string into floats and use that for a calculation.
After multiple attempts, I figured out the easiest way to do this.
List=["1x+1y+0","1x-1y+0","1x+0y-3","0x+1y-0.5"]
I need to extract the numerical coefficients of x and y
I used:
for coef in re.split('x|y', line):
float(coeff)
This was not serving the purpose and then I found out that,
for line in list:
a,b,c = [float(coef) for coef in re.split('x|y', line)]
this code works.
If I do
a=[float(coeff) for coeff in re.split('x|y',lines)]
then a is a list with coefficients of the line
[1.0, 1.0, 0.0]
[1.0, -1.0, 0.0]
[1.0, 0.0, -3.0]
[0.0, 1.0, -0.5]
However, I am struggling to understand the logic. Here we used list comprehension. How can we assign multiple variables in a list comprehension? Is the way it works as follows:
for each string element in the list, it splits the string and converts into float. And then assign the three numbers resulting from the operation to three numbers.
But how is that if we assign only one variable it is a list, but if we assign multiple variables the type is changing?
I am sorry if the question is too basic. Am new to python hence the doubt.
a, b, c = x is called sequence unpacking. It is (almost) equivalent to:
a = x[0]
b = x[1]
c = x[2]
So a,b,c = [float(coef) for coef in re.split('x|y', line)] actually means:
x = [float(coef) for coef in re.split('x|y', line)]
a = x[0]
b = x[1]
c = x[2]
But a = x is not unpacking - it's just normal assignment: it makes a reference x. The difference: in the first case you assign a list to three variables, each "gets" one item of the list. In the second case, you assign a list to one variable and that variable "gets" the whole list. Assigning a list of three numbers to two variables (a, b = [1, 2, 3]) is invalid - you get an error message saying that there are too many values to unpack.

user def. function modifying argument though it is not supposed to

Just for practice, I am using nested lists (for exaple, [[1, 0], [0, 1]] is the 2*2 identity matrix) as matrices. I am trying to compute determinant by reducing it to an upper triangular matrix and then by multiplying its diagonal entries. To do this:
"""adds two matrices"""
def add(A, B):
S = []
for i in range(len(A)):
row = []
for j in range(len(A[0])):
row.append(A[i][j] + B[i][j])
S.append(row)
return S
"""scalar multiplication of matrix with n"""
def scale(n, A):
return [[(n)*x for x in row] for row in A]
def detr(M):
Mi = M
#the loops below are supossed to convert Mi
#to upper triangular form:
for i in range(len(Mi)):
for j in range(len(Mi)):
if j>i:
k = -(Mi[j][i])/(Mi[i][i])
Mi[j] = add( scale(k, [Mi[i]]), [Mi[j]] )[0]
#multiplies diagonal entries of Mi:
k = 1
for i in range(len(Mi)):
k = k*Mi[i][i]
return k
Here, you can see that I have set M (argument) equal to Mi and and then operated on Mi to take it to upper triangular form. So, M is supposed to stay unmodified. But after using detr(A), print(A) prints the upper triangular matrix. I tried:
setting X = M, then Mi = X
defining kill(M): return M and then setting Mi = kill(M)
But these approaches are not working. This was causing some problems as I was trying to use detr(M) in another function, problems which I was able to bypass, but why is this happening? What is the compiler doing here, why was M modified even though I operated only on Mi?
(I am using Spyder 3.3.2, Python 3.7.1)
(I am sorry if this question is silly, but I have only started learning python and new to coding in general. This question means a lot to me because I still don't have a deep understanding of this language.)
See python documentation about assignment:
https://docs.python.org/3/library/copy.html
Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other.
You need to import copy and then use Mi = copy.deepcopy(M)
See also
How to deep copy a list?

normalize vector with respect to the infinity norm python 3

This is the code I'm trying to write im new to coding so im sure im way off any help would be great. Thank you in advance.
Write a function normalize(vector) which takes in a vector and returns the normalized vector with respect to the infinity norm. i.e. (1/infNorm(vector)) * vector.
def normalize(vector):
infNorm(vector) = abs(vector[0])
for i in vector:
if abs(i) > norm:
infNorm(vector) = abs(i)
finalvector = (1/infNorm(vector)) * vector
return finalvector
vector = [2, 5, 7]
print(normalize(vector))
You are confusing function call parameters using () with sequence indices []. By sequence, I mean a Python sequence, which includes things like tuples and lists. Here, you're using a list as a vector. (You could also use tuples, but only if you don't plan to modify them. So we'll stick with lists, for generality and simplicity.)
Also, you need two loops: one to find the norm, and one to apply it.
def infnorm(vector):
norm = 0
for i in range(len(vector)):
if abs(vector[i]) > norm:
norm = vector[i]
return norm
def normalize(vector):
norm = infnorm(vector)
return [v/norm for v in vector]
vector = [2, 5, 7]
print(normalize(vector))
Results:
[0.2857142857142857, 0.7142857142857143, 1.0]
Note that I didn't take the absolute value of each element before normalizing it. I'm no vector wizard, so that might be wrong, but I'm guessing that the normalized vector can have negative values.
The last tricky bit, the return value for normalize(vector), is called a "list comprehension". It's a nifty python trick to build a list using a formula. They look odd at first, but with a little practice it gets easy and they're quite precise and clear. Check it out.
If you are going to use a for loop to find the maximum value of an array in python, I'd suggest splitting the normalize function in two functions, one to get the infinity norm and another one to calculate the vector, as such:
def infNorm(vector):
norm = vector[0]
for element in vector:
if norm < abs(element):
norm = abs(element)
return norm
def normalize(vector):
norm = infNorm(vector)
new_vector = []
for element in vector:
new_vector.append((1.0/norm)*element)
return new_vector
Otherwise, you could use the max() built-in function from python, with such function, the code would look like this:
def normalize(vector):
norm = abs(max(vector, key=abs))
new_vector = []
for element in vector:
new_vector.append((1.0/norm)*element)
return new_vector
By the way, when you have a symbol, followed by parenthesis, you are trying to invoke a function.So, when you do infNorm(vector) = abs(vector[0]), you are trying to assign a value to a function call, which will result in a syntax error. The correct way would be just infNorm = abs(vector[0]).
The infinity norm is the sum of the absolute values of the elements. For instance, here is what sagemath offers for one vector, for the infinity norm, the 2-norm and the 1-norm.
In general to normalise a vector according to a norm you divide each of its elements by its length in that norm.
Then this can be expressed in Python in this way:
>>> vec = [-2, 5, 3]
>>> inf_norm = sum([abs(v) for v in vec])
>>> inf_norm
10
>>> normalised_vec = [v/inf_norm for v in vec]
>>> normalised_vec
[-0.2, 0.5, 0.3]

how to change the type of constraint's arguments in ortools

I don't know my question is possible or not. I am using ortools to solve an optimization problem and I know in the part of conditions the argument should be defined in double type, like this:
constraints[i] = solver.Constraint(0.0 , 10,0)
But my problem is that, I don't want to use this type of argument in creating conditions. For example I want to have a list.
So I wrote this in my code:
constraints[i] = solver.Constraint([1,2,3,...])
And I got this error:
return _pywraplp.Solver_Constraint(self, *args)
NotImplementedError: Wrong number or type of arguments for overloaded
function 'Solver_Constraint'.
Possible C/C++ prototypes are:
operations_research::MPSolver::MakeRowConstraint(double,double)
operations_research::MPSolver::MakeRowConstraint()
operations_research::MPSolver::MakeRowConstraint(double,double,std::string
const &)
operations_research::MPSolver::MakeRowConstraint(std::string const &)
Is there any way to change the type of condition's argument?
My Assumptions
your constraint expression is "a sum of some lists", meaning something along the lines of what the NumPy library does: e.g., if you have two lists of values, [1, 2, 3] and [4, 5, 6], their sum would be element-wise, s.t. [1, 2, 3] + [4, 5, 6] = [1+4, 2+5, 3+6] = [5, 7, 9].
your "list constraint" is also element-wise; e.g., [x1, x2, x3] <= [1, 2, 3] means x1 <= 1, x2 <= 2 and x3 <= 3.
you're using the GLOP Linear Solver. (Everything I say below applies to the ILP/CP/CP-SAT solvers, but some of the particular method names/other details are different.)
My Answer
The thing is, ortools only lets you set scalar values (like numbers) as variables; you can't make a "list variable", so to speak.
Therefore, you'll have to make a list of scalar variables that effectively represents the same thing.
For example, let's say you wanted your "list variable" to be a list of values, each one subjected to a particular constraint which you have stored in a list. Let's say you have a list of upper bounds:
upper_bounds = [1, 2, 3, ..., n]
And you have several lists of solver variables like so:
vars1 = [
# variable bounds here are chosen arbitrarily; set them to your purposes
solver.NumVar(0, solver.infinity, 'x{0}'.format(i))
for i in range(n)
]
vars2 = [...] # you define any other variable lists in the same way
Then, you would make a list of constraint objects, one constraint for each upper bound in your list:
constraints = [
solver.Constraint(0, ubound)
for ubound in upper_bounds
]
And you insert the variables into your constraints however is dictated for your problem:
# Example expression: X1 - X2 + 0.5*X3 < UBOUND
for i in range(n):
constraints[i].SetCoefficient(vars1[i], 1)
constraints[i].SetCoefficient(vars2[i], -1)
constraints[i].SetCoefficient(vars3[i], 0.5)
Hope this helps! I recommend taking (another, if you already have) look at the examples for your particular solver. The one for GLOP can be found here.

How to make a difference between two function close to zero through iteration?

I need to construct a loop (simulation) that will iterate a certain number of times and display a value of warrant once the new firm value is close to the guess firm value. Specifically, the idea is to start out with a guess for the firm value (for example the stock price multiplied by the number of shares). Then you value the warrant as a call option (the code below) on this value multiplied by dilution factor, using the same volatility as the vol of the share price. You recompute then the value of the firm (number of shares times share price plus number of warrants times warrant price). This value will be different from the value of the firm you started with. Then you redo the procedure and after a few iterations you will see that the difference in values of the firm tends to zero. For this, I have a following code, but what I get is the following:
TypeError: 'int' object is not subscriptable
Please, help me to figure out the error given the code below:
def bsm_call_value(S0, K, T, r, sigma):
from math import log, sqrt, exp
from scipy import stats
S0 = float(S0)
d1 = (log(S0 / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
d2 = (log(S0 / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
value = (S0 * stats.norm.cdf(d1, 0.0, 1.0) - K * exp(-r * T) *stats.norm.cdf(d2, 0.0, 1.0))
return value
def warrant_1unobservable(S0, K, T, r, sigma, k, N, M, Iteration):
for i in range(1, Iteration):
Guess_FirmValue = S0*N
dilution = N/(N +k*M)
warrant[i] = bsm_call_value(Guess_FirmValue[i]/N,100,1,0.1,0.2)*dilution
New_FirmValue[i] = Guess_FirmValue[i]+ warrant[i]
Guess_FirmValue[i] - New_FirmValue[i] == 0
return warrant
print(warrant_1unobservable(100,100,1,0.1,0.2,1,100,10, 1000))
I'm not really a python expert and I'm not familiar with the algorithm you're using, but I'll point out a few things that could be causing the issue.
1) In warrant_1observable, you first assign Guess_FirmValue a scalar value (since both S0 and N are scalars the way you call the function), and then you try to access it with an index as Guess_FirmValue[i]. My guess would be that this is causing the error you displayed, since you're trying to index/subscript a variable that, based on your function input values, would be an integer.
2) Both warrant[i] and New_FirmValue[i] are attempts to assign values to an indexed position in a list, but nowhere do you initialize these variables as lists. Lists in python are initialized as warrant = []. Also, it's likely that you would have to either a) pre-allocate the lists to the correct size based on the Iteration or b) use append to push new values onto the back of the list.
3) Guess_FirmValue[i] - New_FirmValue[i] == 0 is a vacuous line of code. All this does is evaluate to either true or false, while performing no other operation. I imagine you're trying to check if the values are equal and then return, but that won't happen even if you stick this in an if statement. It is extremely unlikely that the floating-point representation of the values will ever be identical. This kind of break is accomplished by checking if the difference of the values is below some tolerance, which is set to be a very small number. Ex.:
if (abs(Guess_FirmValue[i] - New_FirmValue[i]) <= 1e-9):
return ...

Resources