Constraint that calls for the previous set member - pyomo

I have the following type of constraint:
def C_rule(model,t-1):
return x[t]<=y[t-1]
model.C=Constraint(model.t,rule=C_rule)
But set model.t elements are string type so i cannot access the previous element this way.
Is there a way to do that ?

If you declare your Set to be ordered then you can do something like this:
m.s = Set(initialize=['A','B','C'], ordered=True)
m.v = Var(m.s)
def _c_rule(m, i):
if i == 'A':
return Constraint.Skip
return m.v[i] <= m.v[m.s.prev(i)]
m.c = Constraint(m.s, rule=_c_rule)
# Or the opposite way
def _c2_rule(m, i):
if i == 'C':
return Constraint.Skip
return m.v[m.s.next(i)] <= m.v[i]
m.c2 = Constraint(m.s, rule=_c2_rule)

Related

(In Python 3.8) filling in lists to mantain them similar in length and average?

I need to allocate some values in 3 individual lists.
The values are generated on the fly but all included in the 0-6 range.
The point is that these values should be put in the three lists so that the average of each list does not differ so much from the others. The lists also need to be similar in length.
So the goal would be to progressively fill these lists to maintain, as much as possible, a uniform average value and size for all of them.
As I didn't found any built-in function to do this, I have implemented a code which keeps track of lists length and tries to keep them as close as possible in their average value. You can play with it and improve it to better fit your case.
class Data:
def __init__(self):
"""Init the three lists."""
self.a = []
self.b = []
self.c = []
#staticmethod
def get_average(data: list):
"""Get average value of a list."""
try:
return sum(data) / len(data)
except ZeroDivisionError:
return 0
def get_shortest(self):
"""Return list with the shortest length."""
shortest_length = min(len(self.a), len(self.b), len(self.c))
if len(self.a) == shortest_length:
return self.a
elif len(self.b) == shortest_length:
return self.b
else:
return self.c
def get_smallest(self):
"""Return list with the smallest average value."""
smallest_average = min(self.get_average(self.a), self.get_average(self.b), self.get_average(self.c))
if self.get_average(self.a) == smallest_average:
return self.a
elif self.get_average(self.b) == smallest_average:
return self.b
else:
return self.c
def get_highest(self):
"""Return list with the highest average value."""
highest_average = max(self.get_average(self.a), self.get_average(self.b), self.get_average(self.c))
if self.get_average(self.a) == highest_average:
return self.a
elif self.get_average(self.b) == highest_average:
return self.b
else:
return self.c
def add_number(self, num):
"""Add number to one of the lists."""
shortest = self.get_shortest()
smallest = self.get_smallest()
highest = self.get_highest()
# Lists must not differ by more than two elements
if len(smallest) - len(shortest) >= 2 or len(highest) - len(shortest) >= 2:
shortest.append(num)
else:
# Test if the number uppers the smallest average
initial_avg = self.get_average(smallest)
smallest.append(number)
final_avg = self.get_average(smallest)
if final_avg > initial_avg:
return
else:
smallest.pop()
# Test if the number lowers the highest average
initial_avg = self.get_average(highest)
highest.append(number)
final_avg = self.get_average(highest)
if final_avg < initial_avg:
return
else:
highest.pop()
# Last resort
shortest.append(num)
d = Data()
value = input("Add number: ")
while value != 'e':
try:
number = int(value)
except ValueError:
break
d.add_number(number)
print(f"List a: {d.a}, avg. {d.get_average(d.a)}")
print(f"List b: {d.b}, avg. {d.get_average(d.b)}")
print(f"List c: {d.c}, avg. {d.get_average(d.c)}")
value = input("Add number:")

Django REST Framework: custom serializer variables

