Absolute value function not recognized as Disciplined Convex Program (CVXPY) - python-3.x

I am trying to run the following optimization using CVXPY:
import cvxpy as cp
import numpy as np
weights_vec = cp.Variable(10)
er_vec = cp.Parameter(10, value=np.random.randn(10))
prev_h_vec = cp.Parameter(10, value=np.ones(10))
tcost_vec = cp.Parameter(10, value=[0.03]*10)
objective = cp.Maximize(weights_vec # er_vec - tcost_vec # cp.abs(weights_vec - prev_h_vec))
prob = cp.Problem(objective)
prob.solve()
However, I get the following error:
cvxpy.error.DCPError: Problem does not follow DCP rules. Specifically:
The objective is not DCP. Its following subexpressions are not:
param516 # abs(var513 + -param515)
The absolute function is convex. Hence, I am not quite sure why CVX is throwing an error for the absolute value function in the objective.

DCP-ness depends on the sign of tcost_vec.
As this is a (unconstrained) parameter it's not okay.
Both of the following will work:
# we promise it's nonnegative
tcost_vec = cp.Parameter(10, value=[0.03]*10, nonneg=True)
# it's fixed and can by analyzed
tcost_vec = np.array([-0.03]*10)
Given the code as posted, there is not reason to use parameters (yet).

Related

Python: Why my module didn't instantiate an object via exec() statement?

I created my own version of GridSearchCV module from sklearn.model_selection library. My version includes iterating through each parameter one by one instead of looking for all possible combinations. For example for a SVR model, if we have three parameters defined as follows:
{
'gamma' : np.arange(0.0, 1.0, 0.1),
'C': np.arange(1, 10, 1),
'epsilon': np.arange(0.0, 1.0, 0.1)
}
The algorithm would in the first turn find one best gamma coefficient (out of ten). Then it moves to assigning C parameter with given value of gamma. After ten iterations it moves to epsilon and assigns optimal epsilon value with given set of [gamma, C] parameters. This gives us in total 30 combinations to check instead of 1000 (10*10*10).
I'd like to import my opt_grid_search object into my projects, like below:
from own_udf_functions import show_description, opt_grid_search
The code of the object begins with dynamic statement that creates object that is going to be optimized:
exec_string = 'opt_object = ' + object_name + '(' + def_params + ')'
which returns for example:
opt_object = SVR(kernel = 'rbf')
However, when I try to use the code in another script as below:
opt_grid_search(object_name, params_set, X_train, y_train, X_test, y_test,
cross_val = 2, def_params = def_params)
following error appears:
*File "C:\Users\Marek\Desktop\Python\Github\Kernele\Kaggle Competitions\own-udf-
functions\own_udf_functions.py", line 40, in opt_grid_search
opt_object.fit(X_train,y_train)
NameError: name 'opt_object' is not defined*
It seems that opt_grid_search function didn't execute the following line of code:
opt_object = SVR(kernel = 'rbf')
and the object named opt_object wasn't actually created.
I think it has to do with classes, but I would like to ask you to help me better understand what actually happened in this error. I think it is a crucial knowledge that would help me a lot write more 'pythonic' codes instead of defining all of the functions in every single code.
Secondly, please let me know if such optimization makes sense as well or is it needed for the GridSearch to go through all possible combinations.
I tried to keep this description as short as possible, however if you would like to see / need it for the reference, my code is accessible below:
https://github.com/markoo26/own-udf-functions
The issue here is the exec function and the namespace/scope in which it operates. I'm struggling to get my head around this myself but essentially exec() doesn't work for assignment used inside a function in this way. The easiest workaround is to use eval() instead which explcitly returns an object. So end up with something like:
exec_string = object_name + '(' + def_params + ')'
opt_object = eval(exec_string)

What initializer does 'uniform' use?

Keras offers a variety of initializers for weights and biases. Which one does 'uniform' use?
I would think it would be RandomUniform, but this is not confirmed in the documentation, and I reached a dead-end in the source-code: the key 'uniform' is used as a global variable within the module, and I cannot find where the variable uniform is set.
One other way to confirm this is to look at the initializers source code:
# Compatibility aliases
zero = zeros = Zeros
one = ones = Ones
constant = Constant
uniform = random_uniform = RandomUniform
normal = random_normal = RandomNormal
truncated_normal = TruncatedNormal
identity = Identity
orthogonal = Orthogonal
I think today's answer is better, though.
Simpler solution:
From the interactive prompt,
import keras
keras.initializers.normal
# Out[3]: keras.initializers.RandomNormal
keras.initializers.uniform
# Out[4]: keras.initializers.RandomUniform
Original post:
Running the debugger to the deserialize method in initializers.py
and examining
globals()['uniform']
Shows that the value is indeed
<class 'keras.initializers.RandomUniform'>
Similarly, 'normal' is shown in the debugger to be <class 'keras.initializers.RandomNormal'>.
Note that uniform often works better than normal, and the theoretical advantages of one over the other is not clear.

Abaqus Python script -- Reading 'TENSOR_3D_FULL' data from *.odb file

What I want: strain values LE11, LE22, LE12 at nodal points
My script is:
#!/usr/local/bin/python
# coding: latin-1
# making the ODB commands available to the script
from odbAccess import*
import sys
import csv
odbPath = "my *.odb path"
odb = openOdb(path=odbPath)
assembly = odb.rootAssembly
# count the number of frames
NumofFrames = 0
for v in odb.steps["Step-1"].frames:
NumofFrames = NumofFrames + 1
# create a variable that refers to the reference (undeformed) frame
refFrame = odb.steps["Step-1"].frames[0]
# create a variable that refers to the node set ‘Region Of Interest (ROI)’
ROINodeSet = odb.rootAssembly.nodeSets["ROI"]
# create a variable that refers to the reference coordinate ‘REFCOORD’
refCoordinates = refFrame.fieldOutputs["COORD"]
# create a variable that refers to the coordinates of the node
# set in the test frame of the step
ROIrefCoords = refCoordinates.getSubset(region=ROINodeSet,position= NODAL)
# count the number of nodes
NumofNodes =0
for v in ROIrefCoords.values:
NumofNodes = NumofNodes +1
# looping over all the frames in the step
for i1 in range(NumofFrames):
# create a variable that refers to the current frame
currFrame = odb.steps["Step-1"].frames[i1+1]
# looping over all the frames in the step
for i1 in range(NumofFrames):
# create a variable that refers to the strain 'LE'
Str = currFrame.fieldOutputs["LE"]
ROIStr = Str.getSubset(region=ROINodeSet, position= NODAL)
# initialize list
list = [[]]
# loop over all the nodes in each frame
for i2 in range(NumofNodes):
strain = ROIStr.values [i2]
list.insert(i2,[str(strain.dataDouble[0])+";"+str(strain.dataDouble[1])+\
";"+str(strain.dataDouble[3]))
# write the list in a new *.csv file (code not included for brevity)
odb.close()
The error I get is:
strain = ROIStr.values [i2]
IndexError: Sequence index out of range
Additional info:
Details for ROIStr:
ROIStr.name
'LE'
ROIStr.type
TENSOR_3D_FULL
OIStr.description
'Logarithmic strain components'
ROIStr.componentLabels
('LE11', 'LE22', 'LE33', 'LE12', 'LE13', 'LE23')
ROIStr.getattribute
'getattribute of openOdb(r'path to .odb').steps['Step-1'].frames[1].fieldOutputs['LE'].getSubset(position=INTEGRATION_POINT, region=openOdb(r'path to.odb').rootAssembly.nodeSets['ROI'])'
When I use the same code for VECTOR objects, like 'U' for nodal displacement or 'COORD' for nodal coordinates, everything works without a problem.
The error happens in the first loop. So, it is not the case where it cycles several loops before the error happens.
Question: Does anyone know what is causing the error in the above code?
Here the reason you get an IndexError. Strains are (obviously) calculated at the integration points; according to the ABQ Scripting Reference Guide:
A SymbolicConstant specifying the position of the output in the element. Possible values are:
NODAL, specifying the values calculated at the nodes.
INTEGRATION_POINT, specifying the values calculated at the integration points.
ELEMENT_NODAL, specifying the values obtained by extrapolating results calculated at the integration points.
CENTROID, specifying the value at the centroid obtained by extrapolating results calculated at the integration points.
In order to use your code, therefore, you should get the results using position= ELEMENT_NODAL
ROIrefCoords = refCoordinates.getSubset(region=ROINodeSet,position= ELEMENT_NODAL)
With
ROIStr.values[0].data
You will then get an array containing the 6 independent components of your tensor.
Alternative Solution
For reading time series of results for a nodeset, you can use the function xyPlot.xyDataListFromField(). I noticed that this function is much faster than using odbread. The code also is shorter, the only drawback is that you have to get an abaqus license for using it (in contrast to odbread which works with abaqus python which only needs an installed version of abaqus and does not need to get a network license).
For your application, you should do something like:
from abaqus import *
from abaqusConstants import *
from abaqusExceptions import *
import visualization
import xyPlot
import displayGroupOdbToolset as dgo
results = session.openOdb(your_file + '.odb')
# without this, you won't be able to extract the results
session.viewports['Viewport: 1'].setValues(displayedObject=results)
xyList = xyPlot.xyDataListFromField(odb=results, outputPosition=NODAL, variable=((
'LE', INTEGRATION_POINT, ((COMPONENT, 'LE11'), (COMPONENT, 'LE22'), (
COMPONENT, 'LE33'), (COMPONENT, 'LE12'), )), ), nodeSets=(
'ROI', ))
(Of course you have to add LE13 etc.)
You will get a list of xyData
type(xyList[0])
<type 'xyData'>
Containing the desired data for each node and each output. It size will therefore be
len(xyList)
number_of_nodes*number_of_requested_outputs
Where the first number_of_nodes elements of the list are the LE11 at each nodes, then LE22 and so on.
You can then transform this in a NumPy array:
LE11_1 = np.array(xyList[0])
would be LE11 at the first node, with dimensions:
LE.shape
(NumberTimeFrames, 2)
That is, for each time step you have time and output variable.
NumPy arrays are also very easy to write on text files (check out numpy.savetxt).

(python) solving for roots of equation that includes probabilistic distribution

I am quite new to this, but I need solution to mathematical problem, which involves finding roots of a function, that involves cumulative density function (several).
For simplicity I tried to code similar procedure, but with as simple function as possible but even that doesn't work.
Would anyone tell me please what am I doing wrong?
from scipy.optimize import fsolve
import sympy as sy
import numpy as np
from scipy.stats import norm
y=sy.Symbol('y')
def cdf(x):
cdf_norm=norm.cdf(x,100,20)
return cdf_norm
result=fsolve(y**2-14*y+7-cdf(y))
print(result)
The problem seems to be that fsolve requires that the first argument is a function. However, you passed it an expression which gets evaluated to some value, however, the expression has a variable name y which is undefined, so the interpreter throws a NameError. Also, it will require one more argument, an ndarray containing the estimates to the roots. So, one easy solution is to define another function:
def f(y):
return y**2 - 14*y + 7 - cdf(y)
result = fsolve(f, np.array([1,0])
print(result)
I get the following result:
array([ 0.51925928, 0.51925928])

Scikit-Learn Multiple Regression Fails with ElasticNetCV

According to the documentation and other SO questions, ElasticNetCV accepts multiple output regression. When I try it, though, it fails. Code:
from sklearn import linear_model
import numpy as np
import numpy.random as rnd
nsubj = 10
nfeat_train = 5
nfeat_predict = 20
x = rnd.random((nsubj, nfeat_train))
y = rnd.random((nsubj, nfeat_predict))
lm = linear_model.LinearRegression()
lm.fit(x,y) # works
el = linear_model.ElasticNetCV()
el.fit(x,y) # fails
Error message:
ValueError: Buffer has wrong number of dimensions (expected 1, got 2)
This is with scikit-learn version 0.14.1. Is this a mismatch between the documentation and implementation?
You may want to take a look at sklearn.linear_model.MultiTaskElasticNetCV. But beware, this object assumes that your multiple targets share features. Thus, a feature is either active for all tasks (with variable activation for each, which can be small), or active for none of them. Before using this object, make sure this is the functionality you need.

Resources