Newer
Older
ResourceDependencyLogic / src / models / meta / MetaVariable.java
package models.meta;

import java.util.HashMap;
import java.util.Map;

import exceptions.CoefficientNotOneException;
import exceptions.NonLinearExpressionException;
import exceptions.TooManyVariablesException;
import lombok.Getter;
import models.RDLTerm;
import models.algebra.Constant;
import models.algebra.Expression;
import models.algebra.Symbol;
import models.algebra.Term;
import models.algebra.Variable;
import models.dataConstraintModel.DataConstraintModel;

@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 = 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;
	}

	@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 (! binding.containsKey(this.variableName)) {
			binding.put(this.variableName, another);
			return true;
		}
		return binding.get(this.variableName).equals(another);
	}

	private 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;
	}
	
	private int getCoefficientAndConstantsFromExpression(Expression expression, Map<Variable, Integer> coefficients, int curWeight) {
		int res = 0;
		if(expression instanceof Constant) {
			return getConstantValue((Constant) expression) * curWeight;
		} else if(expression instanceof Variable) {
			coefficients.put((Variable) expression, coefficients.getOrDefault((Variable) expression, 0) + curWeight);
			return 0;
		}
		Term term = (Term) expression;
		Symbol symbol = term.getSymbol();
		if(symbol.equals(DataConstraintModel.add)) {
			Expression c1 = term.getChild(0);
			Expression c2 = term.getChild(1);
			res += getCoefficientAndConstantsFromExpression(c1, coefficients, curWeight);
			res += getCoefficientAndConstantsFromExpression(c2, coefficients, curWeight);
		} else if(symbol.equals(DataConstraintModel.sub)) {
			Expression c1 = term.getChild(0);
			Expression c2 = term.getChild(1);
			res += getCoefficientAndConstantsFromExpression(c1, coefficients, curWeight);
			res += getCoefficientAndConstantsFromExpression(c2, coefficients, -curWeight);
		} else if(symbol.equals(DataConstraintModel.mul)) {
			Expression c1 = term.getChild(0);
			Expression c2 = term.getChild(1);
			if(c1.getVariables().size() == 0 && c2.getVariables().size() == 0) {
				res += getCoefficientAndConstantsFromExpression(c1, coefficients, curWeight) * 
						getCoefficientAndConstantsFromExpression(c2, coefficients, curWeight);
			} else if(c1.getVariables().size() == 0) {
				res += getCoefficientAndConstantsFromExpression(
							c2, 
							coefficients, 
							getCoefficientAndConstantsFromExpression(c1, coefficients, curWeight)
						);
			} else if(c2.getVariables().size() == 0){
				res += getCoefficientAndConstantsFromExpression(
						c1, 
						coefficients, 
						getCoefficientAndConstantsFromExpression(c2, coefficients, curWeight)
					);
			} else {
				throw new NonLinearExpressionException("Order expression must be linear expression.");
			}
		} else if(symbol.equals(DataConstraintModel.minus)) {
			Expression c1 = term.getChild(0);
			res += getCoefficientAndConstantsFromExpression(c1, coefficients, -curWeight);
		} else {
			throw new NonLinearExpressionException("Order expression must be linear expression.");
		}
		return res;
		
	}
	
	private int getConstantValue(Constant constant) {
		return Integer.parseInt((String) constant.getValue());
	}
	
	
	@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();
	}

	
	
}