How do I prevent multiple starts/stops of my selection? - python

I have CVXPY problem defined with a volume array, and a cost array to match each of volumes. The problem has 192 variables and 3 constraints which I have defined.
My goal is to minimize the cost in this problem to deliver a specific volume and avoid multiple periods where I get a 0, 1, 0, 1.
My current output could look something like follows:
[0, 0, 1, 1, 0, 1... 0, 1, 0, 1]
The ideal solution would avoid an amount. So if the selection decides a 1 at a point, the next 2 points should be 0. Such as below:
[0, 0, 1, 1, 0, 0... 0, 1, 0, 0]
I am unsure how to write such a constraint to include my selection with the problem I have currently programmed as can be seen here:
import cvxpy as cp
import numpy as np
# Volume and cost
full_cost = [[0, data] for data in [0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45,0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4]]
cost_ = np.array(full_cost)
ex = np.array([[0, 17100] for data in [i for i in range(0, 96)]])
# Minimum volume required
v_min = 300000
# Selection variable
selection = cp.Variable(shape=ex.shape, boolean=True)
# Constraints
assignment_constraint = cp.sum(selection,axis=1) == 1
volume_= cp.sum(cp.multiply(ex,selection))
volume_constraint = volume_ >= v_min
cost_constraint = cp.sum(cp.multiply(cost_, selection))
constraints = [assignment_constraint, volume_constraint, cost_constraint]
cost_ = cp.sum(cp.multiply(cost_,selection))
# Problem definition
assign_problem = cp.Problem(cp.Minimize(cost_), constraints)
assign_problem.solve(solver=cp.CPLEX, verbose=True)
# Find solution in ex variable
assignments = [np.where(r==1)[0][0] for r in selection.value]
c = [ ex[i][assignments[i]] for i in range(len(assignments)) ]
best_volume = np.sum(np.multiply(ex,selection.value))
best_cost = np.sum(np.multiply(cost_,selection.value))
print(best_cost)
print(c)
I believe that the constraint should be based around my selection variable, but I am struggling to see how to include it as a constraint.

If I understand correctly the it looks like you want to impose the condition
if x[i]==1 and x[i+1]==0 then x[i+2]==0
for binary variables x. That is equivalent to
x[i+2] <= 1 - x[i] + x[i+1]

Related

How to expand the output of a truncated list to view more values of Pandas dataframe

