Pyomo - is it possible to define conditional domains on a variable set? - python-3.x

I want to define an array of variables x, where some will be integer variables and some real (continuous) variables. For instance, I have three sets:
model = pyo.AbstractModel()
model.N = pyo.Set()
model.NL = pyo.Set()
model.NN = pyo.Set()
NL and NN are mutually exclusive sets whose union is N.
I would like to define the following variables:
model.x = pyo.Var(model.N, within = pyo.Integers) # if x in NL
model.x = pyo.Var(model.N, within = pyo.Reals) # if x in NN
I can of course rename xL and xN, but is it possible to have a single variable set x with subset dependent domains?
Thank you very much.

Yes. There are several ways to accomplish this:
The domain (or within) argument can take a rule:
def x_domain(m, i):
if i in m.NL:
return pyo.Integers
else:
return pyo.Reals
model.x = pyo.Var(model.N, within=x_domain)
You can set the Var to one domain and then update the domain after the fact:
model.x = pyo.Var(model.N, within=Reals)
for i in model.NL:
model.x[i].domain = Integers

Related

Is there a way to pass an equation symbolically into a function for sympy?

From this
import sympy as sp
x,y,z = sp.symbols("x y z")
sp.Ep(x,y/z)
To this
#varibles = array
#equation = ????
def solver(variables,equation):
#Looping through variables array and converting variables to sympy objects
for var in variables:
var = sp.symbols(var)
#Generate sympy Equation
equation = sp.Ep(equation)
variables = [x,y,z]
equation = x,y/z #invalid code
solver(variables,equation)
I'm creating a function that is able to take in an equation with x amount of variables and x-1 number of values then solve for the missing variable symbolically then return a numerical answer using the values provided.
I only included a small portion of code where I'm having trouble understanding how to pass through an equation. Any solutions or pointers would be greatly appericated. Thanks.
There are several layers of potential confusion here concerning Python variables and SymPy objects (Symbols) used for variables.
Here is an example of what you are saying:
# 3 variables
syms = x, y, z = var('x:z')
# 2 values
vals = {x:1, y:2}
# an equations
eq = Eq(x, y/z)
# solve for the missing value symbolically
missing = set(syms) - set(vals) # == {z}
solve(eq, missing)
[y/x]
# solve for the missing value after substituting in the known values
solve(eq.subs(vals))
[2]
You could make a solver to accept an equation and then specified values and figure out the missing one and return that value by doing something like this:
>>> def solver(eq, **vals):
... from sympy.core.containers import Dict
... from sympy.solvers.solvers import solve
... free = eq.free_symbols
... vals = Dict(vals)
... x = free - set(vals)
... if len(x) != 1:
... raise ValueError('specify all but one of the values for %s' % free)
... x = x.pop()
... return solve(eq.subs(vals), x, dict=True)
...
>>> solver(eq, x=1, z=2)
[{y: 2}]
Does that give you some ideas of how to continue?

Is there any method in DASK for creating parallelism while counting distinct values from a dataset

I have successfully extracted the count of a specific word from a dataset but, it is taking too much time. I am new to parallel programming.
How can I create parallelism in the following code:
df = dd.read_csv('crime.csv', encoding="ISO-8859-1")
distinct_values = df.YEAR.unique().compute()
counter = len(distinct_values)
values_count = {}
for i in distinct_values:
count = df[df.YEAR == i].YEAR.value_counts().compute()
values_count.update(count)
list = []
for x, y in values_count.items():
dict = {}
for i in x, y:
dict['name'] = x
dict['value'] = y
# print(dict)
list.append(dict)
# print(list)
maximum = max(distinct_values)
mininmum = min(distinct_values)
Maybe you're looking for a groupby aggregation like the following?
df.groupby("YEAR").count.compute()
Or, if you need to do this as many operations, you should at least use the dask.compute function with many inputs rather than call the .compute method many times.

Access to the local environment of a function from another function called by the previous one

Let's take a look at this piece of code:
def a(): # N = 0
string = "pizza"
# stuff
res_b = b(string)
def b(string): # N = 1
# stuff
res_c = c(string)
return res_c
def c(string): # N = 2
# stuff
return thing
I have a long file which has basically the same shape than that. I would like to remove the parameter str from the definitions and to make b and c able to read it directly (I mean not using an external dictionary) from the N-1 function. So I wonder if a function could read the local environment of the one which called it.
Does anything look like what I am looking for ?

Generate Range containing string and numbers

I'm trying to create a range between two variables. The variables contain string and number characters.
For example P9160-P9163 or P360-P369.
The P is not constant and could be any character(s)/multiple, but i'm trying to generate a list that would contain all values in between.
i tried with looking at ASCII characters but didn't work for me.
Any thoughts?
x = 'P9160'
y = 'P9163'
x = re.match(r"([a-z]+)([0-9]+)", x, re.I)
y = re.match(r"([a-z]+)([0-9]+)", y, re.I)
for i in range(int(x.groups()[1]), int(y.groups()[1])+1):
print("{}{}".format(x.groups()[0], i))
Using a reusable regex pattern, and a generator expression, does certainly improves the code performance.
import re
x = 'P9160'
y = 'P9173'
# resuable regex pattern
regex = re.compile(r"([a-zA-Z]+)(\d+)")
x, y = regex.match(x), regex.match(y)
# generator expression
xy = (x.groups()[0]+str(i) for i in range(int(x.groups()[1]), int(y.groups()[1])+1))
# list of all values from the generator
print(list(xy))

Length of list returns length of list name

Import random
set_list_1 = ["one"]
set_list_2 = ["two"]
number = random.choice(range(1, 3))
chosen_list = "set_list_" + str(number)
print(len(chosen_list))
Returns 10 instead of 1
How do i get it to return the length of the list instead of the length of the lists name?
This is a bad idea. You should use lists.
Try this;
Import random
set_list = [[], ["one"], ["two"]]
number = random.choice(range(1, 3))
chosen_list = set_list[number]
print(len(chosen_list))
If you absolutely want to access variables dynamically;
Import random
set_list_1 = ["one"]
set_list_2 = ["two"]
number = random.choice(range(1, 3))
chosen_list = eval("set_list_" + str(number))
print(len(chosen_list))
To answer the question per se, chosen_list isn't the list, but a string. So then len() returns the length of a string, that is to say, the number of characters in it.
If you want to access the list instead by it's name :
As stated by the other answer and the comment, you could first use eval for this.
You can also use the locals() (or maybe globals() if your lists are in the global scope) (depending on your current scope) dictionnary to avoid eval. These functions return a dictionnary containing everything you can access in the global (well the module scope to be accurate) / local scope.
import random
set_list_1 = ["one"]
set_list_2 = ["two"]
number = random.choice(range(1, 3))
chosen_list = locals()["set_list_" + str(number)]
print(len(chosen_list))
It's probably faster and safer than eval.
Or, you can register your lists in a dict, mapping the variable name to the ̀€list. For instance, you can do something like this :
import random
registry = {}
registry["set_list_1"] = ["one"]
registry["set_list_2"] = ["two"]
number = random.choice(range(1, 3))
chosen_list = registry["set_list_" + str(number)]
print(len(chosen_list))
This is without a doubt even faster than using locals(), and is actually a common pattern in python. Here is a classic example of this, involving metaclasses.
Also, you can do this if you don't actually need the variables names for any other reason :
import random
registry = []
registry.append(["one"])
registry.append(["two"])
chosen_list = random.choice(registry)
print(len(chosen_list))

Resources