I am using a model serializer (many=True) in Django Rest Framework where I want to return booking_color and text_color properties in JSON in order to display a booking instance on a calendar plugin. Both properties depend on job_type and job_status variables that are calculated (using foreign keys, etc.). I want to run a calculation for those variables when a particular instance gets initialized (in the init method) so that both calculated values then become available for both method fields (booking_color and text_color). The init method, however, passes entire queryset as 'inst' and so I can't do instance-specific calculations. What would be the best way around this? I have previously ran those calculations in the first method in the list ('get_booking_color' in this case) and it works, but it isn't very elegant and I am not sure if I am supposed to do it.
class CalendarView(serializers.ModelSerializer):
booking_color = serializers.SerializerMethodField()
text_color = serializers.SerializerMethodField()
def __init__(self, inst):
self.job_type = [complicated calculation that depends on inst values]
self.invoice_status = [complicated calculation that depends on inst values]
def get_booking_color(self, inst):
if self.invoice_status == 1:
if self.job_type == 1:
return "#000000"
elif self.job_type == 2:
return "#f1c40f"
elif self.job_type == 3:
return "#FFFFF"
else:
return '#faase4'
def get_text_color(self, inst):
if self.invoice_status == 2:
if self.job_type == 1:
return "#BBFF33"
elif self.job_type == 2:
return "#272844"
elif self.job_type == 3:
return "#2c0716"
else:
return '#FFFFF'
I believe you need to modify your __init__() call to this:
def __init__(self, instance=None, data=empty, **kwargs):
self.job_type = [complicated calculation that depends on inst values]
self.invoice_status = [complicated calculation that depends on inst values]
super(CalendarViewSerializer, self).__init__(**kwargs)
I'd also recommend renaming your class to CalendarViewSerializer so it is not confused with anythign else.
You may also be able to move around overriding the __init__() call by passing in those calculations via the context - then working with them from there...e.g.,
serializer = CalendarViewSerializer(data=request.data, context={'job_type': ..., 'invoice_status': ...})
class CalendarViewSerializer(serializers.ModelSerializer):
booking_color = serializers.SerializerMethodField()
text_color = serializers.SerializerMethodField()
def get_booking_color(self, inst):
if self.context['invoice_status'] == 1:
if self.context['job_type'] == 1:
return "#000"
elif self.context['job_type'] == 2:
return "#f1c40f"
elif self.context['job_type'] == 3:
return "#fff"
else:
return '#faase4'
def get_text_color(self, inst):
if self.context['invoice_status'] == 2:
if self.context['job_type'] == 1:
return "#bbff33"
elif self.context['job_type'] == 2:
return "#272844"
elif self.context['job_type'] == 3:
return "#2c0716"
else:
return '#fff'
As an extra bonus, I believe you could use some sort of dict()/{} object to return the hex codes from a key lookup, rather than the if elseif elseif else statements.

Pyomo: Extending the "car ampl example" with additional constraints

