# Draft: Refactor constraints to positive

## Change Summary

This MR refactors the way in which coordinate constraints are expressed logically. Previously, constraints were specified as functions that returned True when the given point was outside the interval of constraint (or failed to pass the constraint). This was counter intuitive in many cases. Presently, constraints are specified as functions that return True when the point is *inside* the interval of constraint (or passes the constraint).

## Example:

Let `m_1`

be the coordiante we want to constrain in the interval `[m_-, m_+] \subset \mathbb{R}`

. The below pseudo code shows the old and new ways of implementing this constraint:

```
def old_constraint(m1, bound_low, bound_high):
# Returns True if m1 invalid
# Returns False if m1 valid
return m1 < bound_low or m1 > bound_high
def new_constraint(m1, bound_low, bound_high):
# Returns False if m1 invalid
# Returns True if m1 valid
return m1 >= bound_low and m1 <= bound_high
```

## Notes

### More than Logical Inversion

This MR might seem to only logically invert the syntax of constraints in `manifold`

; however, there is a key difference in edge case behavior. Previously, when a `NaN`

was given, the constraint would return False (meaning Pass), since `bool(numpy.nan)`

is False. This had the downstream effect of including erroneous templates in the bank (where coordinate functions failed). Now, when a `NaN`

is given, the constraint returns False (meaning Fail).