package models.terms.meta;
import java.util.HashMap;
import java.util.Map;
import exceptions.CoefficientNotOneException;
import exceptions.SubstituteFailedException;
import exceptions.TooManyVariablesException;
import lombok.Getter;
import models.algebra.Expression;
import models.algebra.Symbol;
import models.algebra.Variable;
import models.terms.LinearRightNormalizedType;
import models.terms.RDLTerm;
import utils.ExpressionUitls;
@Getter
public abstract class MetaVariable extends MetaRDLTerm {
protected Variable variableName;
protected OrderConstraint constraint;
protected Variable orderVariable;
protected int orderConstant;
protected Expression orderExpression;
protected MetaVariable(Symbol symbol, TermType termType, Variable name, OrderConstraint constraint, Expression order) {
super(symbol, termType);
this.variableName = name;
this.constraint = constraint;
this.orderExpression = order;
Map<Variable, Integer> coefficients = new HashMap<>();
int constant = ExpressionUitls.getCoefficientAndConstantsFromExpression(order, coefficients, 1);
if (coefficients.size() > 1) {
// todo: create exception
throw new TooManyVariablesException("Too many variables");
}
if (coefficients.size() == 1) {
orderVariable = coefficients.keySet().iterator().next();
if (coefficients.get(orderVariable) != 1) {
throw new CoefficientNotOneException();
}
} else {
orderVariable = null;
}
orderConstant = constant;
}
protected MetaVariable(Symbol symbol, TermType termType, Variable name, OrderConstraint constraint, Expression order, LinearRightNormalizedType linearRIghtNormalizedType) {
super(symbol, termType);
this.variableName = name;
this.constraint = constraint;
this.orderExpression = order;
Map<Variable, Integer> coefficients = new HashMap<>();
int constant = ExpressionUitls.getCoefficientAndConstantsFromExpression(order, coefficients, 1);
if (coefficients.size() > 1) {
// todo: create exception
throw new TooManyVariablesException("Too many variables");
}
if (coefficients.size() == 1) {
orderVariable = coefficients.keySet().iterator().next();
if (coefficients.get(orderVariable) != 1) {
throw new CoefficientNotOneException();
}
} else {
orderVariable = null;
}
orderConstant = constant;
this.linearRightNormalizedType = linearRIghtNormalizedType;
}
@Override
public boolean isVariable() {
return true;
}
@Override
public boolean isMatchedBy(RDLTerm another, Map<Variable, RDLTerm> binding,
Map<Variable, OrderVariableConstraint> orderConstraint) {
if (! this.termType.getBaseTermClass().isAssignableFrom(another.getClass())) {
return false;
}
if (! orderConstraintCheck(another, orderConstraint)) {
return false;
}
if (! islinearRightNormalizedMatchedBy(another)) {
return false;
}
if (! binding.containsKey(this.variableName)) {
binding.put(this.variableName, another);
return true;
}
return binding.get(this.variableName).equals(another);
}
@Override
public RDLTerm substitute(Map<Variable, RDLTerm> binding) {
if (binding.containsKey(variableName)) {
return binding.get(variableName);
}
throw new SubstituteFailedException();
}
protected boolean orderConstraintCheck(RDLTerm another, Map<Variable, OrderVariableConstraint> orderConstraints) {
if (orderVariable == null) {
switch (constraint) {
case ANY:
return true;
case EQ:
return another.getOrder() == orderConstant;
case GE:
return another.getOrder() >= orderConstant;
case GT:
return another.getOrder() > orderConstant;
case LE:
return another.getOrder() <= orderConstant;
case LT:
return another.getOrder() < orderConstant;
}
} else {
if (! orderConstraints.containsKey(orderVariable)) {
orderConstraints.put(orderVariable, new OrderVariableConstraint());
}
var orderVarConst = orderConstraints.get(orderVariable);
return orderVarConst.setConstraint(another.getOrder() - orderConstant, constraint);
}
return false;
}
@Override
public String toString() {
return variableName.toString();
}
@Override
public String toStringWithOrder() {
return toString() +getOrderString();
}
protected String getOrderString() {
switch(constraint) {
case ANY:
return "(*)";
case EQ:
return "(= " + orderExpression.toString() + ")";
case GE:
return "(>= " + orderExpression.toString() + ")";
case GT:
return "(> " + orderExpression.toString() + ")";
case LE:
return "(<= " + orderExpression.toString() + ")";
case LT:
return "(< " + orderExpression.toString() + ")";
}
return "";
}
@Override
public boolean equals(Object another) {
if (another instanceof MetaVariable) {
return false;
}
MetaVariable anotherVar = (MetaVariable) another;
return super.equals(another)
&& variableName.equals(another)
&& constraint == anotherVar.getConstraint()
&& orderVariable.equals(anotherVar.getOrderVariable())
&& orderConstant == anotherVar.getOrderConstant();
}
@Override
public int hashCode() {
return (termType.name() + toString()).hashCode();
}
@Override
public Object clone() {
// TODO 自動生成されたメソッド・スタブ
return super.clone();
}
}