2017-05-17 1 views
0

J'utilise PYOMO et je veux implémenter un OR logique dans le "P_constraint_rule", mais je ne peux pas le faire.comment modéliser des OU logiques ou des quantificateurs dans des contraintes Pyomo

il y a des parties de mon modèle:

model.s = Param(within=NonNegativeIntegers) 
model.S = RangeSet(1, model.s) 
model.f = Param(within=NonNegativeIntegers) 
model.F = RangeSet(1, model.f) 
model.p = Param(within=NonNegativeIntegers) 
model.P = RangeSet(0, model.p) 
model.m = Param(within=NonNegativeIntegers) 
model.M = RangeSet(1, model.m) 
model.g = Param(model.M, default=5.0) 
model.b2 = Param(model.F,model.F, within=Binary, default=0) 
model.xf1f2 = Var(model.F, model.F, within=Binary) 
model.y = Var(model.M, within=Binary) 
model.xf = Var(model.F, within=Binary) 
model.aff = Param(model.F,model.F, within=NonNegativeIntegers, default=0) 

...

model.x = Var(model.index_sfpm, within=Binary) 
model.b1 = Param(model.index_sfpm, within=Binary, default=0) 


def Obj_rule(model): 
    expr = 0.0 
    for (s,f,p,m) in model.index_sfpm: 
     expr += model.g[m] * model.xf[f] * model.b1[s,f,p,m] * model.x[s,f,p,m]  
    for m in model.M: 
     expr += model.g[m] * model.y[m] 

    return expr 

model.OBJ = Objective(rule=Obj_rule, sense=maximize) 


def P_constraint_rule (model, f1, f2): 
    expr = 0.0 
    for (s,m) in model.index_sm: 
     expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m] 
     expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m] 

e.g. in my .dat : param aff:= 1 7 10

return expr == model.aff[f1,f2] | expr == 0 

model.PConstraint = Constraint(model.index_f1f2, rule=P_constraint_rule) 

Quand j'utiliser "|", je suis l'erreur suivante:

ERROR: Rule failed when generating expression for constraint PConstraint with index (7, 3): 
     TypeError: unsupported operand type(s) for |: 'int' and '_SumExpression' ERROR: Constructing component 'PConstraint' from data=None failed: 
     TypeError: unsupported operand type(s) for |: 'int' and '_SumExpression' [ 1.72] Pyomo Finished ERROR: Unexpected exception while running model: 
     unsupported operand type(s) for |: 'int' and '_SumExpression' 

et quand j'utilise "|| "

ERROR: Unexpected exception while loading model: 
     invalid syntax 

Lorsque cette contrainte est commenté, le modèle et gurobi belle course.

Quelqu'un pourrait me aider avec ces erreurs?

Y at-il une autre possibilité d'utiliser un quantificateur? Le inéquation P1 .constraint doit être valide pour model.index_f1f2 L'équation P2Constraint doit être valide pour 2 éléments de model.F ou 1 élément de model.index_f1f2 quelque chose comme:

def P1_constraint_rule (model, f1, f2): 
expr = 0.0 
for (s,m) in model.index_sm: 
    expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m] 
    expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m] 
return expr <= model.aff[f1,f2] 

model.P1Constraint = Constraint(model.index_f1f2, rule=P1_constraint_rule) 


def P2_constraint_rule (model, f1, f2): 
    expr = 0.0 
    for (s,m) in model.index_sm: 
     expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m] 
     expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m] 
     #this equation should be valid for 2 elements of model.F or 1 element of model.index_f1f2 
    return expr == model.aff[f1,f2] 

model.P2Constraint = Constraint(model.index_f1f2, rule=P2_constraint_rule) 

merci à l'avance, Lala

+0

Je viens d'ajouter la possibilité "quantificateurs" – Lala

Répondre

2

L'erreur est parce que vous essayez de spécifier une contrainte non-algébrique. Conceptuellement, ce qui suit définirait une disjonction logique:

expr == model.aff[f1,f2] | expr == 0 

Pour les questions syntaxiques:

  • | est binaire OR. Il se lie plus étroitement que les opérateurs relationnels et ne ferait donc pas ce que vous voulez.
  • || n'est pas la syntaxe de Python valide
  • sur le plan conceptuel ce que vous voulez est logique ou, qui en Python est mis en œuvre avec or. Ce serait une bonne syntaxe à supporter - cependant, elle n'est pas actuellement supportée par Pyomo.

