@@ -6643,6 +6643,123 @@ cdef class Model:
66436643 PY_SCIP_CALL(SCIPreleaseCons(self ._scip, & (< Constraint> cons).scip_cons))
66446644 return disj_cons
66456645
6646+ def addMatrixConsDisjunction (self , conss: Iterable ,
6647+ name: Union[str , np.ndarray] = '', initial: Union[bool , np.ndarray] = True ,
6648+ relaxcons = None , enforce: Union[bool , np.ndarray] = True ,
6649+ check: Union[bool , np.ndarray] = True , local: Union[bool , np.ndarray] = False ,
6650+ modifiable: Union[bool , np.ndarray] = False ,
6651+ dynamic: Union[bool , np.ndarray] = False ):
6652+ """
6653+ Add an elementwise disjunction of matrix constraint expressions.
6654+
6655+ Given an iterable of ``MatrixExprCons`` with a common shape, creates one
6656+ disjunction per index: for each position ``idx``, the resulting
6657+ disjunction enforces that at least one of ``conss[k][idx]`` holds.
6658+ ``ExprCons`` entries are broadcast to every position. If every entry in
6659+ ``conss`` is a plain ``ExprCons``, the call is forwarded to
6660+ :meth:`addConsDisjunction` and returns a single ``Constraint``.
6661+
6662+ Note: this method accepts constraint *expressions* (e.g., ``A @ x <= b``),
6663+ not ``MatrixConstraint``/``Constraint`` objects returned by
6664+ :meth:`addMatrixCons`/:meth:`addCons`.
6665+
6666+ Parameters
6667+ ----------
6668+ conss : iterable of MatrixExprCons or ExprCons
6669+ Constraint expressions to combine elementwise into disjunctions. All
6670+ ``MatrixExprCons`` entries must share the same shape.
6671+ name : str or np.ndarray, optional
6672+ Name of the disjunction constraints. (Default value = "")
6673+ initial : bool or np.ndarray, optional
6674+ Should the LP relaxation be in the initial LP? (Default value = True)
6675+ relaxcons : None, optional
6676+ NOT YET SUPPORTED. (Default value = None)
6677+ enforce : bool or np.ndarray, optional
6678+ Should the constraint be enforced during node processing? (Default value = True)
6679+ check : bool or np.ndarray, optional
6680+ Should the constraint be checked for feasibility? (Default value = True)
6681+ local : bool or np.ndarray, optional
6682+ Is the constraint only valid locally? (Default value = False)
6683+ modifiable : bool or np.ndarray, optional
6684+ Is the constraint modifiable (subject to column generation)? (Default value = False)
6685+ dynamic : bool or np.ndarray, optional
6686+ Is the constraint subject to aging? (Default value = False)
6687+
6688+ Returns
6689+ -------
6690+ MatrixConstraint or Constraint
6691+ A ``MatrixConstraint`` of the common shape when any entry of
6692+ ``conss`` is a ``MatrixExprCons``; otherwise a single
6693+ ``Constraint`` from the scalar fallback.
6694+ """
6695+ if not isinstance (conss, Iterable):
6696+ raise TypeError (f" given constraint list is not iterable, but got {type(conss).__name__}" )
6697+ conss = list (conss)
6698+
6699+ for cons in conss:
6700+ if not isinstance (cons, (ExprCons, MatrixExprCons)):
6701+ raise TypeError (
6702+ " element of conss is not MatrixExprCons nor ExprCons but %s "
6703+ % cons.__class__ .__name__
6704+ )
6705+
6706+ if all (isinstance (cons, ExprCons) for cons in conss):
6707+ return self .addConsDisjunction(
6708+ conss, name = name, initial = initial, relaxcons = relaxcons,
6709+ enforce = enforce, check = check, local = local,
6710+ modifiable = modifiable, dynamic = dynamic,
6711+ )
6712+
6713+ shape = None
6714+ for cons in conss:
6715+ if isinstance (cons, MatrixExprCons):
6716+ if shape is None :
6717+ shape = cons.shape
6718+ elif cons.shape != shape:
6719+ raise ValueError (
6720+ " All MatrixExprCons in conss must have the same shape, "
6721+ " got %s and %s " % (shape, cons.shape)
6722+ )
6723+
6724+ for arr in (name, initial, enforce, check, local, modifiable, dynamic):
6725+ if isinstance (arr, np.ndarray):
6726+ assert arr.shape == shape
6727+
6728+ if isinstance (name, str ):
6729+ matrix_names = np.full(shape, name, dtype = object )
6730+ if name != " " :
6731+ for idx in np.ndindex(shape):
6732+ matrix_names[idx] = f" {name}_{'_'.join(map(str, idx))}"
6733+ else :
6734+ matrix_names = name
6735+
6736+ matrix_initial = initial if isinstance (initial, np.ndarray) else np.full(shape, initial, dtype = bool )
6737+ matrix_enforce = enforce if isinstance (enforce, np.ndarray) else np.full(shape, enforce, dtype = bool )
6738+ matrix_check = check if isinstance (check, np.ndarray) else np.full(shape, check, dtype = bool )
6739+ matrix_local = local if isinstance (local, np.ndarray) else np.full(shape, local, dtype = bool )
6740+ matrix_modifiable = modifiable if isinstance (modifiable, np.ndarray) else np.full(shape, modifiable, dtype = bool )
6741+ matrix_dynamic = dynamic if isinstance (dynamic, np.ndarray) else np.full(shape, dynamic, dtype = bool )
6742+
6743+ matrix_cons = np.empty(shape, dtype = object )
6744+ for idx in np.ndindex(shape):
6745+ elem_conss = [
6746+ cons[idx] if isinstance (cons, MatrixExprCons) else cons
6747+ for cons in conss
6748+ ]
6749+ matrix_cons[idx] = self .addConsDisjunction(
6750+ elem_conss,
6751+ name = matrix_names[idx],
6752+ initial = matrix_initial[idx],
6753+ relaxcons = relaxcons,
6754+ enforce = matrix_enforce[idx],
6755+ check = matrix_check[idx],
6756+ local = matrix_local[idx],
6757+ modifiable = matrix_modifiable[idx],
6758+ dynamic = matrix_dynamic[idx],
6759+ )
6760+
6761+ return matrix_cons.view(MatrixConstraint)
6762+
66466763 def getConsNVars (self , Constraint constraint ):
66476764 """
66486765 Gets number of variables in a constraint.
0 commit comments