Optimize and and or by removing an unecessary constraint.

I believe this optimization is valid and correct. "and" saves one constraint and replaces the sum variable with a constant. The "or" saves one constraint.

I've also implemented (but didn't commit) an alternative implementation for "and(Constraint...CONS)" below:

```java
public class AndConstraint extends Constraint<Variable, Propagator<Variable>> {

    private final Constraint[] operands;

    public AndConstraint(Constraint... operands) {
        super(getVariables(operands), operands[0].getSolver());
        this.operands = operands;
        Propagator[] props = getPropagators(operands);
        PropAnd reifProp = new PropAnd(props);
        props = ArrayUtils.append(new Propagator[]{reifProp}, props);
        setPropagators(props);
        for (Propagator prop : props) {
            prop.setReifiedSilent();
        }
    }

    private static Variable[] getVariables(Constraint[] operands) {
        Variable[][] variables = new Variable[operands.length][];
        for (int i = 0; i < variables.length; i++) {
            variables[i] = operands[i].getVariables();
        }
        return ArrayUtils.append(variables);
    }

    private static Propagator[] getPropagators(Constraint[] operands) {
        Propagator[][] propagators = new Propagator[operands.length][];
        for (int i = 0; i < propagators.length; i++) {
            propagators[i] = operands[i].getPropagators();
        }
        return ArrayUtils.append(propagators);
    }

    @Override
    public ESat isSatisfied() {
        boolean allTrue = true;
        for (Constraint operand : operands) {
            switch (operand.isSatisfied()) {
                case FALSE:
                    return ESat.FALSE;
                case UNDEFINED:
                    allTrue = false;
            }
        }
        return allTrue ? ESat.TRUE : ESat.UNDEFINED;
    }

    @Override
    public ESat isEntailed() {
        boolean allTrue = true;
        for (Constraint operand : operands) {
            switch (operand.isEntailed()) {
                case FALSE:
                    return ESat.FALSE;
                case UNDEFINED:
                    allTrue = false;
            }
        }
        return allTrue ? ESat.TRUE : ESat.UNDEFINED;
    }

    @Override
    public String toString() {
        throw new UnsupportedOperationException("TODO");
    }
}
```
```java
public class PropAnd extends Propagator<Variable> {

    private final Propagator[] operands;

    public PropAnd(Propagator[] operands) {
        super(new Variable[]{
                    operands[0].getSolver().ZERO // Don't know what else to put here.
                }, PropagatorPriority.LINEAR);
        this.operands = operands;
    }

    @Override
    public int getPropagationConditions(int vIdx) {
        return EventType.ALL_FINE_EVENTS.mask;
    }

    @Override
    public void propagate(int evtmask) throws ContradictionException {
        for (Propagator operand : operands) {
            assert (operand.isReifiedAndSilent());
            operand.setReifiedTrue();
            operand.propagate(EventType.FULL_PROPAGATION.strengthened_mask);
            solver.getEngine().onPropagatorExecution(operand);
        }
    }

    @Override
    public void propagate(int idxVarInProp, int mask) throws ContradictionException {
        forcePropagate(EventType.FULL_PROPAGATION);
    }

    @Override
    public void explain(Deduction d, Explanation e) {
        throw new UnsupportedOperationException("TODO");
    }

    @Override
    public ESat isEntailed() {
        boolean allTrue = true;
        for (Propagator operand : operands) {
            switch (operand.isEntailed()) {
                case FALSE:
                    return ESat.FALSE;
                case UNDEFINED:
                    allTrue = false;
            }
        }
        return allTrue ? ESat.TRUE : ESat.UNDEFINED;
    }

    @Override
    public String toString() {
        throw new UnsupportedOperationException("TODO");
    }
}
```

The implementation is straightforward and hopefully correct. The current "and(Constraint...CONS)" requires 1 reified var, 1 not view var, and 1 opposite constraint per CON parameter. The dedicated AndConstraint should be more economical but I'm doubting the performance would be that big of a difference though.