com.cyc.kb.client.RelationImpl Maven / Gradle / Ivy
Show all versions of cyc-kb-client Show documentation
package com.cyc.kb.client;
/*
* #%L
* File: RelationImpl.java
* Project: KB Client
* %%
* Copyright (C) 2013 - 2017 Cycorp, Inc
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import com.cyc.base.cycobject.CycObject;
import com.cyc.base.cycobject.DenotationalTerm;
import com.cyc.base.cycobject.Guid;
import com.cyc.base.exception.CycConnectionException;
import com.cyc.baseclient.CycObjectFactory;
import static com.cyc.baseclient.connection.SublApiHelper.makeNestedSubLStmt;
import static com.cyc.baseclient.connection.SublApiHelper.makeSubLStmt;
import com.cyc.baseclient.cycobject.CycConstantImpl;
import com.cyc.baseclient.cycobject.CycSymbolImpl;
import com.cyc.kb.Context;
import com.cyc.kb.Fact;
import com.cyc.kb.KbCollection;
import com.cyc.kb.KbObject;
import com.cyc.kb.KbStatus;
import com.cyc.kb.Relation;
import com.cyc.kb.Sentence;
import com.cyc.kb.client.config.KbConfiguration;
import com.cyc.kb.exception.CreateException;
import com.cyc.kb.exception.InvalidNameException;
import com.cyc.kb.exception.KbException;
import com.cyc.kb.exception.KbObjectNotFoundException;
import com.cyc.kb.exception.KbRuntimeException;
import com.cyc.kb.exception.KbTypeConflictException;
import com.cyc.kb.exception.KbTypeException;
import com.cyc.kb.exception.VariableArityException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* A RelationImpl
object is a facade for a #$Relation
in Cyc KB.
*
* A relation relates one or more things. Relations can be used to construct formulas. Relations can
* be used to construct atomic or non-atomic sentences and non-atomic terms. A well formed formula
* has a relation in 0th argument position and the other arguments satisfy the semantic constraints
* of the relation. This class will be rarely, if ever, used by itself. Instead, its subclasses
* {@link KBPredicateImpl} and {@link KBFunctionImpl} should be used in virtually all cases.
*
* @param type of CycObject core
*
* @author Vijay Raj
* @version $Id: RelationImpl.java 173082 2017-07-28 15:36:55Z nwinant $
*/
public class RelationImpl extends KbIndividualImpl implements Relation {
private static final DenotationalTerm TYPE_CORE
= new CycConstantImpl("Relation", new Guid("bd5880cd-9c29-11b1-9dad-c379636f7270"));
static DenotationalTerm getClassTypeCore() {
return TYPE_CORE;
}
private static final CycSymbolImpl WITH_MT = CycObjectFactory.makeCycSymbol("with-mt");
private Collection arityValues = null;
private Boolean isVariableArity = null;
/**
* Not part of the KB API. This default constructor only has the effect of ensuring that there is
* access to a Cyc server.
*/
RelationImpl() {
super();
}
public RelationImpl(Relation rel, Map kboData) {
super(rel, kboData);
}
/**
* Not part of the KB API. An implementation-dependent constructor.
*
* It is used when the result of query is a CycObject and is known to be or requested to be cast
* as an instance of Relation.
*
* @param cycObject the CycObject wrapped by Relation
. The constructor verifies that
* the CycObject is an instance of #$Relation
*
* @throws KbTypeException if cycObject is not or could not be made an instance of #$Relation
*/
RelationImpl(DenotationalTerm cycObject) throws KbTypeException {
super(cycObject);
}
/**
* This not part of the public, supported KB API. finds or creates an instance of
* CYC_NAME_OF_THE_CLASS represented by relStr in the underlying KB
*
*
* @param relStr the string representing an #$Relation in the KB
*
* @throws CreateException if the #$Relation represented by relStr is not found and could not be
* created
* @throws KbTypeException if the term represented by relStr is not an instance of #$Relation and
* cannot be made into one.
*/
RelationImpl(String relStr) throws KbTypeException, CreateException {
super(relStr);
}
/**
* This not part of the public, supported KB API. finds or creates; or finds an instance of
* #$Relation represented by relStr in the underlying KB based on input ENUM
*
*
* @param relStr the string representing an instance of #$Relation in the KB
* @param lookup the enum to specify LookupType: FIND or FIND_OR_CREATE
*
* @throws CreateException
* @throws KbTypeException
*
* @throws KbObjectNotFoundException if the #$Relation represented by relStr is not found and
* could not be created
* @throws InvalidNameException if the string relStr does not conform to Cyc constant-naming
* conventions
*
* @throws KbTypeException if the term represented by relStr is not an instance of #$Relation and
* lookup is set to find only {@link LookupType#FIND}
* @throws KbTypeConflictException if the term represented by relStr is not an instance of
* #$Relation, and lookup is set to find or create; and if the term cannot be made an instance
* #$Relation by asserting new knowledge.
*/
RelationImpl(String relStr, LookupType lookup) throws KbTypeException, CreateException {
super(relStr, lookup);
}
/**
* Get the Relation
with the name nameOrId
. Throws exceptions if there
* is no KB term by that name, or if it is not already an instance of #$Relation.
*
* @param nameOrId the string representation or the HLID of the #$Relation
*
* @return a new Relation
*
* @throws KbTypeException
* @throws CreateException
*/
public static RelationImpl get(String nameOrId) throws KbTypeException, CreateException {
return KbObjectImplFactory.get(nameOrId, RelationImpl.class);
}
/**
* Get the Relation
object that corresponds to cycObject
. Throws
* exceptions if the object isn't in the KB, or if it's not already an instance of
* #$Relation
.
*
* @param cycObject the CycObject wrapped by Relation. The method verifies that the CycObject is
* an instance of #$Relation
*
* @return a new Relation
*
* @throws CreateException
* @throws KbTypeException
*/
@Deprecated
public static RelationImpl get(CycObject cycObject) throws KbTypeException, CreateException {
return KbObjectImplFactory.get(cycObject, RelationImpl.class);
}
/**
* Find or create a Relation
object named nameOrId
. If no object exists
* in the KB with the name nameOrId
, one will be created, and it will be asserted to
* be an instance of #$Relation
. If there is already an object in the KB called
* nameOrId
, and it is already a #$Relation
, it will be returned. If it
* is not already a #$Relation
, but can be made into one by addition of assertions to
* the KB, such assertions will be made, and the object will be returned. If the object in the KB
* cannot be turned into a #$Relation
by adding assertions (i.e. some existing
* assertion prevents it from being a #$Relation
), a
* KBTypeConflictException
will be thrown.
*
* @param nameOrId the string representation or the HLID of the #$Relation
*
* @return a new Relation
*
* @throws KbTypeException
* @throws CreateException
*/
public static RelationImpl findOrCreate(String nameOrId) throws CreateException, KbTypeException {
return KbObjectImplFactory.findOrCreate(nameOrId, RelationImpl.class);
}
/**
* Find or create a Relation object from cycObject
. If cycObject
is
* already a #$Relation
, an appropriate Relation
object will be
* returned. If object
is not already a #$Relation
, but can be made into
* one by addition of assertions to the KB, such assertions will be made, and the relevant object
* will be returned. If cycObject
cannot be turned into a #$Relation
by
* adding assertions (i.e. some existing assertion prevents it from being a
* #$Relation
, a KBTypeConflictException
will be thrown.
*
* @param cycObject the CycObject wrapped by Relation. The method verifies that the CycObject is
* an #$Relation
*
* @return a new Relation
*
* @throws KbTypeException
* @throws CreateException
*/
@Deprecated
public static RelationImpl findOrCreate(CycObject cycObject) throws CreateException, KbTypeException {
return KbObjectImplFactory.findOrCreate(cycObject, RelationImpl.class);
}
/**
* Find or create a Relation
object named nameOrId
, and also make it an
* instance of constraintCol
in the default context specified by
* {@link KBAPIDefaultContext#forAssertion()}. If no object exists in the KB with the name
* nameOrId
, one will be created, and it will be asserted to be an instance of both
* #$Relation
and constraintCol
. If there is already an object in the KB
* called nameOrId
, and it is already both a #$Relation
and a
* constraintCol
, it will be returned. If it is not already both a
* #$Relation
and a constraintCol
, but can be made so by addition of
* assertions to the KB, such assertions will be made, and the object will be returned. If the
* object in the KB cannot be turned into both a #$Relation
and a
* constraintCol
by adding assertions, a KBTypeConflictException
will be
* thrown.
*
* @param nameOrId the string representation or the HLID of the #$Relation
* @param constraintCol the collection that this #$Relation will instantiate
*
* @return a new Relation
*
* @throws KbTypeException
* @throws CreateException
*/
public static RelationImpl findOrCreate(String nameOrId, KbCollection constraintCol) throws CreateException, KbTypeException {
return KbObjectImplFactory.findOrCreate(nameOrId, constraintCol, RelationImpl.class);
}
/**
* Find or create a Relation
object named nameOrId
, and also make it an
* instance of constraintCol
in the default context specified by
* {@link KBAPIDefaultContext#forAssertion()}. If no object exists in the KB with the name
* nameOrId
, one will be created, and it will be asserted to be an instance of both
* #$Relation
and constraintCol
. If there is already an object in the KB
* called nameOrId
, and it is already both a #$Relation
and a
* constraintCol
, it will be returned. If it is not already both a
* #$Relation
and a constraintCol
, but can be made so by addition of
* assertions to the KB, such assertions will be made, and the object will be returned. If the
* object in the KB cannot be turned into both a #$Relation
and a
* constraintCol
by adding assertions, a KBTypeConflictException
will be
* thrown.
*
* @param nameOrId the string representation or the HLID of the #$Relation
* @param constraintColStr the string representation of the collection that this #$Relation will
* instantiate
*
* @return a new Relation
*
* @throws KbTypeException
* @throws CreateException
*/
public static RelationImpl findOrCreate(String nameOrId, String constraintColStr) throws CreateException, KbTypeException {
return KbObjectImplFactory.findOrCreate(nameOrId, constraintColStr, RelationImpl.class);
}
/**
* Find or create a Relation
object named nameOrId
, and also make it an
* instance of constraintCol
in ctx
. If no object exists in the KB with
* the name nameOrId
, one will be created, and it will be asserted to be an instance
* of both #$Relation
and constraintCol
. If there is already an object
* in the KB called nameOrId
, and it is already both a #$Relation
and a
* constraintCol
, it will be returned. If it is not already both a
* #$Relation
and a constraintCol
, but can be made so by addition of
* assertions to the KB, such assertions will be made, and the object will be returned. If the
* object in the KB cannot be turned into both a #$Relation
and a
* constraintCol
by adding assertions, a KBTypeConflictException
will be
* thrown.
*
* @param nameOrId the string representation or the HLID of the #$Relation
* @param constraintCol the collection that this #$Relation will instantiate
* @param ctx the context in which the resulting object must be an instance of constraintCol
*
* @return a new Relation
*
* @throws KbTypeException
* @throws CreateException
*/
public static RelationImpl findOrCreate(String nameOrId, KbCollection constraintCol, ContextImpl ctx)
throws CreateException, KbTypeException {
return KbObjectImplFactory.findOrCreate(nameOrId, constraintCol, ctx, RelationImpl.class);
}
/**
* Find or create a Relation
object named nameOrId
, and also make it an
* instance of constraintCol
in ctx
. If no object exists in the KB with
* the name nameOrId
, one will be created, and it will be asserted to be an instance
* of both #$Relation
and constraintCol
. If there is already an object
* in the KB called nameOrId
, and it is already both a #$Relation
and a
* constraintCol
, it will be returned. If it is not already both a
* #$Relation
and a constraintCol
, but can be made so by addition of
* assertions to the KB, such assertions will be made, and the object will be returned. If the
* object in the KB cannot be turned into both a #$Relation
and a
* constraintCol
by adding assertions, a KBTypeConflictException
will be
* thrown.
*
* @param nameOrId the string representation or the HLID of the term
* @param constraintColStr the string representation of the collection that this #$Relation will
* instantiate
* @param ctxStr the context in which the resulting object must be an instance of constraintCol
*
* @return a new Relation
*
* @throws KbTypeException
* @throws CreateException
*/
public static RelationImpl findOrCreate(String nameOrId, String constraintColStr, String ctxStr)
throws CreateException, KbTypeException {
return KbObjectImplFactory.findOrCreate(nameOrId, constraintColStr, ctxStr, RelationImpl.class);
}
/**
* Checks whether entity exists in KB and is an instance of #$Relation. If false,
* {@link #getStatus(String)} may yield more information. This method is equivalent to
* getStatus(nameOrId).equals(KBStatus.EXISTS_AS_TYPE)
.
*
* @param nameOrId either the name or HL ID of an entity in the KB
* @return true
if entity exists in KB and is an instance of #$Relation
*/
public static boolean existsAsType(String nameOrId) {
return getStatus(nameOrId).equals(KbStatus.EXISTS_AS_TYPE);
}
/**
* Checks whether entity exists in KB and is an instance of #$Relation. If false,
* {@link #getStatus(CycObject)} may yield more information. This method is equivalent to
* getStatus(object).equals(KBStatus.EXISTS_AS_TYPE)
.
*
* @param cycObject the CycObject representation of a KB entity
* @return true
if entity exists in KB and is an instance of #$Relation
*/
public static boolean existsAsType(CycObject cycObject) {
return getStatus(cycObject).equals(KbStatus.EXISTS_AS_TYPE);
}
/**
* Returns an KBStatus enum which describes whether nameOrId
exists in the KB and is
* an instance of #$Relation
.
*
* @param nameOrId either the name or HL ID of an entity in the KB
* @return an enum describing the existential status of the entity in the KB
*/
public static KbStatus getStatus(String nameOrId) {
return KbObjectImplFactory.getStatus(nameOrId, RelationImpl.class);
}
/**
* Returns an KBStatus enum which describes whether cycObject
exists in the KB and is
* an instance of #$Relation
.
*
* @param cycObject the CycObject representation of a KB entity
* @return an enum describing the existential status of the entity in the KB
*/
public static KbStatus getStatus(CycObject cycObject) {
return KbObjectImplFactory.getStatus(cycObject, RelationImpl.class);
}
@Override
public List> getArgIsaList() {
return getArgIsaList(KbConfiguration.getDefaultContext().forQuery());
}
@Override
public List> getArgIsaList(Context ctx) {
List> argIsaList = new ArrayList();
for (Integer i = 1; i <= this.getArity(); i++) {
argIsaList.add(this.getArgIsa(i, ctx));
}
return argIsaList;
}
@Override
public Collection getArgIsa(int argPos) {
return getArgIsa(argPos, KbConfiguration.getDefaultContext().forQuery());
}
@Override
public Collection getArgIsa(int argPos, String ctxStr) {
return getArgIsa(argPos, KbUtils.getKBObjectForArgument(ctxStr, ContextImpl.class));
}
@Override
public Collection getArgIsa(int argPos, Context ctx) {
int valuePos = 3;
int filter = argPos;
int filtPos = 2;
//return this.getValuesForArg(Constants.argIsa(), 1, getPos, filter, filtPos, ctx);
return Constants.argIsa().getValuesForArgPositionWithMatchArg(this, 1, valuePos, filter, filtPos, ctx);
}
@Override
public Relation addArgIsa(int argPos, String colStr, String ctxStr) throws KbTypeException, CreateException {
return addArgIsa(argPos, KbCollectionImpl.get(colStr), ContextImpl.get(ctxStr));
}
@Override
public Relation addArgIsa(int argPos, KbCollection col, Context ctx) throws KbTypeException, CreateException {
//addFact(ctx, Constants.argIsa(), 1, (Object) argPos, (Object) col);
Constants.argIsa().addFact(ctx, this, argPos, col);
return this;
}
@Override
public Sentence addArgIsaSentence(int argPos, KbCollection col) throws KbTypeException, CreateException {
return new SentenceImpl(Constants.argIsa(), this, argPos, col);
}
@Override
public List> getArgGenlList() {
return getArgGenlList(KbConfiguration.getDefaultContext().forQuery());
}
@Override
public List> getArgGenlList(Context ctx) {
List> argGenlList = new ArrayList();
for (Integer i = 1; i <= this.getArity(); i++) {
argGenlList.add(this.getArgGenl(i));
}
return argGenlList;
}
@Override
public Collection getArgGenl(int argPos) {
return getArgGenl(argPos, KbConfiguration.getDefaultContext().forQuery());
}
@Override
public Collection getArgGenl(int argPos, String ctxStr) {
return getArgGenl(argPos, KbUtils.getKBObjectForArgument(ctxStr, ContextImpl.class));
}
@Override
public Collection getArgGenl(int argPos, Context ctx) {
int valuePos = 3;
int filter = argPos;
int filtPos = 2;
//return this.getValuesForArg(Constants.argGenl(), 1, getPos, filter, filtPos, ctx);
return Constants.argGenl().getValuesForArgPositionWithMatchArg(this, 1, valuePos, filter, filtPos, ctx);
}
@Override
public Relation addArgGenl(int argPos, String colStr, String ctxStr) throws KbTypeException, CreateException {
return addArgGenl(argPos, KbCollectionImpl.get(colStr), ContextImpl.get(ctxStr));
}
@Override
public Relation addArgGenl(int argPos, KbCollection col, Context ctx) throws KbTypeException, CreateException {
//addFact(ctx, Constants.argGenl(), 1, (Object) argPos, (Object) col);
Constants.argGenl().addFact(ctx, this, argPos, col);
return this;
}
//TODO: Add get/addInterArgIsa, get/addInterArgGenl
@Override
public List getInterArgDifferent(Context ctx) {
try {
final List differentArgs = new ArrayList<>();
//Collection facts = this.getFacts(Constants.getInstance().INTER_ARG_DIFF_PRED, 1, ctx);
final Collection facts = Constants.getInstance().INTER_ARG_DIFF_PRED.getFacts(this, 1, ctx);
if (facts.isEmpty()) {
return null;
}
final Fact first = facts.iterator().next();
differentArgs.add(first.getArgument(2));
differentArgs.add(first.getArgument(3));
return differentArgs;
} catch (KbException ex) {
return null;
}
}
@Override
public Relation addInterArgDifferent(Integer argPosM, Integer argPosN, Context ctx) throws KbTypeException, CreateException {
//addFact(ctx, Constants.getInstance().INTER_ARG_DIFF_PRED, 1, argPosM, argPosN);
Constants.getInstance().INTER_ARG_DIFF_PRED.addFact(ctx, this, argPosM, argPosN);
return this;
}
@Override
public Integer getArity() throws VariableArityException {
Context ctx = Constants.uvMt();
if (arityValues == null) {
try {
//arityValues = this.getValuesForArg(Constants.arity(), 1, 2, ctx);
arityValues = Constants.arity().getValuesForArgPosition(this, 1, 2, ctx);
} catch (IllegalArgumentException e) {
throw new VariableArityException(this + " do not have an Integer arity. Try using minArity and maxArity instead.", e);
}
}
if (arityValues == null || arityValues.isEmpty()) {
throw new IllegalArgumentException("There is no asserted arity for " + this);
}
return arityValues.iterator().next();
}
@Override
public boolean isVariableArity() {
if (isVariableArity == null) {
isVariableArity = this.isInstanceOf(Constants.getInstance().VAR_ARITY_COL);
}
return isVariableArity;
}
@Override
public Integer getArityMin() {
try {
final Context ctx = Constants.uvMt();
final String command = makeSubLStmt(
WITH_MT, ctx.getCore(), makeNestedSubLStmt(
SublConstants.getInstance().minArity.stringApiValue(), this.getCore()));
final Object object = getAccess().converse().converseObject(command);
if (object == null || object.equals(CycObjectFactory.nil)) {
throw new IllegalArgumentException("No known min-arity for " + this);
} else {
return (Integer) object;
}
} catch (CycConnectionException e) {
throw new KbRuntimeException(e.getMessage(), e);
}
}
@Override
public Integer getArityMax() {
try {
final Context ctx = Constants.uvMt();
final String command = makeSubLStmt(
WITH_MT, ctx.getCore(), makeNestedSubLStmt(
SublConstants.getInstance().maxArity.stringApiValue(), this.getCore()));
final Object object = getAccess().converse().converseObject(command);
if (object == null || object.equals(CycObjectFactory.nil)) {
throw new IllegalArgumentException("No known max-arity for " + this);
} else {
return (Integer) object;
}
} catch (CycConnectionException e) {
throw new KbRuntimeException(e.getMessage(), e);
}
}
/**
* Provides a string describing the Relation's arity, for use as a substring in error messages and
* whatnot.
*
* @return a string describing the relation's arity
*/
protected String describeArity() {
return !isVariableArity()
? "requires exactly " + getArity() + " arguments"
: "requires a minimum of " + getArityMin()
+ " and a maximum of " + getArityMax() + " arguments";
}
/**
* Checks whether a vararg has an acceptable length wrt the Relation's arity, and throws an
* IllegalArgumentException if it does not.
*
* @param forbidNullArgs throw an exception if any args are null
* @param args
*/
protected void validateArgArity(boolean forbidNullArgs, Object... args) {
if (args == null) {
throw new NullPointerException("This " + getTypeString() + " " + describeArity()
+ ", but received a null vararg");
}
try {
if (!isVariableArity()) {
if (getArity() != args.length) {
throw new IllegalArgumentException("This " + getTypeString() + " " + describeArity()
+ ", but " + args.length + " args were supplied");
}
} else if ((args.length < getArityMin()) || (args.length > getArityMax())) {
throw new IllegalArgumentException("This " + getTypeString() + " " + describeArity()
+ ", but " + args.length + " args were supplied");
}
} catch (IllegalArgumentException ex) {
if (!Objects.toString(ex.getMessage(), "").startsWith("No known ")) {
throw ex;
}
// Min or max arity is unknown, so we're going to trust that args.length is correct...
}
if (forbidNullArgs) {
final StringBuilder sb = new StringBuilder();
for (int i=0; i < args.length; i++) {
if (args[i] == null) {
sb.append(" arg").append(i + 1);
}
// TODO: should we also check for nil? - nwinant, 2017-07-26
}
if (sb.length() > 0) {
throw new IllegalArgumentException("This " + getTypeString() + " " + describeArity()
+ ", but the following args were null: " + sb);
}
}
}
protected void validateArgArity(Object... args) {
validateArgArity(true, args);
}
@Override
public Relation setArity(int arityValue) throws KbTypeException, CreateException {
//addFact(Constants.uvMt(), Constants.arity(), 1, arityValue);
Constants.arity().addFact(Constants.uvMt(), this, arityValue);
return this;
}
@Override
public Sentence setAritySentence(int arityValue) throws KbTypeException, CreateException {
return new SentenceImpl(Constants.arity(), this, arityValue);
}
/**
* Return the KBCollection as a KBObject of the Cyc term that underlies this class.
*
* @return KBCollectionImpl.get("#$Relation");
*/
@Override
public KbObject getType() {
return getClassType();
}
/**
* Return the KBCollection as a KBObject of the Cyc term that underlies this class.
*
* @return KBCollectionImpl.get("#$Relation");
*/
public static KbObject getClassType() {
try {
return KbCollectionImpl.get(getClassTypeString());
} catch (KbException kae) {
throw new KbRuntimeException(kae.getMessage(), kae);
}
}
@Override
String getTypeString() {
return getClassTypeString();
}
static String getClassTypeString() {
return "#$Relation";
}
}