After having seen the nice implementation of the "ampl car example" in Pyomo repository, I would like to keep extending the problem with new features and constraints, but I have found the next problems during development. Is someone able of fix them?
1) Added new constraint "electric car": Now the acceleration is limited by adherence until a determined speed and then constant power model is used. I am not able of implement this constraint as i would think. It is commented in the, but Pyomo complains about that a constraint is related to a variable. (now Umax depends of the car speed).
2) Added new comfort acceleration and jerk constraints. It seems they are working right, but should be nice if a Pyomo guru supervise them and tell me if they are really implemented in the correct way.
3) About last one, in order of reducing verbosity. Is there any way of combine accelerationL and accelerationU in a unique constraint? Same for jerkL and jerkU.
4) The last feature is a speed limit constraint divided in two steps. Again, I am not able of getting it works, so it is commented in code. Does anybody dare to fix it?
# Ampl Car Example (Extended)
#
# Shows how to convert a minimize final time optimal control problem
# to a format pyomo.dae can handle by removing the time scaling from
# the ContinuousSet.
#
# min tf
# dx/dt = v
# dv/dt = u - R*v^2
# x(0)=0; x(tf)=L
# v(0)=0; v(tf)=0
# -3 <= u <= 1 (engine constraint)
#
# {v <= 7m/s ===> u < 1
# u <= { (electric car constraint)
# {v > 7m/s ===> u < 1*7/v
#
# -1.5 <= dv/dt <= 0.8 (comfort constraint -> smooth driving)
# -0.5 <= d2v/dt2 <= 0.5 (comfort constraint -> jerk)
# v <= Vmax (40 kmh[0-500m] + 25 kmh(500-1000m])
from pyomo.environ import *
from pyomo.dae import *
m = ConcreteModel()
m.R = Param(initialize=0.001) # Friction factor
m.L = Param(initialize=1000.0) # Final position
m.T = Param(initialize=50.0) # Estimated time
m.aU = Param(initialize=0.8) # Acceleration upper bound
m.aL = Param(initialize=-1.5) # Acceleration lower bound
m.jU = Param(initialize=0.5) # Jerk upper bound
m.jL = Param(initialize=-0.5) # Jerk lower bound
m.NFE = Param(initialize=100) # Number of finite elements
'''
def _initX(m, i):
return m.x[i] == i*m.L/m.NFE
def _initV(m):
return m.v[i] == m.L/50
'''
m.tf = Var()
m.tau = ContinuousSet(bounds=(0,1)) # Unscaled time
m.t = Var(m.tau) # Scaled time
m.x = Var(m.tau, bounds=(0,m.L))
m.v = Var(m.tau, bounds=(0,None))
m.u = Var(m.tau, bounds=(-3,1), initialize=0)
m.dt = DerivativeVar(m.t)
m.dx = DerivativeVar(m.x)
m.dv = DerivativeVar(m.v)
m.da = DerivativeVar(m.v, wrt=(m.tau, m.tau))
m.obj = Objective(expr=m.tf)
def _ode1(m, i):
if i==0:
return Constraint.Skip
return m.dt[i] == m.tf
m.ode1 = Constraint(m.tau, rule=_ode1)
def _ode2(m, i):
if i==0:
return Constraint.Skip
return m.dx[i] == m.tf * m.v[i]
m.ode2 = Constraint(m.tau, rule=_ode2)
def _ode3(m, i):
if i==0:
return Constraint.Skip
return m.dv[i] == m.tf*(m.u[i] - m.R*m.v[i]**2)
m.ode3 = Constraint(m.tau, rule=_ode3)
def _accelerationL(m, i):
if i==0:
return Constraint.Skip
return m.dv[i] >= m.aL*m.tf
m.accelerationL = Constraint(m.tau, rule=_accelerationL)
def _accelerationU(m, i):
if i==0:
return Constraint.Skip
return m.dv[i] <= m.aU*m.tf
m.accelerationU = Constraint(m.tau, rule=_accelerationU)
def _jerkL(m, i):
if i==0:
return Constraint.Skip
return m.da[i] >= m.jL*m.tf**2
m.jerkL = Constraint(m.tau, rule=_jerkL)
def _jerkU(m, i):
if i==0:
return Constraint.Skip
return m.da[i] <= m.jU*m.tf**2
m.jerkU = Constraint(m.tau, rule=_jerkU)
'''
def _electric(m, i):
if i==0:
return Constraint.Skip
elif value(m.v[i])<=7:
return m.a[i] <= 1
else:
return m.v[i] <= 1*7/m.v[i]
m.electric = Constraint(m.tau, rule=_electric)
'''
'''
def _speed(m, i):
if i==0:
return Constraint.Skip
elif value(m.x[i])<=500:
return m.v[i] <= 40/3.6
else:
return m.v[i] <= 25/3.6
m.speed = Constraint(m.tau, rule=_speed)
'''
def _initial(m):
yield m.x[0] == 0
yield m.x[1] == m.L
yield m.v[0] == 0
yield m.v[1] == 0
yield m.t[0] == 0
m.initial = ConstraintList(rule=_initial)
discretizer = TransformationFactory('dae.finite_difference')
discretizer.apply_to(m, nfe=value(m.NFE), wrt=m.tau, scheme='BACKWARD')
#discretizer = TransformationFactory('dae.collocation')
#discretizer.apply_to(m, nfe=value(m.NFE), ncp=4, wrt=m.tau, scheme='LAGRANGE-RADAU')
solver = SolverFactory('ipopt')
solver.solve(m,tee=True)
print("final time = %6.2f" %(value(m.tf)))
t = []
x = []
v = []
a = []
u = []
for i in m.tau:
t.append(value(m.t[i]))
x.append(value(m.x[i]))
v.append(3.6*value(m.v[i]))
a.append(10*value(m.u[i] - m.R*m.v[i]**2))
u.append(10*value(m.u[i]))
import matplotlib.pyplot as plt
plt.plot(x, v, label='v (km/h)')
plt.plot(x, a, label='a (dm/s2)')
plt.plot(x, u, label='u (dm/s2)')
plt.xlabel('distance')
plt.grid('on')
plt.legend()
plt.show()
Thanks a lot in advance,
Pablo
(1) You should not think of Pyomo constraint rules as callbacks that are used by the solver. You should think of them more as a function to generate a container of constraint objects that gets called once for each index when the model is constructed. Meaning it is invalid to use a variable in an if statement unless you are really only using its initial value to define the constraint expression. There are ways to express what I think you are trying to do, but they involve introducing binary variables into the problem, in which case you can no longer use Ipopt.
(2) Can't really provide any help. Syntax looks fine.
(3) Pyomo allows you to return double-sided inequality expressions (e.g., L <= f(x) <= U) from constraint rules, but they can not involve variable expressions in the L and U locations. It doesn't look like the constraints you are referring to can be combined into this form.
(4) See (1)

Extensible Hashing with unique keys

