DotNet Reference

.Net Reference

IntegerExpressions.cs
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 namespace Google.OrTools.Sat
15 {
16  using System;
17  using System.Collections.Generic;
18  using Google.OrTools.Util;
19 
20  // Helpers.
21 
22  // IntVar[] helper class.
23  public static class IntVarArrayHelper
24  {
25  [Obsolete("This Sum method is deprecated, please use LinearExpr.Sum() instead.")]
26  public static LinearExpr Sum(this IntVar[] vars)
27  {
28  return LinearExpr.Sum(vars);
29  }
30  [Obsolete("This ScalProd method is deprecated, please use LinearExpr.ScalProd() instead.")]
31  public static LinearExpr ScalProd(this IntVar[] vars, int[] coeffs)
32  {
33  return LinearExpr.ScalProd(vars, coeffs);
34  }
35  [Obsolete("This ScalProd method is deprecated, please use LinearExpr.ScalProd() instead.")]
36  public static LinearExpr ScalProd(this IntVar[] vars, long[] coeffs)
37  {
38  return LinearExpr.ScalProd(vars, coeffs);
39  }
40  }
41 
42  public interface ILiteral
43  {
44  ILiteral Not();
45  int GetIndex();
46  }
47 
48  // Holds a linear expression.
49  public class LinearExpr
50  {
51  public static LinearExpr Sum(IEnumerable<IntVar> vars)
52  {
53  return new SumArray(vars);
54  }
55 
56  public static LinearExpr Sum(IEnumerable<LinearExpr> exprs)
57  {
58  return new SumArray(exprs);
59  }
60 
61  public static LinearExpr ScalProd(IEnumerable<IntVar> vars, IEnumerable<int> coeffs)
62  {
63  return new SumArray(vars, coeffs);
64  }
65 
66  public static LinearExpr ScalProd(IEnumerable<IntVar> vars, IEnumerable<long> coeffs)
67  {
68  return new SumArray(vars, coeffs);
69  }
70 
71  public static LinearExpr Term(IntVar var, long coeff)
72  {
73  return Prod(var, coeff);
74  }
75 
76  public static LinearExpr Affine(IntVar var, long coeff, long offset)
77  {
78  if (offset == 0)
79  {
80  return Prod(var, coeff);
81  }
82  else
83  {
84  return new SumArray(Prod(var, coeff), offset);
85  }
86  }
87 
88  public static LinearExpr Constant(long value)
89  {
90  return new ConstantExpr(value);
91  }
92 
93  public int Index
94  {
95  get {
96  return GetIndex();
97  }
98  }
99 
100  public virtual int GetIndex()
101  {
102  throw new NotImplementedException();
103  }
104 
105  public virtual string ShortString()
106  {
107  return ToString();
108  }
109 
111  {
112  return new SumArray(a, b);
113  }
114 
115  public static LinearExpr operator +(LinearExpr a, long v)
116  {
117  return new SumArray(a, v);
118  }
119 
120  public static LinearExpr operator +(long v, LinearExpr a)
121  {
122  return new SumArray(a, v);
123  }
124 
126  {
127  return new SumArray(a, Prod(b, -1));
128  }
129 
130  public static LinearExpr operator -(LinearExpr a, long v)
131  {
132  return new SumArray(a, -v);
133  }
134 
135  public static LinearExpr operator -(long v, LinearExpr a)
136  {
137  return new SumArray(Prod(a, -1), v);
138  }
139 
140  public static LinearExpr operator *(LinearExpr a, long v)
141  {
142  return Prod(a, v);
143  }
144 
145  public static LinearExpr operator *(long v, LinearExpr a)
146  {
147  return Prod(a, v);
148  }
149 
151  {
152  return Prod(a, -1);
153  }
154 
156  {
157  return new BoundedLinearExpression(a, b, true);
158  }
159 
161  {
162  return new BoundedLinearExpression(a, b, false);
163  }
164 
166  {
167  return new BoundedLinearExpression(a, v, true);
168  }
169 
171  {
172  return new BoundedLinearExpression(a, v, false);
173  }
174 
176  {
177  return new BoundedLinearExpression(v, a, Int64.MaxValue);
178  }
179 
181  {
182  return a <= v;
183  }
184 
186  {
187  return new BoundedLinearExpression(v + 1, a, Int64.MaxValue);
188  }
189 
191  {
192  return a < v;
193  }
194 
196  {
197  return new BoundedLinearExpression(Int64.MinValue, a, v);
198  }
199 
201  {
202  return a >= v;
203  }
204 
206  {
207  return new BoundedLinearExpression(Int64.MinValue, a, v - 1);
208  }
209 
211  {
212  return a > v;
213  }
214 
216  {
217  return new BoundedLinearExpression(0, a - b, Int64.MaxValue);
218  }
219 
221  {
222  return new BoundedLinearExpression(1, a - b, Int64.MaxValue);
223  }
224 
226  {
227  return new BoundedLinearExpression(Int64.MinValue, a - b, 0);
228  }
229 
231  {
232  return new BoundedLinearExpression(Int64.MinValue, a - b, -1);
233  }
234 
235  public static LinearExpr Prod(LinearExpr e, long v)
236  {
237  if (v == 1)
238  {
239  return e;
240  }
241  else if (e is ProductCst)
242  {
243  ProductCst p = (ProductCst)e;
244  return new ProductCst(p.Expr, p.Coeff * v);
245  }
246  else
247  {
248  return new ProductCst(e, v);
249  }
250  }
251 
252  public static long GetVarValueMap(LinearExpr e, long initial_coeff, Dictionary<IntVar, long> dict)
253  {
254  List<LinearExpr> exprs = new List<LinearExpr>();
255  List<long> coeffs = new List<long>();
256  if ((Object)e != null)
257  {
258  exprs.Add(e);
259  coeffs.Add(initial_coeff);
260  }
261  long constant = 0;
262 
263  while (exprs.Count > 0)
264  {
265  LinearExpr expr = exprs[0];
266  exprs.RemoveAt(0);
267  long coeff = coeffs[0];
268  coeffs.RemoveAt(0);
269  if (coeff == 0 || (Object)expr == null)
270  continue;
271 
272  if (expr is ProductCst)
273  {
274  ProductCst p = (ProductCst)expr;
275  if (p.Coeff != 0)
276  {
277  exprs.Add(p.Expr);
278  coeffs.Add(p.Coeff * coeff);
279  }
280  }
281  else if (expr is SumArray)
282  {
283  SumArray a = (SumArray)expr;
284  constant += coeff * a.Constant;
285  foreach (LinearExpr sub in a.Expressions)
286  {
287  if (sub is IntVar)
288  {
289  IntVar i = (IntVar)sub;
290  if (dict.ContainsKey(i))
291  {
292  dict[i] += coeff;
293  }
294  else
295  {
296  dict.Add(i, coeff);
297  }
298  }
299  else if (sub is ProductCst && ((ProductCst)sub).Expr is IntVar)
300  {
301  ProductCst sub_prod = (ProductCst)sub;
302  IntVar i = (IntVar)sub_prod.Expr;
303  long sub_coeff = sub_prod.Coeff;
304 
305  if (dict.ContainsKey(i))
306  {
307  dict[i] += coeff * sub_coeff;
308  }
309  else
310  {
311  dict.Add(i, coeff * sub_coeff);
312  }
313  }
314  else
315  {
316  exprs.Add(sub);
317  coeffs.Add(coeff);
318  }
319  }
320  }
321  else if (expr is ConstantExpr)
322  {
323  ConstantExpr cte = (ConstantExpr)expr;
324  constant += coeff * cte.Value;
325  }
326  else if (expr is IntVar)
327  {
328  IntVar i = (IntVar)expr;
329  if (dict.ContainsKey(i))
330  {
331  dict[i] += coeff;
332  }
333  else
334  {
335  dict.Add(i, coeff);
336  }
337  }
338  else if (expr is NotBooleanVariable)
339  {
340  IntVar i = ((NotBooleanVariable)expr).NotVar();
341  if (dict.ContainsKey(i))
342  {
343  dict[i] -= coeff;
344  }
345  else
346  {
347  dict.Add(i, -coeff);
348  }
349  constant += coeff;
350  }
351  else
352  {
353  throw new ArgumentException("Cannot interpret '" + expr.ToString() + "' in an integer expression");
354  }
355  }
356  return constant;
357  }
358  }
359 
360  public class ProductCst : LinearExpr
361  {
362  public ProductCst(LinearExpr e, long v)
363  {
364  expr_ = e;
365  coeff_ = v;
366  }
367 
368  public LinearExpr Expr
369  {
370  get {
371  return expr_;
372  }
373  }
374 
375  public long Coeff
376  {
377  get {
378  return coeff_;
379  }
380  }
381 
382  private LinearExpr expr_;
383  private long coeff_;
384  }
385 
386  public class SumArray : LinearExpr
387  {
389  {
390  expressions_ = new List<LinearExpr>();
391  AddExpr(a);
392  AddExpr(b);
393  constant_ = 0L;
394  }
395 
396  public SumArray(LinearExpr a, long b)
397  {
398  expressions_ = new List<LinearExpr>();
399  AddExpr(a);
400  constant_ = b;
401  }
402 
403  public SumArray(IEnumerable<LinearExpr> exprs)
404  {
405  expressions_ = new List<LinearExpr>(exprs);
406  constant_ = 0L;
407  }
408 
409  public SumArray(IEnumerable<IntVar> vars)
410  {
411  expressions_ = new List<LinearExpr>(vars);
412  constant_ = 0L;
413  }
414 
415  public SumArray(IntVar[] vars, long[] coeffs)
416  {
417  expressions_ = new List<LinearExpr>(vars.Length);
418  for (int i = 0; i < vars.Length; ++i)
419  {
420  AddExpr(Prod(vars[i], coeffs[i]));
421  }
422  constant_ = 0L;
423  }
424  public SumArray(IEnumerable<IntVar> vars, IEnumerable<long> coeffs)
425  {
426  List<IntVar> tmp_vars = new List<IntVar>();
427  foreach (IntVar v in vars)
428  {
429  tmp_vars.Add(v);
430  }
431  List<long> tmp_coeffs = new List<long>();
432  foreach (long c in coeffs)
433  {
434  tmp_coeffs.Add(c);
435  }
436  if (tmp_vars.Count != tmp_coeffs.Count)
437  {
438  throw new ArgumentException("in SumArray(vars, coeffs), the two lists do not have the same length");
439  }
440  IntVar[] flat_vars = tmp_vars.ToArray();
441  long[] flat_coeffs = tmp_coeffs.ToArray();
442  expressions_ = new List<LinearExpr>(flat_vars.Length);
443  for (int i = 0; i < flat_vars.Length; ++i)
444  {
445  expressions_.Add(Prod(flat_vars[i], flat_coeffs[i]));
446  }
447  constant_ = 0L;
448  }
449 
450  public SumArray(IEnumerable<IntVar> vars, IEnumerable<int> coeffs)
451  {
452  List<IntVar> tmp_vars = new List<IntVar>();
453  foreach (IntVar v in vars)
454  {
455  tmp_vars.Add(v);
456  }
457  List<long> tmp_coeffs = new List<long>();
458  foreach (int c in coeffs)
459  {
460  tmp_coeffs.Add(c);
461  }
462  if (tmp_vars.Count != tmp_coeffs.Count)
463  {
464  throw new ArgumentException("in SumArray(vars, coeffs), the two lists do not have the same length");
465  }
466  IntVar[] flat_vars = tmp_vars.ToArray();
467  long[] flat_coeffs = tmp_coeffs.ToArray();
468  expressions_ = new List<LinearExpr>(flat_vars.Length);
469  for (int i = 0; i < flat_vars.Length; ++i)
470  {
471  expressions_.Add(Prod(flat_vars[i], flat_coeffs[i]));
472  }
473  constant_ = 0L;
474  }
475 
476  public void AddExpr(LinearExpr expr)
477  {
478  if ((Object)expr != null)
479  {
480  expressions_.Add(expr);
481  }
482  }
483 
484  public List<LinearExpr> Expressions
485  {
486  get {
487  return expressions_;
488  }
489  }
490 
491  public long Constant
492  {
493  get {
494  return constant_;
495  }
496  }
497 
498  public override string ShortString()
499  {
500  return String.Format("({0})", ToString());
501  }
502 
503  public override string ToString()
504  {
505  string result = "";
506  foreach (LinearExpr expr in expressions_)
507  {
508  if ((Object)expr == null)
509  continue;
510  if (!String.IsNullOrEmpty(result))
511  {
512  result += String.Format(" + ");
513  }
514 
515  result += expr.ShortString();
516  }
517  return result;
518  }
519 
520  private List<LinearExpr> expressions_;
521  private long constant_;
522  }
523 
524  public class ConstantExpr : LinearExpr
525  {
526  public ConstantExpr(long value)
527  {
528  value_ = value;
529  }
530 
531  public long Value
532  {
533  get {
534  return value_;
535  }
536  }
537 
538  private long value_;
539  }
540 
541  public class IntVar : LinearExpr, ILiteral
542  {
543  public IntVar(CpModelProto model, Domain domain, string name)
544  {
545  model_ = model;
546  index_ = model.Variables.Count;
547  var_ = new IntegerVariableProto();
548  var_.Name = name;
549  var_.Domain.Add(domain.FlattenedIntervals());
550  model.Variables.Add(var_);
551  negation_ = null;
552  }
553 
554  public int Index
555  {
556  get {
557  return index_;
558  }
559  }
560 
561  public override int GetIndex()
562  {
563  return index_;
564  }
565 
567  {
568  get {
569  return var_;
570  }
571  set {
572  var_ = value;
573  }
574  }
575 
576  public Domain Domain
577  {
578  get {
579  return CpSatHelper.VariableDomain(var_);
580  }
581  }
582 
583  public override string ToString()
584  {
585  return var_.ToString();
586  }
587 
588  public override string ShortString()
589  {
590  if (var_.Name != null)
591  {
592  return var_.Name;
593  }
594  else
595  {
596  return var_.ToString();
597  }
598  }
599 
600  public string Name()
601  {
602  return var_.Name;
603  }
604 
605  public ILiteral Not()
606  {
607  foreach (long b in var_.Domain)
608  {
609  if (b < 0 || b > 1)
610  {
611  throw new ArgumentException("Cannot call Not() on a non boolean variable");
612  }
613  }
614  if (negation_ == null)
615  {
616  negation_ = new NotBooleanVariable(this);
617  }
618  return negation_;
619  }
620 
621  private CpModelProto model_;
622  private int index_;
623  private List<long> bounds_;
624  private IntegerVariableProto var_;
625  private NotBooleanVariable negation_;
626  }
627 
629  {
630  public NotBooleanVariable(IntVar boolvar)
631  {
632  boolvar_ = boolvar;
633  }
634 
635  public override int GetIndex()
636  {
637  return -boolvar_.Index - 1;
638  }
639 
640  public ILiteral Not()
641  {
642  return boolvar_;
643  }
644 
645  public IntVar NotVar()
646  {
647  return boolvar_;
648  }
649 
650  public override string ShortString()
651  {
652  return String.Format("Not({0})", boolvar_.ShortString());
653  }
654 
655  private IntVar boolvar_;
656  }
657 
659  {
660  public enum Type
661  {
662  BoundExpression,
663  VarEqVar,
664  VarDiffVar,
665  VarEqCst,
666  VarDiffCst,
667  }
668 
669  public BoundedLinearExpression(long lb, LinearExpr expr, long ub)
670  {
671  left_ = expr;
672  right_ = null;
673  lb_ = lb;
674  ub_ = ub;
675  type_ = Type.BoundExpression;
676  }
677 
678  public BoundedLinearExpression(LinearExpr left, LinearExpr right, bool equality)
679  {
680  left_ = left;
681  right_ = right;
682  lb_ = 0;
683  ub_ = 0;
684  type_ = equality ? Type.VarEqVar : Type.VarDiffVar;
685  }
686 
687  public BoundedLinearExpression(LinearExpr left, long v, bool equality)
688  {
689  left_ = left;
690  right_ = null;
691  lb_ = v;
692  ub_ = 0;
693  type_ = equality ? Type.VarEqCst : Type.VarDiffCst;
694  }
695 
696  bool IsTrue()
697  {
698  if (type_ == Type.VarEqVar)
699  {
700  return (object)left_ == (object)right_;
701  }
702  else if (type_ == Type.VarDiffVar)
703  {
704  return (object)left_ != (object)right_;
705  }
706  return false;
707  }
708 
709  public static bool operator true(BoundedLinearExpression bie)
710  {
711  return bie.IsTrue();
712  }
713 
714  public static bool operator false(BoundedLinearExpression bie)
715  {
716  return !bie.IsTrue();
717  }
718 
719  public override string ToString()
720  {
721  switch (type_)
722  {
723  case Type.BoundExpression:
724  return String.Format("{0} <= {1} <= {2}", lb_, left_, ub_);
725  case Type.VarEqVar:
726  return String.Format("{0} == {1}", left_, right_);
727  case Type.VarDiffVar:
728  return String.Format("{0} != {1}", left_, right_);
729  case Type.VarEqCst:
730  return String.Format("{0} == {1}", left_, lb_);
731  case Type.VarDiffCst:
732  return String.Format("{0} != {1}", left_, lb_);
733  default:
734  throw new ArgumentException("Wrong mode in BoundedLinearExpression.");
735  }
736  }
737 
739  {
740  if (a.CtType != Type.BoundExpression || a.Ub != Int64.MaxValue)
741  {
742  throw new ArgumentException("Operator <= not supported for this BoundedLinearExpression");
743  }
744  return new BoundedLinearExpression(a.Lb, a.Left, v);
745  }
746 
748  {
749  if (a.CtType != Type.BoundExpression || a.Ub != Int64.MaxValue)
750  {
751  throw new ArgumentException("Operator < not supported for this BoundedLinearExpression");
752  }
753  return new BoundedLinearExpression(a.Lb, a.Left, v - 1);
754  }
755 
757  {
758  if (a.CtType != Type.BoundExpression || a.Lb != Int64.MinValue)
759  {
760  throw new ArgumentException("Operator >= not supported for this BoundedLinearExpression");
761  }
762  return new BoundedLinearExpression(v, a.Left, a.Ub);
763  }
764 
766  {
767  if (a.CtType != Type.BoundExpression || a.Lb != Int64.MinValue)
768  {
769  throw new ArgumentException("Operator < not supported for this BoundedLinearExpression");
770  }
771  return new BoundedLinearExpression(v + 1, a.Left, a.Ub);
772  }
773 
774  public LinearExpr Left
775  {
776  get {
777  return left_;
778  }
779  }
780 
781  public LinearExpr Right
782  {
783  get {
784  return right_;
785  }
786  }
787 
788  public long Lb
789  {
790  get {
791  return lb_;
792  }
793  }
794 
795  public long Ub
796  {
797  get {
798  return ub_;
799  }
800  }
801 
802  public Type CtType
803  {
804  get {
805  return type_;
806  }
807  }
808 
809  private LinearExpr left_;
810  private LinearExpr right_;
811  private long lb_;
812  private long ub_;
813  private Type type_;
814  }
815 
816 } // namespace Google.OrTools.Sat
static BoundedLinearExpression operator>(long v, LinearExpr a)
static LinearExpr operator -(LinearExpr a)
static long GetVarValueMap(LinearExpr e, long initial_coeff, Dictionary< IntVar, long > dict)
static LinearExpr Constant(long value)
SumArray(IEnumerable< IntVar > vars, IEnumerable< int > coeffs)
static LinearExpr Sum(this IntVar[] vars)
SumArray(LinearExpr a, long b)
BoundedLinearExpression(long lb, LinearExpr expr, long ub)
static LinearExpr operator -(LinearExpr a, long v)
static LinearExpr ScalProd(this IntVar[] vars, int[] coeffs)
static BoundedLinearExpression operator>(LinearExpr a, LinearExpr b)
long [] FlattenedIntervals()
Definition: Domain.cs:84
static BoundedLinearExpression operator<(long v, LinearExpr a)
static BoundedLinearExpression operator !=(LinearExpr a, LinearExpr b)
static LinearExpr Term(IntVar var, long coeff)
static LinearExpr operator *(long v, LinearExpr a)
static BoundedLinearExpression operator >=(long v, LinearExpr a)
ProductCst(LinearExpr e, long v)
static LinearExpr operator -(LinearExpr a, LinearExpr b)
static BoundedLinearExpression operator >=(BoundedLinearExpression a, long v)
static BoundedLinearExpression operator !=(LinearExpr a, long v)
static LinearExpr ScalProd(this IntVar[] vars, long[] coeffs)
static Domain VariableDomain(Google.OrTools.Sat.IntegerVariableProto variable_proto)
Definition: CpSatHelper.cs:64
static BoundedLinearExpression operator>(BoundedLinearExpression a, long v)
static BoundedLinearExpression operator>(LinearExpr a, long v)
IntVar(CpModelProto model, Domain domain, string name)
SumArray(IEnumerable< LinearExpr > exprs)
static BoundedLinearExpression operator<(LinearExpr a, long v)
static BoundedLinearExpression operator >=(LinearExpr a, LinearExpr b)
static LinearExpr Affine(IntVar var, long coeff, long offset)
static LinearExpr operator *(LinearExpr a, long v)
A constraint programming problem.
Definition: CpModel.pb.cs:8766
static BoundedLinearExpression operator<(LinearExpr a, LinearExpr b)
static BoundedLinearExpression operator<=(BoundedLinearExpression a, long v)
pbc::RepeatedField< global::Google.OrTools.Sat.IntegerVariableProto > Variables
The associated Protos should be referred by their index in these fields.
Definition: CpModel.pb.cs:8842
SumArray(IntVar[] vars, long[] coeffs)
SumArray(LinearExpr a, LinearExpr b)
BoundedLinearExpression(LinearExpr left, long v, bool equality)
pbc::RepeatedField< long > Domain
The variable domain given as a sorted list of n disjoint intervals [min, max] and encoded as [min_0,...
Definition: CpModel.pb.cs:348
static LinearExpr ScalProd(IEnumerable< IntVar > vars, IEnumerable< int > coeffs)
static BoundedLinearExpression operator==(LinearExpr a, LinearExpr b)
string Name
For debug/logging only.
Definition: CpModel.pb.cs:315
static LinearExpr ScalProd(IEnumerable< IntVar > vars, IEnumerable< long > coeffs)
static LinearExpr Sum(IEnumerable< IntVar > vars)
static BoundedLinearExpression operator<(BoundedLinearExpression a, long v)
SumArray(IEnumerable< IntVar > vars)
SumArray(IEnumerable< IntVar > vars, IEnumerable< long > coeffs)
static BoundedLinearExpression operator<=(LinearExpr a, long v)
static LinearExpr operator+(LinearExpr a, LinearExpr b)
void AddExpr(LinearExpr expr)
static LinearExpr operator -(long v, LinearExpr a)
static LinearExpr Prod(LinearExpr e, long v)
IntegerVariableProto Proto
static LinearExpr Sum(IEnumerable< LinearExpr > exprs)
static BoundedLinearExpression operator >=(LinearExpr a, long v)
BoundedLinearExpression(LinearExpr left, LinearExpr right, bool equality)