/*
* Kodkod -- Copyright (c) 2005-present, Emina Torlak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package kodkod.ast;
import kodkod.ast.operator.Multiplicity;
import kodkod.ast.visitor.ReturnVisitor;
import kodkod.ast.visitor.VoidVisitor;
/**
* A relation is a leaf expression.
* Two relations are the same if and only if they
* refer to the same object. That is, r1.equals(r2) <=> r1 == r2. Each
* variable has a name, which is a comment for the purpose of
* printing, viewing, etc. The name has no meaning otherwise.
*
* <p>Four methods for creating commonly used predicates over binary relations
* are provided: {@link #function(Expression, Expression)}, {@link #partialFunction(Expression, Expression)},
* {@link #acyclic()}, and {@link #totalOrder(Relation, Relation, Relation)}. Using
* these methods to generate desired predicates will result in faster constraint solving
* than creating the same predicates via other API calls.</p>
*
* @specfield name: String
* @specfield arity: int
* @invariant no children
* @author Emina Torlak
*/
public class Relation extends LeafExpression {
/**
* Constructs a relation with the specified name and arity.
* @ensures this.name' = name && this.arity' = arity
* @throws IllegalArgumentException arity < 1
*/
private Relation(String name, int arity) {
super(name,arity);
}
/**
* Returns a new relation with the given name and arity.
* @return {r: Relation | r.arity = arity && r.name = name }
* @throws IllegalArgumentException arity < 1
*/
public static Relation nary(String name, int arity) {
return new Relation(name,arity);
}
/**
* Returns a new unary relation with the given name.
* The effect of this method is the same as calling Relation.nary(name,1).
* @return {r: Relation | r.arity = 1 && r.name = name }
*/
public static Relation unary(String name) {
return new Relation(name,1);
}
/**
* Returns a new binary relation with the given name.
* The effect of this method is the same as calling Relation.nary(name,2).
* @return {r: Relation | r.arity = 2 && r.name = name }
*/
public static Relation binary(String name) {
return new Relation(name, 2);
}
/**
* Returns a ternary relation with the specified name.
* @return {r: Relation | r.name = name && r.arity = 3}
*/
public static Relation ternary(String name) {
return new Relation(name,3);
}
/**
* {@inheritDoc}
* @see kodkod.ast.Expression#accept(kodkod.ast.visitor.ReturnVisitor)
*/
public <E, F, D, I> E accept(ReturnVisitor<E, F, D, I> visitor) {
return visitor.visit(this);
}
/**
* {@inheritDoc}
* @see kodkod.ast.Node#accept(kodkod.ast.visitor.VoidVisitor)
*/
public void accept(VoidVisitor visitor) {
visitor.visit(this);
}
/**
* Returns a formula stating that this relation is acyclic.
* @return {f: Formula | f <=> no ^this & iden}
* @throws IllegalArgumentException this.arity != 2
*/
public Formula acyclic() {
return new RelationPredicate.Acyclic(this);
}
/**
* Returns a formula stating that this relation is a total function
* with the specified domain and range.
* @return {f: Formula | f <=> this in domain->range && all v: domain | one v.this }
* @throws NullPointerException domain = null || range = null
* @throws IllegalArgumentException domain.arity != 1 || range.arity != 1
* @throws IllegalArgumentException this.arity != 2
*/
public Formula function(Expression domain, Expression range) {
return new RelationPredicate.Function(this, domain, Multiplicity.ONE, range);
}
/**
* Returns a formula stating that this relation is a partial function
* with the specified domain and range.
* @return {f: Formula | f <=> this in domain->range && all v: domain | lone v.this }
* @throws NullPointerException domain = null || range = null
* @throws IllegalArgumentException domain.arity != 1 || range.arity != 1
* @throws IllegalArgumentException this.arity != 2
*/
public Formula partialFunction(Expression domain, Expression range) {
return new RelationPredicate.Function(this, domain, Multiplicity.LONE, range);
}
/**
* Returns a formula stating that this relation imposes a total ordering
* over the atoms in the set <code>ordered</code>, and that thet first and
* last elements in the ordering are given by the relations <code>first</code>
* and <code>last</code>.
* @return {f: Formula | f <=> one first && one last && last in ordered &&
* no this.first && no last.this &&
* ordered = first.*this &&
* all e: ordered - last | one e.this }
* @throws NullPointerException any of the arguments are null
* @throws IllegalArgumentException any of the argument relations' arities are greater than one
* @throws IllegalArgumentException this.arity != 2
*/
public Formula totalOrder(Relation ordered, Relation first, Relation last) {
return new RelationPredicate.TotalOrdering(this, ordered, first, last);
}
}