I have a database that consists of tuples like so
'The Abyss,1989,LaserDisc,Science Fiction,James Cameron,James Cameron,USA,20th Century Fox,$0.00'
I want to concatenate the movie title with the year to make the unique key for each bucket. But unsure how to... I think it would be beneficial to use extensible hashing for this,
I would like to be able to search by movies being DVD or VHS as well as searching through and finding movies by year. I would consist buckets of years in a decade increments and types of movie (DVD, VHS)
Right now I just have a simple add, remove, and get functionality
class HTable(object):
def __init__(self, table = [], maximum = 100):
#table = dict, maximum = maximum amount of elements.
assert type(table) == dict
self.table = table
self.max = maximum
def lookup(self, data):
#Lookup a value in our table.
if type(data) == int or type(data) == long:
try:
if self.table[data % self.max] != None:
return (data % self.max, self.table[data % self.max])
else:
return None
except:
return None
else:
try:
obj1 = self.string2int(data) % self.max
obj2 = self.table[self.string2int(data) % self.max]
if obj2 != None:
return (obj1, obj2)
else:
return None
except:
return None
def append(self, data):
#data = int, string, object, etc. No duplicates allowed.
assert len(self.table) < self.max
if type(data) == int or type(data) == long:
original = data
if data >= self.max:
raise IOError, "Value to large to append into hash table. Max limit reached."
else:
original = data
data = self.string2int(data)
index = data % self.max
if int(index) >= self.max:
raise IOError, "Data: %s, exceeded your maximum limit of %s, with the size of %s." %(str(original), str(self.max), str(index))
try:
if type(original) == int or type(original) == long:
self.table[data % self.max] = data
else:
self.table[data % self.max] = original
return self.table
except:
if len(self.table) < data % self.max:
while len(self.table) < data % self.max:
self.table.append(None)
if type(original) == int:
self.table.insert(data % self.max, data)
else:
self.table.insert(data % self.max, str(original))
return self.table
def string2int(self, STRING):
#Convert a string into a 'hash' integer.
return sum([ord(j) for j in STRING])
def isEmpty(self):
#Return True if empty, false otherwise.
if len(self.table) == 0:
return True
else:
return False
def isFull(self):
#Returns TRUE if full, false otherwise.
if len(self.table) == self.max:
return True
else:
return False
def remove(self, key):
#Remove the data located at the given index/key. Key can be a index key(integer), or the data itself. For example: self.remove(key = 'value') or self.remove(key = 10).
try:
self.table.pop(int(key))
return 1
except:
try:
self.table.remove(key)
return 1
except:
return False
def get(self, key):
#Get the data in our HASH Table, using the given index(key).
try:
return self.table[int(key)]
except:
return None
def output(self):
#Return our current HASH Table.
return self.table

Best approach to create an saturating integer in python?

What would be the best approach to create a type that is a saturated integer in python ?
i.e.:
v = SaturatedInteger(0, 100)
# That should create an integer that will always be in between 0 and 100,
# and have all default operations
v += 68719
print v #Should print '100'.
I can think of inheriting int type, but where should the saturating logic be implemented then ?
If you need a new (quick and dirty) class for it, I would implement it as follows.
class SaturatedInteger:
def __init__(self, val, lo, hi):
self.real, self.lo, self.hi = val, lo, hi
def __add__(self, other):
return min(self.real + other.real, self.hi)
def __sub__(self, other):
return max(self.real - other.real, self.lo)
...
Add as many of the other operators in the docs as you feel you will need (and their 'r' variants).
By storing the value in the instance name real, you can do your arithmetic with regular integers, floats, etc. too:
a = SaturatedInteger(60, 0, 100)
print(a)
60
print(a+30)
90
print(a+40)
100
print(a+50.)
100
print(a-70.)
0
print(a+a)
100
Though, of course you only add the real part if you're adding a complex number to your SaturatedInteger, so watch out. (For a much more complete and robust version, #jonrsharpe's answer is the way to go).
In general, I would implement using a #property to protect an instance's value attribute, then emulate a numeric type, rather than inheriting from int:
class SaturatedInteger(object):
"""Emulates an integer, but with a built-in minimum and maximum."""
def __init__(self, min_, max_, value=None):
self.min = min_
self.max = max_
self.value = min_ if value is None else value
#property
def value(self):
return self._value
#value.setter
def value(self, new_val):
self._value = min(self.max, max(self.min, new_val))
#staticmethod
def _other_val(other):
"""Get the value from the other object."""
if hasattr(other, 'value'):
return other.value
return other
def __add__(self, other):
new_val = self.value + self._other_val(other)
return SaturatedInteger(self.min, self.max, new_val)
__radd__ = __add__
def __eq__(self, other):
return self.value == self._other_val(other)
if __name__ == '__main__':
v = SaturatedInteger(0, 100)
v += 68719
assert v == 100
assert 123 + v == 100
I've only implemented __add__, __radd__ and __eq__, but you can probably see how the rest could be built out as required. You might want to think about what happens when two SaturatedIntegers are used together - should the result have e.g. min(self.min, other.min) as its own min?
I wrote a sample class that has an add function:
class SatInt:
def __init__(self, low, up):
self.lower = low
self.upper = up
self.value = 0
def add(self, n):
if n+self.value > self.upper:
self.value = self.upper
else:
self.value = self.value + n
x = SatInt(0,100)
x.add(32718)
print(x.value)
100