Is there a specific way to display all the truncated data values of a list. The displayed values are as follows
v w
Row1 [0.1, 0.2, 0.3 .....1.0] [0.1, 0.2, 0.3 .....1.0]
Here are the option I tried
Option 1
p
pd.set_option('display.max_colwidth', None)
pd.set_option('display.max_seq_items', None)
z = pd.read_csv('a.csv')
Output:
it is still truncated
Option 2
for i, row in z.iterrows():
for j in row['w']:
print(j)
Output:
it is stll truncated
Any help on how to display all the truncated values and display the full list.
You can print after conversion to_string:
print(df.to_string())
output:
v w
Row1 [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
Used input:
L = list(np.arange(0, 1.1, 0.1).round(2))
df = pd.DataFrame({'v': [L], 'w': [L]}, index=['Row1'])
default print:
v \
Row1 [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, ...
w
Row1 [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, ...

My itertools product method is not working? Why?

I'm working with itertools product and trying to return possible permutations.
This is what I'm trying to pass:
from itertools import product
df = {'A':[0,0.03,0.5],
'B':[0,0.02,0.5],
'C':[0,0.015,0.03],
'D':[0,0.15,0.3],
'E':[0,0.1,0.4],
'F':[0,0.06,0.5],
'G':[0,0.07,0.5]}
for element in product(list(df.values())):
print(element)
What I get back:
([0, 0.03, 0.5],)
([0, 0.02, 0.5],)
([0, 0.015, 0.03],)
([0, 0.15, 0.3],)
([0, 0.1, 0.4],)
([0, 0.06, 0.5],)
([0, 0.07, 0.5],)
What I want:
All possible permutations of the numbers, one possible solution would look like:
[0,0.02,0.015,0.15,0.4,0.06,0.07]
Why is the product method not working as desired. Working out of Jupyter Notebooks - Python 3.
Are you looking for this?
from itertools import product
df = {'A':[0,0.03,0.5],
'B':[0,0.02,0.5],
'C':[0,0.015,0.03],
'D':[0,0.15,0.3],
'E':[0,0.1,0.4],
'F':[0,0.06,0.5],
'G':[0,0.07,0.5]}
for element in product(*df.values()):
print(element)
example output:
...
(0.5, 0.5, 0.03, 0.3, 0.1, 0.5, 0)
(0.5, 0.5, 0.03, 0.3, 0.1, 0.5, 0.07)
(0.5, 0.5, 0.03, 0.3, 0.1, 0.5, 0.5)
(0.5, 0.5, 0.03, 0.3, 0.4, 0, 0)
(0.5, 0.5, 0.03, 0.3, 0.4, 0, 0.07)
(0.5, 0.5, 0.03, 0.3, 0.4, 0, 0.5)
(0.5, 0.5, 0.03, 0.3, 0.4, 0.06, 0)
(0.5, 0.5, 0.03, 0.3, 0.4, 0.06, 0.07)
(0.5, 0.5, 0.03, 0.3, 0.4, 0.06, 0.5)
(0.5, 0.5, 0.03, 0.3, 0.4, 0.5, 0)
(0.5, 0.5, 0.03, 0.3, 0.4, 0.5, 0.07)
(0.5, 0.5, 0.03, 0.3, 0.4, 0.5, 0.5)
You need to flatten the list as below:
for element in product([item for data in df.values() for item in data)):
print(element)

How to reorder one set of data points to minimize error with another set of data points

I have the following set of 15 data points:
[0.287 , 0.0691, 0.856, 0.731, 0.895, 0.76, 0.496, 0.749, 0.77, 0.684, 0.667, 0.386, 0.4, 0.334, 0.346]
And I would like the order of these data points to be changed so to minimize the error with the following set of 15 data points:
[0.1, 0.3, 0.5, 0.7, 0.9, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.3, 0.2, 0.1]
I could just try all permutations of the first set of data points and see which one gives the smallest error but that would take forever...
I'm assuming by error you mean the summed absolute difference. It is not difficult to check that this error is minimized when a and b have the same rank order. The best reordering of a can thus be obtained using argsort
>>> a = np.array([0.287 , 0.0691, 0.856 , 0.731 , 0.895 , 0.76 , 0.496 , 0.749 , 0.77 , 0.684 , 0.667 , 0.386 , 0.4 , 0.334 , 0.346 ])
>>> b = np.array([0.1, 0.3, 0.5, 0.7, 0.9, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.3, 0.2, 0.1])
>>>
>>> best_shuffle = np.empty(a.size,int)
>>> best_shuffle[b.argsort(kind="stable")] = a.argsort(kind="stable")
>>>
>>> np.abs(b-a[best_shuffle]).sum()
1.3499000000000005

How can a tensor in tensorflow be sliced ​using elements of another array as an index?

I'm looking for a similar function to tf.unsorted_segment_sum, but I don't want to sum the segments, I want to get every segment as a tensor.
So for example, I have this code:
(In real, I have a tensor with shapes of (10000, 63), and the number of segments would be 2500)
to_be_sliced = tf.constant([[0.1, 0.2, 0.3, 0.4, 0.5],
[0.3, 0.2, 0.2, 0.6, 0.3],
[0.9, 0.8, 0.7, 0.6, 0.5],
[2.0, 2.0, 2.0, 2.0, 2.0]])
indices = tf.constant([0, 2, 0, 1])
num_segments = 3
tf.unsorted_segment_sum(to_be_sliced, indices, num_segments)
The output would be here
array([sum(row1+row3), row4, row2]
What I am looking for is 3 tensor with different shapes (maybe a list of tensors), first containing the first and third rows of the original (shape of (2, 5)), the second contains the 4th row (shape of (1, 5)), the third contains the second row, like this:
[array([[0.1, 0.2, 0.3, 0.4, 0.5],
[0.9, 0.8, 0.7, 0.6, 0.5]]),
array([[2.0, 2.0, 2.0, 2.0, 2.0]]),
array([[0.3, 0.2, 0.2, 0.6, 0.3]])]
Thanks in advance!
You can do that like this:
import tensorflow as tf
to_be_sliced = tf.constant([[0.1, 0.2, 0.3, 0.4, 0.5],
[0.3, 0.2, 0.2, 0.6, 0.3],
[0.9, 0.8, 0.7, 0.6, 0.5],
[2.0, 2.0, 2.0, 2.0, 2.0]])
indices = tf.constant([0, 2, 0, 1])
num_segments = 3
result = [tf.boolean_mask(to_be_sliced, tf.equal(indices, i)) for i in range(num_segments)]
with tf.Session() as sess:
print(*sess.run(result), sep='\n')
Output:
[[0.1 0.2 0.3 0.4 0.5]
[0.9 0.8 0.7 0.6 0.5]]
[[2. 2. 2. 2. 2.]]
[[0.3 0.2 0.2 0.6 0.3]]
For your case, you can do Numpy slicing in Tensorflow. So this will work:
sliced_1 = to_be_sliced[:3, :]
# [[0.4 0.5 0.5 0.7 0.8]
# [0.3 0.2 0.2 0.6 0.3]
# [0.3 0.2 0.2 0.6 0.3]]
sliced_2 = to_be_sliced[3, :]
# [0.3 0.2 0.2 0.6 0.3]
Or a more general option, you can do it in the following way:
to_be_sliced = tf.constant([[0.1, 0.2, 0.3, 0.4, 0.5],
[0.3, 0.2, 0.2, 0.6, 0.3],
[0.9, 0.8, 0.7, 0.6, 0.5],
[2.0, 2.0, 2.0, 2.0, 2.0]])
first_tensor = tf.gather_nd(to_be_sliced, [[0], [2]])
second_tensor = tf.gather_nd(to_be_sliced, [[3]])
third_tensor = tf.gather_nd(to_be_sliced, [[1]])
concat = tf.concat([first_tensor, second_tensor, third_tensor], axis=0)

how to add value within certain intervals only python

I have a dataframe and values in a columns ranges from -1 to 1. I want to add 0.1 to all value between -1 to 0.6 only. Is it possible to do it?
suppose a is my list:
a = ([-1. , -0.5, 0.1 , 0.2, 0.45, 0.7, 0.64, 1])
and I want this:
([-0.9, -0.4, 0.2, 0.3, 0.55, 0.7, 0.74, 1])
Yes, it's possible:
a = [-1. , -0.5, 0.1 , 0.2, 0.45, 0.7, 0.64, 1]
a = [x + 0.1 if -1 <= x <= 0.6 else x for x in a]
print a
Results:
[-0.9, -0.4, 0.2, 0.3, 0.55, 0.7, 0.64, 1]

Categories