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
14namespace Google.OrTools.Sat
15{
16using System;
17using System.Collections.Generic;
18using Google.OrTools.Util;
19
20// Helpers.
21
22// IntVar[] helper class.
23public 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
42public interface ILiteral
43{
45 int GetIndex();
46}
47
48// Holds a linear expression.
49public 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 if (v == 0)
118 {
119 return a;
120 }
121 return new SumArray(a, v);
122 }
123
124 public static LinearExpr operator +(long v, LinearExpr a)
125 {
126 if (v == 0)
127 {
128 return a;
129 }
130 return new SumArray(a, v);
131 }
132
134 {
135 return new SumArray(a, Prod(b, -1));
136 }
137
138 public static LinearExpr operator -(LinearExpr a, long v)
139 {
140 if (v == 0)
141 {
142 return a;
143 }
144 return new SumArray(a, -v);
145 }
146
147 public static LinearExpr operator -(long v, LinearExpr a)
148 {
149 if (v == 0)
150 {
151 return Prod(a, -1);
152 }
153 return new SumArray(Prod(a, -1), v);
154 }
155
156 public static LinearExpr operator *(LinearExpr a, long v)
157 {
158 return Prod(a, v);
159 }
160
161 public static LinearExpr operator *(long v, LinearExpr a)
162 {
163 return Prod(a, v);
164 }
165
167 {
168 return Prod(a, -1);
169 }
170
172 {
173 return new BoundedLinearExpression(a, b, true);
174 }
175
177 {
178 return new BoundedLinearExpression(a, b, false);
179 }
180
182 {
183 return new BoundedLinearExpression(a, v, true);
184 }
185
187 {
188 return new BoundedLinearExpression(a, v, false);
189 }
190
192 {
193 return new BoundedLinearExpression(v, a, Int64.MaxValue);
194 }
195
197 {
198 return a <= v;
199 }
200
202 {
203 return new BoundedLinearExpression(v + 1, a, Int64.MaxValue);
204 }
205
207 {
208 return a < v;
209 }
210
212 {
213 return new BoundedLinearExpression(Int64.MinValue, a, v);
214 }
215
217 {
218 return a >= v;
219 }
220
222 {
223 return new BoundedLinearExpression(Int64.MinValue, a, v - 1);
224 }
225
227 {
228 return a > v;
229 }
230
232 {
233 return new BoundedLinearExpression(0, a - b, Int64.MaxValue);
234 }
235
237 {
238 return new BoundedLinearExpression(1, a - b, Int64.MaxValue);
239 }
240
242 {
243 return new BoundedLinearExpression(Int64.MinValue, a - b, 0);
244 }
245
247 {
248 return new BoundedLinearExpression(Int64.MinValue, a - b, -1);
249 }
250
251 public static LinearExpr Prod(LinearExpr e, long v)
252 {
253 if (v == 1)
254 {
255 return e;
256 }
257 else if (e is ProductCst)
258 {
259 ProductCst p = (ProductCst)e;
260 return new ProductCst(p.Expr, p.Coeff * v);
261 }
262 else
263 {
264 return new ProductCst(e, v);
265 }
266 }
267
268 public static long GetVarValueMap(LinearExpr e, long initial_coeff, Dictionary<IntVar, long> dict)
269 {
270 List<LinearExpr> exprs = new List<LinearExpr>();
271 List<long> coeffs = new List<long>();
272 if ((Object)e != null)
273 {
274 exprs.Add(e);
275 coeffs.Add(initial_coeff);
276 }
277 long constant = 0;
278
279 while (exprs.Count > 0)
280 {
281 LinearExpr expr = exprs[0];
282 exprs.RemoveAt(0);
283 long coeff = coeffs[0];
284 coeffs.RemoveAt(0);
285 if (coeff == 0 || (Object)expr == null)
286 continue;
287
288 if (expr is ProductCst)
289 {
290 ProductCst p = (ProductCst)expr;
291 if (p.Coeff != 0)
292 {
293 exprs.Add(p.Expr);
294 coeffs.Add(p.Coeff * coeff);
295 }
296 }
297 else if (expr is SumArray)
298 {
299 SumArray a = (SumArray)expr;
300 constant += coeff * a.Offset;
301 foreach (LinearExpr sub in a.Expressions)
302 {
303 if (sub is IntVar)
304 {
305 IntVar i = (IntVar)sub;
306 if (dict.ContainsKey(i))
307 {
308 dict[i] += coeff;
309 }
310 else
311 {
312 dict.Add(i, coeff);
313 }
314 }
315 else if (sub is ProductCst && ((ProductCst)sub).Expr is IntVar)
316 {
317 ProductCst sub_prod = (ProductCst)sub;
318 IntVar i = (IntVar)sub_prod.Expr;
319 long sub_coeff = sub_prod.Coeff;
320
321 if (dict.ContainsKey(i))
322 {
323 dict[i] += coeff * sub_coeff;
324 }
325 else
326 {
327 dict.Add(i, coeff * sub_coeff);
328 }
329 }
330 else
331 {
332 exprs.Add(sub);
333 coeffs.Add(coeff);
334 }
335 }
336 }
337 else if (expr is ConstantExpr)
338 {
339 ConstantExpr cte = (ConstantExpr)expr;
340 constant += coeff * cte.Value;
341 }
342 else if (expr is IntVar)
343 {
344 IntVar i = (IntVar)expr;
345 if (dict.ContainsKey(i))
346 {
347 dict[i] += coeff;
348 }
349 else
350 {
351 dict.Add(i, coeff);
352 }
353 }
354 else if (expr is NotBooleanVariable)
355 {
356 IntVar i = ((NotBooleanVariable)expr).NotVar();
357 if (dict.ContainsKey(i))
358 {
359 dict[i] -= coeff;
360 }
361 else
362 {
363 dict.Add(i, -coeff);
364 }
365 constant += coeff;
366 }
367 else
368 {
369 throw new ArgumentException("Cannot interpret '" + expr.ToString() + "' in an integer expression");
370 }
371 }
372 return constant;
373 }
374
376 {
377 int numElements = proto.Vars.Count;
378 long offset = proto.Offset;
379 if (numElements == 0)
380 {
381 return LinearExpr.Constant(offset);
382 }
383 else if (numElements == 1)
384 {
385 IntVar var = new IntVar(model, proto.Vars[0]);
386 long coeff = proto.Coeffs[0];
387 return LinearExpr.Affine(var, coeff, offset);
388 }
389 else
390 {
391 LinearExpr[] exprs = new LinearExpr[numElements];
392 for (int i = 0; i < numElements; ++i)
393 {
394 IntVar var = new IntVar(model, proto.Vars[i]);
395 long coeff = proto.Coeffs[i];
396 exprs[i] = Prod(var, coeff);
397 }
398 SumArray sum = new SumArray(exprs);
399 sum.Offset = sum.Offset + offset;
400 return sum;
401 }
402 }
403}
404
405public class ProductCst : LinearExpr
406{
407 public ProductCst(LinearExpr e, long v)
408 {
409 expr_ = e;
410 coeff_ = v;
411 }
412
414 {
415 get {
416 return expr_;
417 }
418 }
419
420 public long Coeff
421 {
422 get {
423 return coeff_;
424 }
425 }
426
427 private LinearExpr expr_;
428 private long coeff_;
429}
430
431public class SumArray : LinearExpr
432{
434 {
435 expressions_ = new List<LinearExpr>();
436 AddExpr(a);
437 AddExpr(b);
438 offset_ = 0L;
439 }
440
441 public SumArray(LinearExpr a, long b)
442 {
443 expressions_ = new List<LinearExpr>();
444 AddExpr(a);
445 offset_ = b;
446 }
447
448 public SumArray(IEnumerable<LinearExpr> exprs)
449 {
450 expressions_ = new List<LinearExpr>(exprs);
451 offset_ = 0L;
452 }
453
454 public SumArray(IEnumerable<IntVar> vars)
455 {
456 expressions_ = new List<LinearExpr>(vars);
457 offset_ = 0L;
458 }
459
460 public SumArray(IntVar[] vars, long[] coeffs)
461 {
462 expressions_ = new List<LinearExpr>(vars.Length);
463 for (int i = 0; i < vars.Length; ++i)
464 {
465 AddExpr(Prod(vars[i], coeffs[i]));
466 }
467 offset_ = 0L;
468 }
469
470 public SumArray(IEnumerable<IntVar> vars, IEnumerable<long> coeffs)
471 {
472 List<IntVar> tmp_vars = new List<IntVar>();
473 foreach (IntVar v in vars)
474 {
475 tmp_vars.Add(v);
476 }
477 List<long> tmp_coeffs = new List<long>();
478 foreach (long c in coeffs)
479 {
480 tmp_coeffs.Add(c);
481 }
482 if (tmp_vars.Count != tmp_coeffs.Count)
483 {
484 throw new ArgumentException("in SumArray(vars, coeffs), the two lists do not have the same length");
485 }
486 IntVar[] flat_vars = tmp_vars.ToArray();
487 long[] flat_coeffs = tmp_coeffs.ToArray();
488 expressions_ = new List<LinearExpr>(flat_vars.Length);
489 for (int i = 0; i < flat_vars.Length; ++i)
490 {
491 expressions_.Add(Prod(flat_vars[i], flat_coeffs[i]));
492 }
493 offset_ = 0L;
494 }
495
496 public SumArray(IEnumerable<IntVar> vars, IEnumerable<int> coeffs)
497 {
498 List<IntVar> tmp_vars = new List<IntVar>();
499 foreach (IntVar v in vars)
500 {
501 tmp_vars.Add(v);
502 }
503 List<long> tmp_coeffs = new List<long>();
504 foreach (int c in coeffs)
505 {
506 tmp_coeffs.Add(c);
507 }
508 if (tmp_vars.Count != tmp_coeffs.Count)
509 {
510 throw new ArgumentException("in SumArray(vars, coeffs), the two lists do not have the same length");
511 }
512 IntVar[] flat_vars = tmp_vars.ToArray();
513 long[] flat_coeffs = tmp_coeffs.ToArray();
514 expressions_ = new List<LinearExpr>(flat_vars.Length);
515 for (int i = 0; i < flat_vars.Length; ++i)
516 {
517 expressions_.Add(Prod(flat_vars[i], flat_coeffs[i]));
518 }
519 offset_ = 0L;
520 }
521
522 public void AddExpr(LinearExpr expr)
523 {
524 if ((Object)expr != null)
525 {
526 expressions_.Add(expr);
527 }
528 }
529
530 public List<LinearExpr> Expressions
531 {
532 get {
533 return expressions_;
534 }
535 }
536
537 public long Offset
538 {
539 get {
540 return offset_;
541 }
542 set {
543 offset_ = value;
544 }
545 }
546
547 public override string ShortString()
548 {
549 return String.Format("({0})", ToString());
550 }
551
552 public override string ToString()
553 {
554 string result = "";
555 foreach (LinearExpr expr in expressions_)
556 {
557 if ((Object)expr == null)
558 continue;
559 if (!String.IsNullOrEmpty(result))
560 {
561 result += String.Format(" + ");
562 }
563
564 result += expr.ShortString();
565 }
566 if (offset_ != 0)
567 {
568 result += String.Format(" + {0}", offset_);
569 }
570 return result;
571 }
572
573 private List<LinearExpr> expressions_;
574 private long offset_;
575}
576
578{
579 public ConstantExpr(long value)
580 {
581 value_ = value;
582 }
583
584 public long Value
585 {
586 get {
587 return value_;
588 }
589 }
590
591 public override string ShortString()
592 {
593 return String.Format("{0}", value_);
594 }
595
596 public override string ToString()
597 {
598 return String.Format("ConstantExpr({0})", value_);
599 }
600
601 private long value_;
602}
603
605{
606 public IntVar(CpModelProto model, Domain domain, string name)
607 {
608 model_ = model;
609 index_ = model.Variables.Count;
610 var_ = new IntegerVariableProto();
611 var_.Name = name;
612 var_.Domain.Add(domain.FlattenedIntervals());
613 model.Variables.Add(var_);
614 negation_ = null;
615 }
616
617 public IntVar(CpModelProto model, int index)
618 {
619 model_ = model;
620 index_ = index;
621 var_ = model.Variables[index];
622 negation_ = null;
623 }
624
625 public override int GetIndex()
626 {
627 return index_;
628 }
629
631 {
632 get {
633 return var_;
634 }
635 set {
636 var_ = value;
637 }
638 }
639
641 {
642 get {
643 return CpSatHelper.VariableDomain(var_);
644 }
645 }
646
647 public override string ToString()
648 {
649 return var_.ToString();
650 }
651
652 public override string ShortString()
653 {
654 if (var_.Name != null)
655 {
656 return var_.Name;
657 }
658 else
659 {
660 return var_.ToString();
661 }
662 }
663
664 public string Name()
665 {
666 return var_.Name;
667 }
668
669 public ILiteral Not()
670 {
671 foreach (long b in var_.Domain)
672 {
673 if (b < 0 || b > 1)
674 {
675 throw new ArgumentException("Cannot call Not() on a non boolean variable");
676 }
677 }
678 if (negation_ == null)
679 {
680 negation_ = new NotBooleanVariable(this);
681 }
682 return negation_;
683 }
684
685 private CpModelProto model_;
686 private int index_;
687 private IntegerVariableProto var_;
688 private NotBooleanVariable negation_;
689}
690
692{
694 {
695 boolvar_ = boolvar;
696 }
697
698 public override int GetIndex()
699 {
700 return -boolvar_.Index - 1;
701 }
702
703 public ILiteral Not()
704 {
705 return boolvar_;
706 }
707
708 public IntVar NotVar()
709 {
710 return boolvar_;
711 }
712
713 public override string ShortString()
714 {
715 return String.Format("Not({0})", boolvar_.ShortString());
716 }
717
718 private IntVar boolvar_;
719}
720
722{
723 public enum Type
724 {
725 BoundExpression,
726 VarEqVar,
727 VarDiffVar,
728 VarEqCst,
729 VarDiffCst,
730 }
731
732 public BoundedLinearExpression(long lb, LinearExpr expr, long ub)
733 {
734 left_ = expr;
735 right_ = null;
736 lb_ = lb;
737 ub_ = ub;
738 type_ = Type.BoundExpression;
739 }
740
741 public BoundedLinearExpression(LinearExpr left, LinearExpr right, bool equality)
742 {
743 left_ = left;
744 right_ = right;
745 lb_ = 0;
746 ub_ = 0;
747 type_ = equality ? Type.VarEqVar : Type.VarDiffVar;
748 }
749
750 public BoundedLinearExpression(LinearExpr left, long v, bool equality)
751 {
752 left_ = left;
753 right_ = null;
754 lb_ = v;
755 ub_ = 0;
756 type_ = equality ? Type.VarEqCst : Type.VarDiffCst;
757 }
758
759 bool IsTrue()
760 {
761 if (type_ == Type.VarEqVar)
762 {
763 return (object)left_ == (object)right_;
764 }
765 else if (type_ == Type.VarDiffVar)
766 {
767 return (object)left_ != (object)right_;
768 }
769 return false;
770 }
771
772 public static bool operator true(BoundedLinearExpression bie)
773 {
774 return bie.IsTrue();
775 }
776
777 public static bool operator false(BoundedLinearExpression bie)
778 {
779 return !bie.IsTrue();
780 }
781
782 public override string ToString()
783 {
784 switch (type_)
785 {
786 case Type.BoundExpression:
787 return String.Format("{0} <= {1} <= {2}", lb_, left_, ub_);
788 case Type.VarEqVar:
789 return String.Format("{0} == {1}", left_, right_);
790 case Type.VarDiffVar:
791 return String.Format("{0} != {1}", left_, right_);
792 case Type.VarEqCst:
793 return String.Format("{0} == {1}", left_, lb_);
794 case Type.VarDiffCst:
795 return String.Format("{0} != {1}", left_, lb_);
796 default:
797 throw new ArgumentException("Wrong mode in BoundedLinearExpression.");
798 }
799 }
800
802 {
803 if (a.CtType != Type.BoundExpression || a.Ub != Int64.MaxValue)
804 {
805 throw new ArgumentException("Operator <= not supported for this BoundedLinearExpression");
806 }
807 return new BoundedLinearExpression(a.Lb, a.Left, v);
808 }
809
811 {
812 if (a.CtType != Type.BoundExpression || a.Ub != Int64.MaxValue)
813 {
814 throw new ArgumentException("Operator < not supported for this BoundedLinearExpression");
815 }
816 return new BoundedLinearExpression(a.Lb, a.Left, v - 1);
817 }
818
820 {
821 if (a.CtType != Type.BoundExpression || a.Lb != Int64.MinValue)
822 {
823 throw new ArgumentException("Operator >= not supported for this BoundedLinearExpression");
824 }
825 return new BoundedLinearExpression(v, a.Left, a.Ub);
826 }
827
829 {
830 if (a.CtType != Type.BoundExpression || a.Lb != Int64.MinValue)
831 {
832 throw new ArgumentException("Operator < not supported for this BoundedLinearExpression");
833 }
834 return new BoundedLinearExpression(v + 1, a.Left, a.Ub);
835 }
836
838 {
839 get {
840 return left_;
841 }
842 }
843
845 {
846 get {
847 return right_;
848 }
849 }
850
851 public long Lb
852 {
853 get {
854 return lb_;
855 }
856 }
857
858 public long Ub
859 {
860 get {
861 return ub_;
862 }
863 }
864
866 {
867 get {
868 return type_;
869 }
870 }
871
872 private LinearExpr left_;
873 private LinearExpr right_;
874 private long lb_;
875 private long ub_;
876 private Type type_;
877}
878
879} // namespace Google.OrTools.Sat
static BoundedLinearExpression operator<=(BoundedLinearExpression a, long v)
BoundedLinearExpression(long lb, LinearExpr expr, long ub)
BoundedLinearExpression(LinearExpr left, LinearExpr right, bool equality)
BoundedLinearExpression(LinearExpr left, long v, bool equality)
static BoundedLinearExpression operator<(BoundedLinearExpression a, long v)
static BoundedLinearExpression operator>(BoundedLinearExpression a, long v)
static BoundedLinearExpression operator>=(BoundedLinearExpression a, long v)
A constraint programming problem.
Definition: CpModel.pb.cs:8645
pbc::RepeatedField< global::Google.OrTools.Sat.IntegerVariableProto > Variables
The associated Protos should be referred by their index in these fields.
Definition: CpModel.pb.cs:8718
static Domain VariableDomain(Google.OrTools.Sat.IntegerVariableProto variable_proto)
Definition: CpSatHelper.cs:64
static LinearExpr ScalProd(this IntVar[] vars, long[] coeffs)
static LinearExpr Sum(this IntVar[] vars)
static LinearExpr ScalProd(this IntVar[] vars, int[] coeffs)
IntVar(CpModelProto model, int index)
IntVar(CpModelProto model, Domain domain, string name)
IntegerVariableProto Proto
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:354
string Name
For debug/logging only.
Definition: CpModel.pb.cs:321
static LinearExpr operator*(LinearExpr a, long v)
static LinearExpr Constant(long value)
static LinearExpr Term(IntVar var, long coeff)
static LinearExpr Sum(IEnumerable< LinearExpr > exprs)
static BoundedLinearExpression operator<(LinearExpr a, long v)
static BoundedLinearExpression operator==(LinearExpr a, LinearExpr b)
static BoundedLinearExpression operator>(LinearExpr a, long v)
static LinearExpr Affine(IntVar var, long coeff, long offset)
static BoundedLinearExpression operator>=(LinearExpr a, long v)
static BoundedLinearExpression operator<=(LinearExpr a, long v)
static LinearExpr Prod(LinearExpr e, long v)
static LinearExpr ScalProd(IEnumerable< IntVar > vars, IEnumerable< long > coeffs)
static LinearExpr ScalProd(IEnumerable< IntVar > vars, IEnumerable< int > coeffs)
static LinearExpr operator+(LinearExpr a, LinearExpr b)
static BoundedLinearExpression operator<(LinearExpr a, LinearExpr b)
static BoundedLinearExpression operator>(LinearExpr a, LinearExpr b)
static BoundedLinearExpression operator<(long v, LinearExpr a)
static long GetVarValueMap(LinearExpr e, long initial_coeff, Dictionary< IntVar, long > dict)
static BoundedLinearExpression operator>(long v, LinearExpr a)
static LinearExpr Sum(IEnumerable< IntVar > vars)
static LinearExpr RebuildLinearExprFromLinearExpressionProto(LinearExpressionProto proto, CpModelProto model)
static BoundedLinearExpression operator!=(LinearExpr a, LinearExpr b)
static LinearExpr operator-(LinearExpr a, LinearExpr b)
Some constraints supports linear expression instead of just using a reference to a variable.
Definition: CpModel.pb.cs:699
pbc::RepeatedField< int > Vars
Definition: CpModel.pb.cs:748
pbc::RepeatedField< long > Coeffs
Definition: CpModel.pb.cs:759
ProductCst(LinearExpr e, long v)
SumArray(LinearExpr a, long b)
SumArray(IEnumerable< IntVar > vars, IEnumerable< long > coeffs)
void AddExpr(LinearExpr expr)
SumArray(IEnumerable< IntVar > vars)
SumArray(IEnumerable< IntVar > vars, IEnumerable< int > coeffs)
SumArray(IntVar[] vars, long[] coeffs)
SumArray(LinearExpr a, LinearExpr b)
SumArray(IEnumerable< LinearExpr > exprs)