Vous avez deux options pour spécifier des contraintes comme ceci: soit (1) spécifient comme une disjonction en utilisant l'extension pyomo.gdp puis tirer parti des transformations dans pyomo.gdp pour se détendre le programme disjonctive retour à un MIP, ou (2) relaxer explicitement la disjonction en utilisant, par exemple, une relaxation Big-M. Pour ce faire, l'ancien, vous devez définir les deux disjoints, puis la disjonction:

from pyomo.gdp import * 

def P_disjunct_rule (b, f1, f2, i): 
    model = b.model() 
    expr = 0.0 
    for (s,m) in model.index_sm: 
     expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m] 
     expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m] 
    if i: 
     return expr == model.aff[f1,f2] 
    else: 
     return expr == 0 
model.PDisjunct = Disjunct(model.index_f1f2, [0,1], rule=P_constraint_rule) 

def P_disjunction_rule(m,f1,f2): 
    return [ m.PDisjunct[f1,f2,i] for i in [0,1] ] 
model.PDisjunction = Disjunction(model.index_f1f2, rule=P_Disjunction_rule) 

Vous devez ensuite invoquer une transformation pour convertir les disjonctions retour aux contraintes algébriques. Remarque: les transformations nécessitent que vos variables Pyomo aient toutes des limites inférieure et supérieure, OU vous devez spécifier des valeurs "Big-M" valides via un suffixe BigM sur votre modèle.Vous pouvez:

  • spécifier la transformation sur la ligne de commande Pyomo (par exemple, --transform=gdp.bigm ou --transform=gdp.chull)
  • préciser la transformation dans un BuildAction

    def xfrm(m): 
        TransformationFactory('gdp.bigm').apply_to(m) 
    model.xfrm = BuildAction(rule=xfrm) 
    
  • appeler explicitement la transformation dans le cadre de votre script de pilote personnalisé.

L'alternative à pyomo.gdp est d'implémenter explicitement la relaxation vous-même. Vous auriez besoin d'ajouter une variable binaire (appelons-la y) qui indique quel côté de la disjonction doit être True, puis relâchez explicitement les deux disjonctions en utilisant cette variable binaire. Conceptuellement vous tournez

expr == model.aff[f1,f2] | expr == 0 

dans

expr - model.aff[f1.f2] <= M1 * y 
model.aff[f1.f2] - expr <= M2 * y 
expr <= M3 * (1-y) 
expr >- M4 * (1-y) 

Notez que selon les limites de expr et aff, certaines de ces contraintes peuvent être redondantes. De plus, les quatre "Big-M's" (grandes constantes) ne doivent pas forcément être différents, bien que le problème soit mieux résolu si vous pouvez déterminer la plus petite valeur valide pour chacun des M.

0

merci @jsiirola. J'ai implémenté la contrainte avec relaxation Big-M. Ça marche.

De plus, j'ai simplifié l'expression expr et return.

pour chaque f (ancien f1, f2) la somme sur S et M de (model.b [s, f, 1, m] * model.x [s, f, 1, m]) doit être égale à 0 OU model.af [f] (ancien model.aff [f1, f2]).

model.af [f] est également utilisé comme lié M.

## Big-M Relaxation 
def P1_constraint_rule (model, f): 
    expr = 0 
    for (s,m) in model.index_sm: 
     expr += model.b[s,f,1,m] * model.x[s,f,1,m] 

    return expr <= model.af[f] * model.xf[f] 

model.P1Constraint = Constraint(model.F, rule=P1_constraint_rule) 


def P2_constraint_rule (model, f): 
    expr = 0 
    for (s,m) in model.index_sm: 
     expr += model.b[s,f,1,m] * model.x[s,f,1,m] 

    return expr >= model.af[f] * model.xf[f] 

model.P2Constraint = Constraint(model.F, rule=P2_constraint_rule) 


def P3_constraint_rule (model, f): 
    expr = 0 
    for (s,m) in model.index_sm: 
     expr += model.b[s,f,1,m] * model.x[s,f,1,m] 

    return expr - model.af[f] <= model.af[f] * (1- model.xf[f]) 

model.P3Constraint = Constraint(model.F, rule=P3_constraint_rule) 


def P4_constraint_rule (model, f): 
    expr = 0 
    for (s,m) in model.index_sm: 
     expr += model.b[s,f,1,m] * model.x[s,f,1,m] 

    return model.af[f] - expr <= model.af[f] * (1- model.xf[f]) 

model.P4Constraint = Constraint(model.F, rule=P4_constraint_rule)