|
#!/usr/bin/env python3 |
|
'''Simple test |
|
''' |
|
from ortools.sat.python import cp_model |
|
import pandas as pd |
|
|
|
# Define the dataframe with feature columns and the target column |
|
data = { |
|
'A': [1.59, 0.9, 2.82,2.44,2.61], |
|
'B': [0.68,0.1,1.3,1.64,1.59], |
|
'C': [2.15,-0.45,2.91,5.2,2.72], |
|
'P': [-0.5,0,1.2,-0.1,1.5] |
|
} |
|
df = pd.DataFrame(data) |
|
|
|
# Multiply by large int to frame the problem in integers |
|
df = df * 100 |
|
|
|
model = cp_model.CpModel() |
|
|
|
# Contraint 1: A is between bounds |
|
A_MIN_LB = int(df['A'].min()-1) |
|
A_MAX_UB = int(df['A'].max()+1) |
|
print(f'A range: [{A_MIN_LB}, {A_MAX_UB}]') |
|
|
|
a_lb = model.NewIntVar(A_MIN_LB, A_MAX_UB, 'a_lb') |
|
a_ub = model.NewIntVar(A_MIN_LB,A_MAX_UB , 'a_ub') |
|
model.Add(a_lb < a_ub) |
|
|
|
# Contraint 2: B is between bounds |
|
B_MIN_LB = int(df['B'].min()-1) |
|
B_MAX_UB = int(df['B'].max()+1) |
|
print(f'B range: [{B_MIN_LB}, {B_MAX_UB}]') |
|
|
|
b_lb = model.NewIntVar(B_MIN_LB, B_MAX_UB, 'b_lb') |
|
b_ub = model.NewIntVar(B_MIN_LB,B_MAX_UB , 'b_ub') |
|
model.Add(b_lb < b_ub) |
|
|
|
# Contraint 3: C is between bounds |
|
C_MIN_LB = int(df['C'].min()-1) |
|
C_MAX_UB = int(df['C'].max()+1) |
|
print(f'C range: [{C_MIN_LB}, {C_MAX_UB}]') |
|
|
|
c_lb = model.NewIntVar(C_MIN_LB, C_MAX_UB, 'c_lb') |
|
c_ub = model.NewIntVar(C_MIN_LB, C_MAX_UB , 'c_ub') |
|
model.Add(c_lb < c_ub) |
|
|
|
# Define a binary variable representing inclusion of each row in the DataFrame |
|
x = {} |
|
for i in range(len(df)): |
|
x[i] = model.NewBoolVar(f'x[{i}]') |
|
|
|
df_a = int(df['A'][i]) |
|
df_b = int(df['B'][i]) |
|
df_c = int(df['C'][i]) |
|
print(f'tuple[{i}]: (A:{df_a}, B:{df_b}, C:{df_c}), P:{df["P"][i]}') |
|
|
|
## Intermediate bools for channeling |
|
is_A_greater = model.NewBoolVar(f'is_A_greater_{i}') |
|
is_A_lesser = model.NewBoolVar(f'is_A_lesser_{i}') |
|
model.Add(a_lb < df_a).OnlyEnforceIf(is_A_greater) |
|
model.Add(a_lb >= df_a).OnlyEnforceIf(is_A_greater.Not()) |
|
|
|
model.Add(df_a < a_ub).OnlyEnforceIf(is_A_lesser) |
|
model.Add(df_a >= a_ub).OnlyEnforceIf(is_A_lesser.Not()) |
|
|
|
is_B_greater = model.NewBoolVar(f'is_B_greater_{i}') |
|
is_B_lesser = model.NewBoolVar(f'is_B_lesser_{i}') |
|
model.Add(b_lb < df_b).OnlyEnforceIf(is_B_greater) |
|
model.Add(b_lb >= df_b).OnlyEnforceIf(is_B_greater.Not()) |
|
|
|
model.Add(df_b < b_ub).OnlyEnforceIf(is_B_lesser) |
|
model.Add(df_b >= b_ub).OnlyEnforceIf(is_B_lesser.Not()) |
|
|
|
is_C_greater = model.NewBoolVar(f'is_C_greater_{i}') |
|
is_C_lesser = model.NewBoolVar(f'is_C_lesser_{i}') |
|
model.Add(c_lb < df_c).OnlyEnforceIf(is_C_greater) |
|
model.Add(c_lb >= df_c).OnlyEnforceIf(is_C_greater.Not()) |
|
|
|
model.Add(df_c < c_ub).OnlyEnforceIf(is_C_lesser) |
|
model.Add(df_c >= c_ub).OnlyEnforceIf(is_C_lesser.Not()) |
|
|
|
# Assign true to x[i] only if all all conditions met |
|
model.AddBoolAnd( |
|
is_A_greater, is_A_lesser, |
|
is_B_greater, is_B_lesser, |
|
is_C_greater, is_C_lesser |
|
).OnlyEnforceIf(x[i]) |
|
# Assign false to x[i] if at least one condition is *not* met |
|
model.AddBoolOr( |
|
is_A_greater.Not(), is_A_lesser.Not(), |
|
is_B_greater.Not(), is_B_lesser.Not(), |
|
is_C_greater.Not(), is_C_lesser.Not() |
|
).OnlyEnforceIf(x[i].Not()) |
|
|
|
# Contraint 3: At least 3 items are not filtered |
|
model.Add(sum(x[i] for i in range(len(df))) >= 3) |
|
|
|
# Objective |
|
#objective_terms = [] |
|
#for i in range(len(df)): |
|
# objective_terms.append(x[i] * int(df['P'][i])) |
|
#model.Maximize(sum(objective_terms)) |
|
model.Maximize(sum(x[i] * int(df['P'][i]) for i in range(len(df)))) |
|
|
|
solver = cp_model.CpSolver() |
|
status = solver.Solve(model) |
|
|
|
print(f'Solve status: {solver.StatusName(status)}') # "INFEASIBLE" :( ? |
|
print(f'Optimal objective value: {solver.ObjectiveValue()}') # "0" |
|
|
|
if status in (cp_model.OPTIMAL, cp_model.FEASIBLE): |
|
print(f'{solver.Value(a_lb)} < a < {solver.Value(a_ub)}') |
|
print(f'{solver.Value(b_lb)} < b < {solver.Value(b_ub)}') |
|
print(f'{solver.Value(c_lb)} < c < {solver.Value(c_ub)}') |
|
for i in range(len(df)): |
|
print(f'x[{i}]: {solver.BooleanValue(x[i])}') |
|
else: |
|
print('No solution found.') |