github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/resolver/solver/constraints.go (about)

     1  package solver
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/go-air/gini/logic"
     8  	"github.com/go-air/gini/z"
     9  )
    10  
    11  // Constraint implementations limit the circumstances under which a
    12  // particular Variable can appear in a solution.
    13  type Constraint interface {
    14  	String(subject Identifier) string
    15  	apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit
    16  	order() []Identifier
    17  	anchor() bool
    18  }
    19  
    20  // zeroConstraint is returned by ConstraintOf in error cases.
    21  type zeroConstraint struct{}
    22  
    23  var _ Constraint = zeroConstraint{}
    24  
    25  func (zeroConstraint) String(subject Identifier) string {
    26  	return ""
    27  }
    28  
    29  func (zeroConstraint) apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit {
    30  	return z.LitNull
    31  }
    32  
    33  func (zeroConstraint) order() []Identifier {
    34  	return nil
    35  }
    36  
    37  func (zeroConstraint) anchor() bool {
    38  	return false
    39  }
    40  
    41  // AppliedConstraint values compose a single Constraint with the
    42  // Variable it applies to.
    43  type AppliedConstraint struct {
    44  	Variable   Variable
    45  	Constraint Constraint
    46  }
    47  
    48  // String implements fmt.Stringer and returns a human-readable message
    49  // representing the receiver.
    50  func (a AppliedConstraint) String() string {
    51  	return a.Constraint.String(a.Variable.Identifier())
    52  }
    53  
    54  type mandatory struct{}
    55  
    56  func (constraint mandatory) String(subject Identifier) string {
    57  	return fmt.Sprintf("%s is mandatory", subject)
    58  }
    59  
    60  func (constraint mandatory) apply(_ *logic.C, lm *litMapping, subject Identifier) z.Lit {
    61  	return lm.LitOf(subject)
    62  }
    63  
    64  func (constraint mandatory) order() []Identifier {
    65  	return nil
    66  }
    67  
    68  func (constraint mandatory) anchor() bool {
    69  	return true
    70  }
    71  
    72  // Mandatory returns a Constraint that will permit only solutions that
    73  // contain a particular Variable.
    74  func Mandatory() Constraint {
    75  	return mandatory{}
    76  }
    77  
    78  type prohibited struct{}
    79  
    80  func (constraint prohibited) String(subject Identifier) string {
    81  	return fmt.Sprintf("%s is prohibited", subject)
    82  }
    83  
    84  func (constraint prohibited) apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit {
    85  	return lm.LitOf(subject).Not()
    86  }
    87  
    88  func (constraint prohibited) order() []Identifier {
    89  	return nil
    90  }
    91  
    92  func (constraint prohibited) anchor() bool {
    93  	return false
    94  }
    95  
    96  // Prohibited returns a Constraint that will reject any solution that
    97  // contains a particular Variable. Callers may also decide to omit
    98  // an Variable from input to Solve rather than apply such a
    99  // Constraint.
   100  func Prohibited() Constraint {
   101  	return prohibited{}
   102  }
   103  
   104  type dependency []Identifier
   105  
   106  func (constraint dependency) String(subject Identifier) string {
   107  	if len(constraint) == 0 {
   108  		return fmt.Sprintf("%s has a dependency without any candidates to satisfy it", subject)
   109  	}
   110  	s := make([]string, len(constraint))
   111  	for i, each := range constraint {
   112  		s[i] = string(each)
   113  	}
   114  	return fmt.Sprintf("%s requires at least one of %s", subject, strings.Join(s, ", "))
   115  }
   116  
   117  func (constraint dependency) apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit {
   118  	m := lm.LitOf(subject).Not()
   119  	for _, each := range constraint {
   120  		m = c.Or(m, lm.LitOf(each))
   121  	}
   122  	return m
   123  }
   124  
   125  func (constraint dependency) order() []Identifier {
   126  	return constraint
   127  }
   128  
   129  func (constraint dependency) anchor() bool {
   130  	return false
   131  }
   132  
   133  // Dependency returns a Constraint that will only permit solutions
   134  // containing a given Variable on the condition that at least one
   135  // of the Variables identified by the given Identifiers also
   136  // appears in the solution. Identifiers appearing earlier in the
   137  // argument list have higher preference than those appearing later.
   138  func Dependency(ids ...Identifier) Constraint {
   139  	return dependency(ids)
   140  }
   141  
   142  type conflict Identifier
   143  
   144  func (constraint conflict) String(subject Identifier) string {
   145  	return fmt.Sprintf("%s conflicts with %s", subject, constraint)
   146  }
   147  
   148  func (constraint conflict) apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit {
   149  	return c.Or(lm.LitOf(subject).Not(), lm.LitOf(Identifier(constraint)).Not())
   150  }
   151  
   152  func (constraint conflict) order() []Identifier {
   153  	return nil
   154  }
   155  
   156  func (constraint conflict) anchor() bool {
   157  	return false
   158  }
   159  
   160  // Conflict returns a Constraint that will permit solutions containing
   161  // either the constrained Variable, the Variable identified by
   162  // the given Identifier, or neither, but not both.
   163  func Conflict(id Identifier) Constraint {
   164  	return conflict(id)
   165  }
   166  
   167  type leq struct {
   168  	ids []Identifier
   169  	n   int
   170  }
   171  
   172  func (constraint leq) String(subject Identifier) string {
   173  	s := make([]string, len(constraint.ids))
   174  	for i, each := range constraint.ids {
   175  		s[i] = string(each)
   176  	}
   177  	return fmt.Sprintf("%s permits at most %d of %s", subject, constraint.n, strings.Join(s, ", "))
   178  }
   179  
   180  func (constraint leq) apply(c *logic.C, lm *litMapping, subject Identifier) z.Lit {
   181  	ms := make([]z.Lit, len(constraint.ids))
   182  	for i, each := range constraint.ids {
   183  		ms[i] = lm.LitOf(each)
   184  	}
   185  	return c.CardSort(ms).Leq(constraint.n)
   186  }
   187  
   188  func (constraint leq) order() []Identifier {
   189  	return nil
   190  }
   191  
   192  func (constraint leq) anchor() bool {
   193  	return false
   194  }
   195  
   196  // AtMost returns a Constraint that forbids solutions that contain
   197  // more than n of the Variables identified by the given
   198  // Identifiers.
   199  func AtMost(n int, ids ...Identifier) Constraint {
   200  	return leq{
   201  		ids: ids,
   202  		n:   n,
   203  	}
   204  }