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{
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 {
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.Offset;
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
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 offset_ = 0L;
394 }
395
396 public SumArray(LinearExpr a, long b)
397 {
398 expressions_ = new List<LinearExpr>();
399 AddExpr(a);
400 offset_ = b;
401 }
402
403 public SumArray(IEnumerable<LinearExpr> exprs)
404 {
405 expressions_ = new List<LinearExpr>(exprs);
406 offset_ = 0L;
407 }
408
409 public SumArray(IEnumerable<IntVar> vars)
410 {
411 expressions_ = new List<LinearExpr>(vars);
412 offset_ = 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 offset_ = 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 offset_ = 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 offset_ = 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 Offset
492 {
493 get {
494 return offset_;
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 offset_;
522 }
523
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 override int GetIndex()
555 {
556 return index_;
557 }
558
560 {
561 get {
562 return var_;
563 }
564 set {
565 var_ = value;
566 }
567 }
568
570 {
571 get {
572 return CpSatHelper.VariableDomain(var_);
573 }
574 }
575
576 public override string ToString()
577 {
578 return var_.ToString();
579 }
580
581 public override string ShortString()
582 {
583 if (var_.Name != null)
584 {
585 return var_.Name;
586 }
587 else
588 {
589 return var_.ToString();
590 }
591 }
592
593 public string Name()
594 {
595 return var_.Name;
596 }
597
598 public ILiteral Not()
599 {
600 foreach (long b in var_.Domain)
601 {
602 if (b < 0 || b > 1)
603 {
604 throw new ArgumentException("Cannot call Not() on a non boolean variable");
605 }
606 }
607 if (negation_ == null)
608 {
609 negation_ = new NotBooleanVariable(this);
610 }
611 return negation_;
612 }
613
614 private CpModelProto model_;
615 private int index_;
616 private IntegerVariableProto var_;
617 private NotBooleanVariable negation_;
618 }
619
621 {
623 {
624 boolvar_ = boolvar;
625 }
626
627 public override int GetIndex()
628 {
629 return -boolvar_.Index - 1;
630 }
631
632 public ILiteral Not()
633 {
634 return boolvar_;
635 }
636
637 public IntVar NotVar()
638 {
639 return boolvar_;
640 }
641
642 public override string ShortString()
643 {
644 return String.Format("Not({0})", boolvar_.ShortString());
645 }
646
647 private IntVar boolvar_;
648 }
649
651 {
652 public enum Type
653 {
654 BoundExpression,
655 VarEqVar,
656 VarDiffVar,
657 VarEqCst,
658 VarDiffCst,
659 }
660
661 public BoundedLinearExpression(long lb, LinearExpr expr, long ub)
662 {
663 left_ = expr;
664 right_ = null;
665 lb_ = lb;
666 ub_ = ub;
667 type_ = Type.BoundExpression;
668 }
669
670 public BoundedLinearExpression(LinearExpr left, LinearExpr right, bool equality)
671 {
672 left_ = left;
673 right_ = right;
674 lb_ = 0;
675 ub_ = 0;
676 type_ = equality ? Type.VarEqVar : Type.VarDiffVar;
677 }
678
679 public BoundedLinearExpression(LinearExpr left, long v, bool equality)
680 {
681 left_ = left;
682 right_ = null;
683 lb_ = v;
684 ub_ = 0;
685 type_ = equality ? Type.VarEqCst : Type.VarDiffCst;
686 }
687
688 bool IsTrue()
689 {
690 if (type_ == Type.VarEqVar)
691 {
692 return (object)left_ == (object)right_;
693 }
694 else if (type_ == Type.VarDiffVar)
695 {
696 return (object)left_ != (object)right_;
697 }
698 return false;
699 }
700
701 public static bool operator true(BoundedLinearExpression bie)
702 {
703 return bie.IsTrue();
704 }
705
706 public static bool operator false(BoundedLinearExpression bie)
707 {
708 return !bie.IsTrue();
709 }
710
711 public override string ToString()
712 {
713 switch (type_)
714 {
715 case Type.BoundExpression:
716 return String.Format("{0} <= {1} <= {2}", lb_, left_, ub_);
717 case Type.VarEqVar:
718 return String.Format("{0} == {1}", left_, right_);
719 case Type.VarDiffVar:
720 return String.Format("{0} != {1}", left_, right_);
721 case Type.VarEqCst:
722 return String.Format("{0} == {1}", left_, lb_);
723 case Type.VarDiffCst:
724 return String.Format("{0} != {1}", left_, lb_);
725 default:
726 throw new ArgumentException("Wrong mode in BoundedLinearExpression.");
727 }
728 }
729
731 {
732 if (a.CtType != Type.BoundExpression || a.Ub != Int64.MaxValue)
733 {
734 throw new ArgumentException("Operator <= not supported for this BoundedLinearExpression");
735 }
736 return new BoundedLinearExpression(a.Lb, a.Left, v);
737 }
738
740 {
741 if (a.CtType != Type.BoundExpression || a.Ub != Int64.MaxValue)
742 {
743 throw new ArgumentException("Operator < not supported for this BoundedLinearExpression");
744 }
745 return new BoundedLinearExpression(a.Lb, a.Left, v - 1);
746 }
747
749 {
750 if (a.CtType != Type.BoundExpression || a.Lb != Int64.MinValue)
751 {
752 throw new ArgumentException("Operator >= not supported for this BoundedLinearExpression");
753 }
754 return new BoundedLinearExpression(v, a.Left, a.Ub);
755 }
756
758 {
759 if (a.CtType != Type.BoundExpression || a.Lb != Int64.MinValue)
760 {
761 throw new ArgumentException("Operator < not supported for this BoundedLinearExpression");
762 }
763 return new BoundedLinearExpression(v + 1, a.Left, a.Ub);
764 }
765
767 {
768 get {
769 return left_;
770 }
771 }
772
774 {
775 get {
776 return right_;
777 }
778 }
779
780 public long Lb
781 {
782 get {
783 return lb_;
784 }
785 }
786
787 public long Ub
788 {
789 get {
790 return ub_;
791 }
792 }
793
795 {
796 get {
797 return type_;
798 }
799 }
800
801 private LinearExpr left_;
802 private LinearExpr right_;
803 private long lb_;
804 private long ub_;
805 private Type type_;
806 }
807
808} // 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:8770
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
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, 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:348
string Name
For debug/logging only.
Definition: CpModel.pb.cs:315
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 BoundedLinearExpression operator!=(LinearExpr a, LinearExpr b)
static LinearExpr operator-(LinearExpr a, LinearExpr b)
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)
long[] FlattenedIntervals()
Definition: Domain.cs:84