/****************************************************************************** * * Copyright 2014 Paphus Solutions Inc. * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html * * 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. * ******************************************************************************/ package org.botlibre.knowledge; import java.io.PrintWriter; import java.io.Serializable; import java.io.StringWriter; import java.lang.reflect.Method; import java.math.BigInteger; import java.net.URI; import java.net.URL; import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.logging.Level; import org.botlibre.Bot; import org.botlibre.aiml.AIMLParser; import org.botlibre.api.knowledge.MemoryStorageException; import org.botlibre.api.knowledge.Network; import org.botlibre.api.knowledge.Path; import org.botlibre.api.knowledge.Relationship; import org.botlibre.api.knowledge.Vertex; import org.botlibre.api.knowledge.VertexIterator; import org.botlibre.self.SelfDecompiler; import org.botlibre.self.SelfExecutionException; import org.botlibre.sense.service.RemoteService; import org.botlibre.thought.forgetfulness.Forgetfulness; import org.botlibre.thought.language.Language; import org.botlibre.util.Utils; /** * Represents a piece of knowledge. * Vertex is a very simple structure mainly comprised of its relationships, * this gives the system a very simple and extendable structure. * Basic implementation to allow subclasses to avoid defining some of the basic stuff. * The data attribute allows for vertices that represents something tangible such as * text, sound, image, number, etc. The data is also indexed within a network, so is the * only guaranteed way to lookup an existing vertex. */ public class BasicVertex implements Vertex, Serializable { public static String SELF = "SELF"; public static int SMALL = 10; public static int MEDIUM = 50; public static int LARGE = 100; private static final long serialVersionUID = 1L; protected Long id; protected String name; /** Allow for database lazy initialization. */ protected Collection<Relationship> allRelationships; protected Map<Vertex, Map<Relationship, Relationship>> relationships; protected String dataType; protected Object data; protected Date creationDate; protected Date accessDate; protected int accessCount; protected boolean pinned; protected int consciousnessLevel; protected Network network; protected Vertex original; protected Boolean hasResponse; protected int wordCount; protected boolean isDirty; protected long groupId; protected boolean isTemporary; public BasicVertex() { this.accessCount = 0; } public BasicVertex(Object data) { this(); this.data = data; } public void init() { this.hasResponse = false; this.creationDate = new Date(); incrementAccessCount(); } public boolean isTemporary() { return isTemporary; } public void setIsTemporary(boolean isTemporary) { this.isTemporary = isTemporary; } public int getWordCount() { return wordCount; } public void setWordCount(int wordCount) { this.wordCount = wordCount; } public long getGroupId() { return groupId; } public void setGroupId(long groupId) { this.groupId = groupId; } /** * PERF: Used to check response without accessing relationships. */ public boolean hasAnyResponseRelationship() { if (this.hasResponse == null) { this.hasResponse = hasRelationship(Primitive.RESPONSE); } return this.hasResponse; } public Boolean getHasResponse() { return hasResponse; } public void setHasResponse(Boolean hasResponse) { this.hasResponse = hasResponse; } public boolean isDirty() { return isDirty; } public void setIsDirty(boolean isDirty) { this.isDirty = isDirty; } /** * Create the vertex as a clone of the original. */ public BasicVertex(Vertex original) { this.id = original.getId(); this.name = original.getName(); this.data = original.getData(); this.creationDate = original.getCreationDate(); this.accessCount = original.getAccessCount(); this.accessDate = original.getAccessDate(); this.consciousnessLevel = original.getConsciousnessLevel(); this.original = original; } /** * Return the original long term vertex the short term vertex was derived from. */ protected Vertex getOriginal() { return original; } /** * Set the original long term vertex the short term vertex was derived from. */ public void setOriginal(Vertex original) { this.original = original; this.relationships = null; } /** * Return the network the vertex is derived from. */ public Network getNetwork() { return network; } /** * Set the network the vertex is derived from. */ public void setNetwork(Network network) { this.network = network; } /** * Return the date the vertex was created. */ public Date getCreationDate() { return creationDate; } /** * Set the date the vertex was created. */ public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } /** * Return the date the vertex was last accessed. */ public Date getAccessDate() { return accessDate; } /** * Set the date the vertex was last accessed. * Access is considered moving from long term to short term memory. */ public void setAccessDate(Date accessDate) { this.accessDate = accessDate; } /** * Return the number of times the vertex has been accessed. * Access is considered moving from long term to short term memory. */ public int getAccessCount() { return accessCount; } /** * Set the number of times the vertex has been accessed. */ public void setAccessCount(int accessCount) { this.accessCount = accessCount; } /** * Record that the vertex was accessed, update the access time and increment the access count. */ public void incrementAccessCount() { if (isPrimitive()) { return; } if ((this.accessDate != null) && ((System.currentTimeMillis() - this.accessDate.getTime()) < (24 * Utils.HOUR))) { // Avoid incrementing if already incremented this day. return; } setAccessDate(new Date()); setAccessCount(this.accessCount + 1); } /** * Increase the vertices's level of consciousness. */ public void incrementConsciousnessLevel() { incrementConsciousnessLevel(1); } /** * Decrease the vertices's level of consciousness. */ public void decrementConsciousnessLevel() { decrementConsciousnessLevel(1); } /** * Decrease the vertices's level of consciousness by the amount. */ public void decrementConsciousnessLevel(int amount) { this.consciousnessLevel = this.consciousnessLevel - amount; } /** * Increase the vertices's level of consciousness by the amount. */ public void incrementConsciousnessLevel(int amount) { this.consciousnessLevel = this.consciousnessLevel + amount; int size = getRelationships().size(); if (size > SMALL) { this.consciousnessLevel++; } if (size > MEDIUM) { this.consciousnessLevel++; } if (size > LARGE) { this.consciousnessLevel++; } if (this.consciousnessLevel > 5) { incrementAccessCount(); } } /** * Return the vertices's level of consciousness. */ public int getConsciousnessLevel() { return this.consciousnessLevel; } /** * Set the vertices's level of consciousness. */ public void setConsciousnessLevel(int consciousnessLevel) { this.consciousnessLevel = consciousnessLevel; } /** * Helper inner class used to making iterating a vertices's relationships easier. */ protected class RelationshipIterator implements Iterator<Relationship> { private Iterator<Map<Relationship, Relationship>> mapIterator; private Iterator<Relationship> collectionIterator; private boolean order; public RelationshipIterator(boolean order) { this.mapIterator = getRelationships().values().iterator(); this.collectionIterator = null; this.order = order; } public Relationship next() { if ((this.collectionIterator == null) || (! this.collectionIterator.hasNext())) { if (order) { this.collectionIterator = new TreeSet<Relationship>(mapIterator.next().values()).iterator(); } else { this.collectionIterator = mapIterator.next().values().iterator(); } } return this.collectionIterator.next(); } public boolean hasNext() { if ((this.collectionIterator == null) || (! this.collectionIterator.hasNext())) { if (! this.mapIterator.hasNext()) { return false; } if (order) { this.collectionIterator = new TreeSet<Relationship>(mapIterator.next().values()).iterator(); } else { this.collectionIterator = mapIterator.next().values().iterator(); } } return this.collectionIterator.hasNext(); } public void remove() { if (this.collectionIterator == null) { this.collectionIterator = mapIterator.next().values().iterator(); } this.collectionIterator.remove(); } } /** * Add the relation of the relationship primitive type to the target primitive. */ public synchronized Relationship addRelationship(Primitive type, Primitive target) { Vertex typeVertex = this.network.createVertex(type); Vertex targetVertex = this.network.createVertex(target); return addRelationship(typeVertex, targetVertex, -1, false); } /** * Add the relation of the relationship primitive type to the target vertex. */ public synchronized Relationship addRelationship(Primitive type, Vertex target) { Vertex primitive = this.network.createVertex(type); return addRelationship(primitive, target, -1, false); } /** * Add the relation of the relationship type to the target vertex. * These are currently uni-directional. * Only a single relation of a type can be defined to the same target, * i.e. relationships to the same vertex are unique. * unless the relationship is ordered, then they are only equal if the same index. */ public synchronized Relationship addRelationship(Vertex type, Vertex target) { return addRelationship(type, target, -1, false); } /** * Add the relation of the relationship type to the target vertex. * These are currently uni-directional. * Only a single relation of a type can be defined to the same target, * i.e. relationships to the same vertex are unique. * unless the relationship is ordered, then they are only equal if the same index. */ public synchronized Relationship addRelationship(Primitive type, Vertex target, int index) { return addRelationship(this.network.createVertex(type), target, index, false); } /** * Add the relation of the relationship type to the target vertex. * These are currently uni-directional. * Only a single relation of a type can be defined to the same target, * i.e. relationships to the same vertex are unique. * unless the relationship is ordered, then they are only equal if the same index. */ public synchronized Relationship addRelationship(Primitive type, Primitive target, int index) { return addRelationship(this.network.createVertex(type), this.network.createVertex(target), index, false); } /** * Add the relation of the relationship type to the target vertex. * These are currently uni-directional. * Only a single relation of a type can be defined to the same target, * i.e. relationships to the same vertex are unique. * unless the relationship is ordered, then they are only equal if the same index. */ public synchronized Relationship addRelationship(Vertex type, Vertex target, int index) { return addRelationship(type, target, index, false); } /** * Add the relation of the relationship type to the target vertex. * Only increment the correctness if not internal. */ public synchronized Relationship addRelationship(Vertex type, Vertex target, int index, boolean internal) { BasicRelationship relationship = new BasicRelationship(this, type, target); relationship.setIndex(index); return addRelationship(relationship, internal, false, 0.5f); } /** * Add the relation of the relationship type to the target vertex. * The correctness decreases the correctness of the relation. */ public synchronized Relationship addWeakRelationship(Primitive type, Primitive target, float correctnessMultiplier) { return addWeakRelationship(this.network.createVertex(type), this.network.createVertex(target), correctnessMultiplier); } /** * Add the relation of the relationship type to the target vertex. * The correctness decreases the correctness of the relation. */ public synchronized Relationship addWeakRelationship(Primitive type, Vertex target, float correctnessMultiplier) { return addWeakRelationship(this.network.createVertex(type), target, correctnessMultiplier); } /** * Add the relation of the relationship type to the target vertex. * The correctness decreases the correctness of the relation. */ public synchronized Relationship addWeakRelationship(Vertex type, Vertex target, float correctnessMultiplier) { BasicRelationship relationship = new BasicRelationship(this, type, target); return addRelationship(relationship, false, false, correctnessMultiplier); } /** * Add the relation ensuring uniqueness. */ public synchronized Relationship addRelationship(Relationship relationship, boolean internal) { return addRelationship(relationship, internal, false, 0.5f); } /** * Add the relation ensuring uniqueness. */ public synchronized Relationship addRelationship(Relationship relationship, boolean internal, boolean init, float correctnessMultiplier) { if (!internal && !init && !this.isTemporary && (this.network.isReadOnly() || relationship.getType().getNetwork().isReadOnly() || relationship.getTarget().getNetwork().isReadOnly())) { MemoryStorageException exception = new MemoryStorageException("Read-only vertices cannot be modified."); exception.printStackTrace(); throw exception; } // Stored as map of maps. Map<Relationship, Relationship> relationships = getRelationships().get(relationship.getType()); if (relationships == null) { relationships = new HashMap<Relationship, Relationship>(); getRelationships().put(relationship.getType(), relationships); } // Check if already has the relationship. Relationship existing = relationships.get(relationship); if (existing == null) { if (! internal) { // MAX_VALUE means add to the end. if (!relationship.hasIndex() || (relationship.getIndex() == Integer.MAX_VALUE)) { relationship.setIndex(relationships.size()); } relationship.setCorrectness(correctnessMultiplier); } relationships.put(relationship, relationship); // Also add to allRelationships for JPA change tracking. if (!init && (this.allRelationships != null)) { this.allRelationships.add(relationship); } if (!internal) { relationship.setCreationDate(new Date()); } existing = relationship; } else if (! internal) { float correctness = existing.getCorrectness(); if (correctness != 2.0f) { // 2.0 is used to define prefer relationship // Either switch to positive as the inverse value, // or increment its correctness by 1/2. if (correctness < 0) { correctness = (-1.0f - correctness) * -1.0f; if (correctness <= -0.99) { correctness = -1; } } else { correctness = correctness + ((1.0f - correctness) * correctnessMultiplier); if (correctness >= 0.99) { correctness = 1; } } existing.setCorrectness(correctness); } } if (!internal) { existing.incrementAccessCount(); if (relationship.getType().is(Primitive.RESPONSE)) { this.hasResponse = Boolean.TRUE; } if (relationships.size() > Forgetfulness.MAX_RELATIONSHIPS) { setIsDirty(true); // direct access doesn't detect change... } if ((this.allRelationships != null) && (this.allRelationships.size() > Forgetfulness.MAX_RELATIONSHIPS)) { if (this.allRelationships.size() != totalRelationships()) { // Corruption detected. System.out.println("Relationship corruption detected: " + this); setIsDirty(true); // direct access doesn't detect change... } } } return existing; } /** * Two vertices are equal if they have the same data. */ public boolean equals(Object object) { if (this == object) { return true; } if (!(object instanceof Vertex)) { return false; } Vertex otherVertex = (Vertex) object; if ((this.id != null) && this.id.equals(otherVertex.getId())) { return true; } if ((this.data == null) || (otherVertex.getData() == null)) { return false; } return (this.data.equals(otherVertex.getData())); } /** * Compare the vertices ignoring case. */ public boolean equalsIgnoreCase(Vertex vertex) { if (this.equals(vertex)) { return true; } if ((this.data instanceof String) && (vertex.getData() instanceof String)) { return ((String)this.data).equalsIgnoreCase((String)vertex.getData()); } return false; } public Long getId() { return id; } /** * Set the vertex id. * The id can only be set when loading or creating a vertex. */ public void setId(Long id) { this.id = id; } /** * Hash first on data then id for equality compatibility. */ public int hashCode() { if (this.data != null) { return this.data.hashCode(); } else if (this.id != null) { return this.id.intValue(); } return super.hashCode(); } /** * Return the data value that the vertex represents. */ public Object getData() { return data; } /** * Set the data value that the vertex represents. */ public void setData(Object data) { this.data = data; if (data != null) { this.dataType = convertDataType(data); } } /** * Return if the vertex has a data value that it represents. */ public boolean hasData() { return data != null; } /** * Return if the relationships have been instantiated. */ public synchronized boolean hasRelationships() { return this.relationships != null; } /** * Return all relationships. * Relationships are stored as a map keyed on the relationship type, * with ordered list of relationship targets. */ public Map<Vertex, Map<Relationship, Relationship>> getRelationships() { if (this.relationships == null) { this.relationships = new HashMap<Vertex, Map<Relationship, Relationship>>(); // Lazy init from parent. if (this.original != null) { for (Iterator<Relationship> iterator = this.original.allRelationships(); iterator.hasNext(); ) { Relationship originalRelationship = iterator.next(); Vertex type = this.network.findById(originalRelationship.getType().getId()); Vertex target = this.network.findById(originalRelationship.getTarget().getId()); Relationship relationship = addRelationship(type, target, originalRelationship.getIndex(), true); relationship.setCorrectness(originalRelationship.getCorrectness()); } } else if (this.allRelationships != null) { // Lazy init from database. for (Relationship relationship : this.allRelationships) { addRelationship(relationship, true, true, 0); } } } return this.relationships; } /** * Apply the quotient. * Apply the equation to the variable matches. * This is basically a meta-language (4GL) based on Equation objects (vertices). */ public synchronized Vertex applyQuotient(Map<Vertex, Vertex> variables, Network network) { // TODO error handle invalid operations Vertex result = null; boolean isDebug = network.getBot().isDebugFiner(); if (isVariable()) { result = variables.get(this); if (result == null) { result = network.createVertex(Primitive.NULL); } } else if (instanceOf(Primitive.EQUATION)) { try { // Check for byte-code. if (getData() instanceof BinaryData) { Vertex equation = new SelfDecompiler().parseEquationByteCode(this, (BinaryData)getData(), this.network); return equation.applyQuotient(variables, network); } Vertex operator = getRelationship(Primitive.OPERATOR); if (operator == null) { return network.createVertex(Primitive.NULL); } List<Relationship> arguments = orderedRelationships(Primitive.ARGUMENT); if (isDebug) { Vertex source = getRelationship(Primitive.SOURCE); String sourceCode = ""; if (source != null) { sourceCode = String.valueOf(source.getData()).trim(); } else if (operator.isPrimitive()) { sourceCode = ((Primitive)operator.getData()).getIdentity().toUpperCase() + "(" + orderedRelations(Primitive.ARGUMENT) + ")"; } Vertex number = getRelationship(Primitive.LINE_NUMBER); if (number != null) { sourceCode = String.valueOf(number.getData()) + ":" + sourceCode; } network.getBot().log(SELF, sourceCode, Level.FINER); } // NOT :0 // Check if negated. if (operator.is(Primitive.NOT)) { Vertex equation = arguments.get(0).getTarget(); result = equation.applyQuotient(variables, network); if (result.is(Primitive.TRUE)) { result = network.createVertex(Primitive.FALSE); } else if (result.is(Primitive.FALSE)) { result = network.createVertex(Primitive.TRUE); } else if (result.is(Primitive.UNKNOWN)) { result = network.createVertex(Primitive.UNKNOWN); } } else if (operator.is(Primitive.RELATION)) { result = applyRELATION(arguments, variables, network); } else if (operator.is(Primitive.RELATED)) { result = applyRELATED(arguments, variables, network); } else if (operator.is(Primitive.ASSOCIATE) || operator.is(Primitive.DISSOCIATE) || operator.is(Primitive.WEAKASSOCIATE)) { result = applyASSOCIATE(operator, arguments, variables, network); } else if (operator.is(Primitive.FOR)) { result = applyFOR(arguments, variables, network); } else if (operator.is(Primitive.WHILE)) { result = applyWHILE(arguments, variables, network); } else if (operator.is(Primitive.ASSIGN)) { // ASSIGN :0 TO :1 // Assign a variable a new value. Vertex variable = arguments.get(0).getTarget(); Vertex value = arguments.get(1).getTarget().applyQuotient(variables, network); if (value != null) { variables.put(variable, value); } if (isDebug) { network.getBot().log(SELF, "ASSIGN " + variable + " TO " + value, Level.FINER); } result = value; } else if (operator.is(Primitive.DEFINE)) { // DEFINE :0 AS (:1, :2) // Define the word(s) for something. Vertex object = arguments.get(0).getTarget().applyQuotient(variables, network); Iterator<Relationship> iterator = arguments.iterator(); iterator.next(); while (iterator.hasNext()) { Vertex word = iterator.next().getTarget().applyQuotient(variables, network); word.addRelationship(Primitive.MEANING, object); object.addRelationship(Primitive.WORD, word); network.associateCaseInsensitivity((String)word.getData(), object); if (isDebug) { network.getBot().log(SELF, "DEFINE " + object + " AS " + word, Level.FINER); } } result = object; } else if (operator.is(Primitive.RANDOM)) { result = applyRANDOM(arguments, variables, network); } else if (operator.is(Primitive.DEBUG)) { result = applyDEBUG(arguments, variables, network); } else if (operator.is(Primitive.IF)) { result = applyIF(arguments, variables, network); } else if (operator.is(Primitive.GREATER)) { result = applyGREATER(arguments, variables, network); } else if (operator.is(Primitive.LESS)) { result = applyLESS(arguments, variables, network); } else if (operator.is(Primitive.EQUAL)) { result = applyEQUAL(arguments, variables, network); } else if (operator.is(Primitive.OR) || operator.is(Primitive.AND)) { result = applyCONDITION(arguments, variables, network); } else if (operator.is(Primitive.DO)) { // DO (:0, :1, :2, ...) // Apply each equation in the arguments. Vertex returnPrimitive = network.createVertex(Primitive.RETURN); if (arguments != null) { for (Relationship doEquation : arguments) { result = doEquation.getTarget().applyQuotient(variables, network); if (variables.containsKey(returnPrimitive)) { // Clear return for named functions. if (hasName()) { variables.remove(returnPrimitive); } return result; } } } } else if (operator.is(Primitive.THINK)) { // THINK (:0, :1, :2, ...) // Apply each equation in the arguments and return. Vertex returnPrimitive = network.createVertex(Primitive.RETURN); for (Relationship doEquation : arguments) { result = doEquation.getTarget().applyQuotient(variables, network); if (variables.containsKey(returnPrimitive)) { // Clear return for named functions. if (hasName()) { variables.remove(returnPrimitive); } return result; } } result = returnPrimitive; } else if (operator.is(Primitive.WORD)) { result = applyWORD(arguments, variables, network); } else if (operator.is(Primitive.SENTENCE)) { result = applySENTENCE(arguments, variables, network); } else if (operator.is(Primitive.UPPERCASE)) { result = applyFRAGMENT(arguments, variables, network, Primitive.UPPERCASE); } else if (operator.is(Primitive.LOWERCASE)) { result = applyFRAGMENT(arguments, variables, network, Primitive.LOWERCASE); } else if (operator.is(Primitive.FORMAT)) { Vertex as = getRelationship(Primitive.AS); if (as != null) { as = as.applyQuotient(variables, network); } if (as != null && as.isPrimitive()) { result = applyFRAGMENT(arguments, variables, network, (Primitive)as.getData()); } else { result = applyFRAGMENT(arguments, variables, network, null); } } else if (operator.is(Primitive.PRIMITIVE)) { // PRIMITIVE (:0) // Create a primitive from the string. if (arguments.size() == 0) { result = network.createVertex(Primitive.NULL); } Vertex primitive = arguments.get(0).getTarget().applyQuotient(variables, network); result = network.createVertex(new Primitive(((String.valueOf(primitive.getData()).toLowerCase())))); } else if (operator.is(Primitive.INPUT)) { result = applyINPUT(arguments, variables, network); } else if (operator.is(Primitive.GET)) { result = applyGET(arguments, variables, network); } else if (operator.is(Primitive.SET)) { result = applySET(arguments, variables, network); } else if (operator.is(Primitive.ALL)) { result = applyALL(arguments, variables, network); } else if (operator.is(Primitive.COUNT)) { result = applyCOUNT(arguments, variables, network); } else if (operator.is(Primitive.APPEND)) { result = applyAPPEND(arguments, variables, network); } else if (operator.is(Primitive.NEW)) { result = applyNEW(arguments, variables, network); } else if (operator.is(Primitive.CALL)) { result = applyCALL(arguments, variables, network); } else if (operator.is(Primitive.LEARN)) { result = applyLEARN(arguments, variables, network); } else if (operator.is(Primitive.SRAI) || operator.is(Primitive.REDIRECT)) { result = applySRAI(arguments, variables, network); } else if (operator.is(Primitive.SRAIX) || operator.is(Primitive.REQUEST)) { result = applySRAIX(arguments, variables, network); } else if (operator.is(Primitive.RETURN)) { // RETURN :0 if (arguments == null || arguments.isEmpty()) { result = network.createVertex(Primitive.NULL); } else { result = arguments.get(0).getTarget().applyQuotient(variables, network); } variables.put(network.createVertex(Primitive.RETURN), result); } // Clear return for named functions. if (hasName()) { variables.remove(network.createVertex(Primitive.RETURN)); } } catch (SelfExecutionException exception) { throw exception; } catch (Exception exception) { network.getBot().log(this, exception); throw new SelfExecutionException(this, exception); } } else { result = (Vertex)(Object)this; } if (result == null) { result = network.createVertex(Primitive.NULL); } if (result.getNetwork() != network) { result = network.createVertex(result); } // Check for formula and transpose if (result.instanceOf(Primitive.FORMULA)) { Language language = network.getBot().mind().getThought(Language.class); Vertex newResult = language.evaluateFormula(result, variables, network); if (newResult == null) { language.log("Template formula cannot be evaluated", Level.FINE, result); result = network.createVertex(Primitive.NULL); } else { result = language.getWord(newResult, network); } } network.getBot().log(this, "result:", Level.FINER, result); return result; } /** * Evaluates any eval functions in the equation or formula.. * This is used by learn. */ public Vertex applyEval(Map<Vertex, Vertex> variables, Network network) { Vertex result = null; try { if (isVariable()) { result = variables.get(this); if (result == null) { result = network.createVertex(Primitive.NULL); } } else if (instanceOf(Primitive.EQUATION)) { // Check for byte-code. if (getData() instanceof BinaryData) { Vertex equation = new SelfDecompiler().parseEquationByteCode(this, (BinaryData)getData(), this.network); return equation.applyEval(variables, network); } Vertex operator = getRelationship(Primitive.OPERATOR); List<Relationship> arguments = orderedRelationships(Primitive.ARGUMENT); if (operator.is(Primitive.EVAL)) { // EVAL :0 return arguments.get(0).getTarget().applyQuotient(variables, network); } } else { result = (Vertex)(Object)this; } if (result == null) { result = network.createVertex(Primitive.NULL); } if (result.getNetwork() != network) { result = network.createVertex(result); } boolean formula = result.instanceOf(Primitive.FORMULA); boolean pattern = result.instanceOf(Primitive.PATTERN); // Check for formula and transpose if (formula || pattern) { List<Vertex> words = result.orderedRelations(Primitive.WORD); if (words == null) { return result; } List<Vertex> newWords = new ArrayList<Vertex>(words.size()); boolean eval = false; boolean formulaRequired = false; for (Vertex word: words) { if (word.instanceOf(Primitive.EQUATION)) { // Check for byte-code. if (word.getData() instanceof BinaryData) { word = new SelfDecompiler().parseEquationByteCode(word, (BinaryData)word.getData(), this.network); } Vertex operator = word.getRelationship(Primitive.OPERATOR); if (operator != null && operator.is(Primitive.EVAL)) { eval = true; Vertex newWord = word.applyEval(variables, network); if (newWord.instanceOf(Primitive.EQUATION) || newWord.instanceOf(Primitive.FORMULA)) { formulaRequired = true; } newWords.add(newWord); } else { formulaRequired = true; newWords.add(word); } } else if (word.instanceOf(Primitive.VARIABLE)) { formulaRequired = true; newWords.add(word); } else { newWords.add(word); } } if (eval) { if (pattern) { result = network.createTemporyVertex(); result.addRelationship(Primitive.INSTANTIATION, Primitive.PATTERN); } else if (formulaRequired) { result = network.createInstance(Primitive.FORMULA); } else { result = network.createTemporyVertex(); result.addRelationship(Primitive.INSTANTIATION, Primitive.SENTENCE); } int index = 0; for (Vertex word : newWords) { result.addRelationship(Primitive.WORD, word, index); index++; } if (!formulaRequired) { Language language = network.getBot().mind().getThought(Language.class); result = language.createSentenceText(result, network); if (pattern) { result = network.createSentence(Utils.reduce(result.printString())); } } } } } catch (SelfExecutionException exception) { throw exception; } catch (Exception exception) { throw new SelfExecutionException(this, exception); } return result; } /** * Apply the WORD operation. * WORD (:0, :1, :2, ...) * Create a compound word from the arguments. */ public Vertex applyWORD(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex nil = network.createVertex(Primitive.NULL); if (arguments.size() == 0) { return nil; } StringWriter writer = new StringWriter(); List<Vertex> words = new ArrayList<Vertex>(); for (Relationship relationship : arguments) { Vertex word = relationship.getTarget().applyQuotient(variables, network); if (word.instanceOf(Primitive.LIST)) { List<Vertex> elements = word.orderedRelations(Primitive.SEQUENCE); if (elements != null) { words.addAll(elements); } } else { words.add(word); } } Vertex previousWord = nil; for (int index = 0; index < words.size(); index++) { Vertex word = words.get(index); Vertex nextWord = nil; if (words.size() > (index + 1)) { nextWord = words.get(index + 1); } word = Language.getWordFollowing(word, previousWord, nextWord, network); writer.write(String.valueOf(word.getData())); if ((index + 1) < words.size()) { writer.write(" "); } previousWord = word; } return network.createWord(writer.toString()); } /** * Apply the SENTENCE operation. * SENTENCE (:0, :1, :2, ...) * Create a sentence from printing the arguments. */ public Vertex applySENTENCE(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex result = null; Vertex nil = network.createVertex(Primitive.NULL); if (arguments.size() == 0) { result = nil; } else if (arguments.size() == 1) { result = arguments.get(0).getTarget().applyQuotient(variables, network); if (!(result.getData() instanceof String)) { StringWriter writer = new StringWriter(); Vertex text = Language.getWordFollowing(result, nil, nil, network); writer.write(text.getDataValue()); result = network.createSentence(writer.toString()); } else { result = network.createSentence((String)result.getData()); } } else { StringWriter writer = new StringWriter(); List<Vertex> words = new ArrayList<Vertex>(); for (Relationship relationship : arguments) { words.add(relationship.getTarget().applyQuotient(variables, network)); } Vertex previousWord = nil; for (int index = 0; index < words.size(); index++) { Vertex word = words.get(index); Vertex nextWord = nil; if (words.size() > (index + 1)) { nextWord = words.get(index + 1); } word = Language.getWordFollowing(word, previousWord, nextWord, network); writer.write(String.valueOf(word.getData())); if ((index + 1) < words.size()) { writer.write(" "); } previousWord = word; } result = network.createSentence(writer.toString()); } return result; } /** * Apply the FRAGMENT operation. * FRAGMENT (:0, :1, :2, ...) * Create a fragment from printing the arguments. */ public Vertex applyFRAGMENT(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, Primitive format) { String text = null; Vertex nil = network.createVertex(Primitive.NULL); if (arguments.size() == 0) { return nil; } else if (arguments.size() == 1) { Vertex result = arguments.get(0).getTarget().applyQuotient(variables, network); if (!(result.getData() instanceof String)) { StringWriter writer = new StringWriter(); Vertex word = Language.getWordFollowing(result, nil, nil, network); writer.write(word.getDataValue()); text = writer.toString(); } else { text = (String)result.getData(); } } else { StringWriter writer = new StringWriter(); List<Vertex> words = new ArrayList<Vertex>(); for (Relationship relationship : arguments) { words.add(relationship.getTarget().applyQuotient(variables, network)); } Vertex previousWord = nil; for (int index = 0; index < words.size(); index++) { Vertex word = words.get(index); Vertex nextWord = nil; if (words.size() > (index + 1)) { nextWord = words.get(index + 1); } word = Language.getWordFollowing(word, previousWord, nextWord, network); writer.write(String.valueOf(word.getData())); if ((index + 1) < words.size()) { writer.write(" "); } previousWord = word; } text = writer.toString(); } boolean caseSensitive = false; if (format != null) { if (format.equals(Primitive.UPPERCASE)) { text = text.toUpperCase(); caseSensitive = true; } else if (format.equals(Primitive.LOWERCASE)) { text = text.toLowerCase(); caseSensitive = true; } else if (format.equals(Primitive.FORMAL)) { text = org.botlibre.tool.Utils.formal(text); caseSensitive = true; } else if (format.equals(Primitive.PERSON)) { text = org.botlibre.tool.Utils.person(text); } else if (format.equals(Primitive.PERSON2)) { text = org.botlibre.tool.Utils.person2(text); } else if (format.equals(Primitive.GENDER)) { text = org.botlibre.tool.Utils.gender(text); } else if (format.equals(Primitive.SENTENCE)) { text = Utils.capitalize(text); caseSensitive = true; } else if (format.equals(Primitive.EXPLODE)) { text = org.botlibre.tool.Utils.explode(text); } else if (format.equals(Primitive.NORMALIZE)) { text = org.botlibre.tool.Utils.normalize(text); } else if (format.equals(Primitive.DENORMALIZE)) { text = org.botlibre.tool.Utils.denormalize(text); } } Vertex fragment = network.createFragment(text); if (caseSensitive) { fragment.addRelationship(Primitive.TYPE, Primitive.CASESENSITVE); } return fragment; } /** * Apply the ALL operation. * ALL :0 FROM :1 * Get all the relationship value of type ARGUMENT(0) from ARGUMENT(1) as a new list */ public Vertex applyALL(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex result = null; Vertex relationship = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex source = arguments.get(1).getTarget().applyQuotient(variables, network); if (arguments.size() > 2) { Vertex associate = arguments.get(2).getTarget().applyQuotient(variables, network); Vertex associateRelationship = arguments.get(3).getTarget().applyQuotient(variables, network); // TODO result = source.mostConsciousWithAssoiate(relationship, associate, associateRelationship); } else { List<Relationship> values = source.orderedRelationships(relationship); if (values == null) { // Check all meanings of all words. Collection<Relationship> words = relationship.getRelationships(Primitive.WORD); Set<Vertex> processed = new HashSet<Vertex>(); processed.add(relationship); for (Relationship word : words) { Collection<Relationship> otherMeanings = word.getTarget().getRelationships(Primitive.MEANING); if (otherMeanings != null) { for (Relationship meaning : otherMeanings) { if (!processed.contains(meaning.getTarget())) { processed.add(meaning.getTarget()); values = source.orderedRelationships(meaning.getTarget()); if (values != null) { break; } } } } } } if (values == null) { result = network.createVertex(Primitive.NULL); } else { result = network.createInstance(Primitive.LIST); int index = 0; for (Relationship value : values) { if (value.getCorrectness() > 0) { if (index > 12) { break; } result.addRelationship(Primitive.SEQUENCE, value.getTarget(), index); index++; } } } } if (result == null) { result = network.createVertex(Primitive.NULL); } return result; } /** * Apply the ASSOCIATE or DISSOCIATE operation. * ASSOCIATE :0 TO :1 BY :3 * ASSOCIATE :0 TO :1 BY :3 WITH META :4 AS :5 * DISSOCIATE :0 TO :1 BY :3 * Associate the left with the right by the association, or remove association if negated. * i.e. "Bob loves Jill" (associate Bob to Jill by #loves) */ public Vertex applyASSOCIATE(Vertex operator, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex source = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex target = arguments.get(1).getTarget().applyQuotient(variables, network); Vertex association = arguments.get(2).getTarget().applyQuotient(variables, network); Relationship relationship = null; if (operator.is(Primitive.DISSOCIATE)) { if (source.hasRelationship(association, target)) { relationship = source.removeRelationship(association, target); } else if (target.instanceOf(Primitive.WORD) && target.getData() instanceof String) { // Check words case. if (!Utils.isCapitalized((String)target.getData())) { Vertex capitalized = network.createWord(Utils.capitalize((String)target.getData())); if (source.hasRelationship(association, capitalized)) { relationship = source.removeRelationship(association, capitalized); } } else { Vertex lower = network.createWord(((String)target.getData()).toLowerCase()); if (source.hasRelationship(association, lower)) { relationship = source.removeRelationship(association, lower); } } } else { // Check all meanings of all words. Collection<Relationship> words = target.getRelationships(Primitive.WORD); if (words != null) { Set<Vertex> processed = new HashSet<Vertex>(); processed.add(target); for (Relationship word : words) { Collection<Relationship> otherMeanings = word.getTarget().getRelationships(Primitive.MEANING); if (source.hasRelationship(word.getTarget())) { relationship = source.removeRelationship(association, word.getTarget()); break; } if (otherMeanings != null) { for (Relationship meaning : otherMeanings) { if (!processed.contains(meaning.getTarget())) { processed.add(meaning.getTarget()); if (source.hasRelationship(meaning.getTarget())) { relationship = source.removeRelationship(association, meaning.getTarget()); break; } } } } } } } if (relationship == null) { relationship = source.removeRelationship(association, target); } network.getBot().log(this, "Removing relation", Level.FINE, source, association, target); } else if (operator.is(Primitive.WEAKASSOCIATE)) { relationship = source.addWeakRelationship(association, target, 0.1f); network.getBot().log(this, "Adding weak relation", Level.FINE, source, association, target); } else { relationship = source.addRelationship(association, target); network.getBot().log(this, "Adding relation", Level.FINE, source, association, target); } if (arguments.size() == 5) { Vertex metaType = arguments.get(3).getTarget().applyQuotient(variables, network); Vertex metaTarget = arguments.get(4).getTarget().applyQuotient(variables, network); if (!metaTarget.is(Primitive.NULL)) { Vertex meta = network.createMeta(relationship); meta.addRelationship(metaType, metaTarget); network.getBot().log(this, "Adding relation meta", Level.FINER, metaType, metaTarget); } } return network.createVertex(Primitive.KNOWN); } /** * Append the relationship in order. * APPEND :0 TO :1 OF :2 * APPEND :0 TO :1 OF :2 WITH META :3 AS :4 * Add the relationship value ARGUMENT(2) of type ARGUMENT(1) to ARGUMENT(0) */ public Vertex applyAPPEND(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex source = arguments.get(2).getTarget().applyQuotient(variables, network); Vertex type = arguments.get(1).getTarget().applyQuotient(variables, network); Vertex target = arguments.get(0).getTarget().applyQuotient(variables, network); Relationship relationship = source.addRelationship(type, target, Integer.MAX_VALUE); if (arguments.size() == 5) { Vertex metaType = arguments.get(3).getTarget().applyQuotient(variables, network); Vertex metaTarget = arguments.get(4).getTarget().applyQuotient(variables, network); if (!metaTarget.is(Primitive.NULL)) { Vertex meta = network.createMeta(relationship); meta.addRelationship(metaType, metaTarget); } } return source; } /** * Apply the OR/AND condition. * IF (:0, :1) OR (:2, :3) THEN :0 ELSE :1 */ public Vertex applyCONDITION(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex first = arguments.get(0).getTarget().applyQuotient(variables, network); boolean result = false; if (arguments.size() == 1) { result = first.is(Primitive.TRUE); } else { Vertex second = arguments.get(1).getTarget().applyQuotient(variables, network); result = first.matches(second, new HashMap<Vertex, Vertex>()) == Boolean.TRUE; } if (hasRelationship(Primitive.NOT, Primitive.NOT)) { result = !result; } Collection<Relationship> conditions = getRelationships(Primitive.CONDITION); if (conditions != null) { for (Relationship condition : conditions) { Vertex operator = condition.getTarget().getRelationship(Primitive.OPERATOR); if (operator == null) { continue; } if (!result && operator.is(Primitive.OR)) { Vertex value = condition.getTarget().applyQuotient(variables, network); if (value.is(Primitive.TRUE)) { result = true; } } else if (result && operator.is(Primitive.AND)) { Vertex value = condition.getTarget().applyQuotient(variables, network); if (value.is(Primitive.FALSE)) { result = false; } } } } if (result) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } /** * Apply the IF operation. * IF (:0, :1) OR (:2, :3) THEN :0 ELSE :1 * If the first argument matches the second then apply the then, else apply the last then. */ public Vertex applyIF(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex first = arguments.get(0).getTarget().applyQuotient(variables, network); boolean result = false; if (arguments.size() == 1) { result = first.is(Primitive.TRUE); } else { Vertex second = arguments.get(1).getTarget().applyQuotient(variables, network); result = first.matches(second, new HashMap<Vertex, Vertex>()) == Boolean.TRUE; } if (hasRelationship(Primitive.NOT, Primitive.NOT)) { result = !result; } Collection<Relationship> conditions = getRelationships(Primitive.CONDITION); if (conditions != null) { for (Relationship condition : conditions) { Vertex operator = condition.getTarget().getRelationship(Primitive.OPERATOR); if (operator == null) { continue; } if (!result && operator.is(Primitive.OR)) { Vertex value = condition.getTarget().applyQuotient(variables, network); if (value.is(Primitive.TRUE)) { result = true; } } else if (result && operator.is(Primitive.AND)) { Vertex value = condition.getTarget().applyQuotient(variables, network); if (value.is(Primitive.FALSE)) { result = false; } } } } if (result) { Vertex then = getRelationship(Primitive.THEN); if (then != null) { return then.applyQuotient(variables, network); } } else { Vertex elseEquation = getRelationship(Primitive.ELSE); if (elseEquation != null) { return elseEquation.applyQuotient(variables, network); } } if (result) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } /** * Apply the SET operation. * SET :0 TO :1 ON :3 * SET the left with the right by the association, replace any existing relationship. * i.e. "Bob only loves Jill" (set #loves to Jill on Bob) */ public Vertex applySET(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex association = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex source = arguments.get(2).getTarget().applyQuotient(variables, network); Vertex target = arguments.get(1).getTarget().applyQuotient(variables, network); source.setRelationship(association, target); network.getBot().log(this, "Setting relation", Level.FINER, source, association, target); // Following some crazy AIML implied rules here... if (association.isPrimitive() && (association.is(Primitive.IT) || association.is(Primitive.HE) || association.is(Primitive.SHE))) { return association; } return target; } /** * Apply the RANDOM operation. * RANDOM (:0, :1, ...) * Return a random argument. */ public Vertex applyRANDOM(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { if (arguments.isEmpty()) { return network.createVertex(Primitive.NULL); } return Utils.random(arguments).getTarget().applyQuotient(variables, network); } /** * Apply the DEBUG operation. * DEBUG ("debug", :0, :2) * Log the arguments to the log. */ public Vertex applyDEBUG(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { if (network.getBot().isDebugFine()) { StringWriter writer = new StringWriter(); boolean first = true; for (Relationship argument : arguments) { if (!first) { writer.write(" : "); } first = false; writer.write(argument.getTarget().applyQuotient(variables, network).printString()); } network.getBot().log("DEBUG", writer.toString(), Level.FINE); } return network.createVertex(Primitive.NULL); } /** * Apply the COUNT operation. * COUNT :0 OF :1 * Return if the number of elements. */ public Vertex applyCOUNT(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex source = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex relationship; if (arguments.size() == 1) { relationship = network.createVertex(Primitive.SEQUENCE); } else { relationship = source; source = arguments.get(1).getTarget().applyQuotient(variables, network); } Collection<Relationship> values = source.getRelationships(relationship); BigInteger count = null; if (values == null) { count = BigInteger.valueOf(0); } else { count = BigInteger.valueOf(values.size()); } return network.createVertex(count); } /** * Apply the GREATER operation. * GREATER (:0, :2) * Return if the left is bigger than the right. */ public Vertex applyGREATER(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex left = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex right = arguments.get(1).getTarget().applyQuotient(variables, network); if (!(left.getData() instanceof Number) || !(right.getData() instanceof Number)) { return network.createVertex(Primitive.FALSE); } if (((Number) left.getData()).doubleValue() > ((Number) right.getData()).doubleValue()) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } /** * Apply the LESS operation. * LESS (:0, :2) * Return if the left is smaller than the right. */ public Vertex applyLESS(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex left = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex right = arguments.get(1).getTarget().applyQuotient(variables, network); if (!(left.getData() instanceof Number) || !(right.getData() instanceof Number)) { return network.createVertex(Primitive.FALSE); } if (((Number) left.getData()).doubleValue() < ((Number) right.getData()).doubleValue()) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } /** * Apply the LESS operation. * RQUAL (:0, :2) * Return if the left is equal to the right. */ public Vertex applyEQUAL(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex left = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex right = arguments.get(1).getTarget().applyQuotient(variables, network); if (left.equals(right)) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } /** * Apply the FOR operation. * FOR EACH #word OF :sentence AS :word [AND EACH :3 OF :4 AS :5] DO (:0, :1, ...) * Evaluate the DO for each relationship. */ public Vertex applyFOR(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { // Process a for loop, repeat the operation for each element in the sequence. List<List<Relationship>> sequences = new ArrayList<List<Relationship>>(); List<Vertex> forVariables = new ArrayList<Vertex>(); // Process the tri-pairs of source.relationship=variable. int maxSequenceSize = 0; for (int index = 0; index < arguments.size(); index = index + 3) { Vertex source = arguments.get(index + 1).getTarget().applyQuotient(variables, network); Vertex relationship = arguments.get(index).getTarget().applyQuotient(variables, network); List<Relationship> sequence = source.orderedRelationships(relationship); if (sequence == null) { sequence = new ArrayList<Relationship>(0); } // Keep track of the biggest sequence to null pads others. if (sequence.size() > maxSequenceSize) { maxSequenceSize = sequence.size(); } sequences.add(sequence); Vertex variable = null; if (arguments.size() > 2) { variable = arguments.get(index + 2).getTarget(); } forVariables.add(variable); } List<Relationship> doEquations = orderedRelationships(Primitive.DO); Vertex result; for (int index = 0; index < maxSequenceSize; index++) { for (int variableIndex = 0; variableIndex < forVariables.size(); variableIndex++) { Vertex variable = forVariables.get(variableIndex); if (variable != null) { List<Relationship> sequence = sequences.get(variableIndex); Vertex value = null; if (index >= sequence.size()) { value = network.createVertex(Primitive.NULL); } else { value = sequence.get(index).getTarget(); } variables.put(variable, value); } } for (Relationship doEquation: doEquations) { result = doEquation.getTarget().applyQuotient(variables, network); if (variables.containsKey(network.createVertex(Primitive.RETURN))) { return result; } } } return network.createVertex(Primitive.NULL); } /** * Apply the WHILE operation. * WHILE (:0, :1) DO (:0, :1, ...) * Evaluate the DO while true or matching. */ public Vertex applyWHILE(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { // Process a while loop, repeat the operation until true or max depth int depth = 0; boolean condition = true; List<Relationship> doEquations = orderedRelationships(Primitive.DO); Vertex result = network.createVertex(Primitive.NULL); while (condition && depth < Language.MAX_STACK) { Vertex first = arguments.get(0).getTarget().applyQuotient(variables, network); if (arguments.size() == 1) { condition = first.is(Primitive.TRUE); } else { Vertex second = arguments.get(1).getTarget().applyQuotient(variables, network); condition = first.matches(second, new HashMap<Vertex, Vertex>()) == Boolean.TRUE; } if (condition) { for (Relationship doEquation: doEquations) { result = doEquation.getTarget().applyQuotient(variables, network); if (variables.containsKey(network.createVertex(Primitive.RETURN))) { return result; } } } depth++; } if (depth >= Language.MAX_STACK) { network.getBot().log(SELF, "Max stack exceeded on while loop", Level.WARNING, Language.MAX_STACK); } return result; } /** * Apply the INPUT operation. * INPUT :0 PART :1 FOR :2 * Get the last input from the conversation for the speaker. */ public Vertex applyINPUT(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex index = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex speaker = arguments.get(1).getTarget().applyQuotient(variables, network); Vertex part = null; int partValue = 1; if (arguments.size() == 3) { part = speaker; try { partValue = Integer.valueOf(String.valueOf(part.getData())); } catch (Exception exception) { // Ignore, use 1; } speaker = arguments.get(2).getTarget().applyQuotient(variables, network); } Vertex input = network.createVertex(Primitive.INPUT_VARIABLE); Vertex conversation = variables.get(input.getRelationship(Primitive.CONVERSATION)); if (conversation == null) { return network.createVertex(Primitive.NULL); } int count = 0; int value = 1; try { value = Integer.valueOf(String.valueOf(index.getData())); } catch (Exception exception) { // Ignore, use 1; } List<Vertex> inputs = conversation.orderedRelations(Primitive.INPUT); int element = inputs.size() - 1; while (count < value && element >= 0) { input = inputs.get(element); if (input.hasRelationship(Primitive.SPEAKER, speaker)) { count++; if (count == value) { Vertex sentence = input.getRelationship(Primitive.INPUT); if (part == null) { return sentence; } if (!sentence.instanceOf(Primitive.PARAGRAPH)) { if (partValue == 1) { return sentence; } return network.createVertex(Primitive.NULL); } List<Vertex> sentences = sentence.orderedRelations(Primitive.SENTENCE); if (partValue > sentences.size()) { return network.createVertex(Primitive.NULL); } return sentences.get(partValue - 1); } } element--; } return network.createVertex(Primitive.NULL); } /** * Apply the GET operation. * GET :0 FROM :1 * Get the relationship value of type ARGUMENT(0) from ARGUMENT(1) */ public Vertex applyGET(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex result = null; Vertex relationship = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex source = arguments.get(1).getTarget().applyQuotient(variables, network); Vertex index = getRelationship(Primitive.INDEX); Vertex lastindex = getRelationship(Primitive.LASTINDEX); if ((index != null) && (index.getData() instanceof Number)) { int position = ((Number)index.getData()).intValue(); List<Vertex> values = source.orderedRelations(relationship); if (values != null && position > 0 && position <= values.size()) { result = values.get(position - 1); } } else if ((lastindex != null) && (lastindex.getData() instanceof Number)) { int position = ((Number)lastindex.getData()).intValue(); List<Vertex> values = source.orderedRelations(relationship); if (values != null && position > 0 && position <= values.size()) { result = values.get(values.size() - position); } } else { if (arguments.size() > 2) { Vertex associate = arguments.get(2).getTarget().applyQuotient(variables, network); Vertex associateRelationship = arguments.get(3).getTarget().applyQuotient(variables, network); result = source.mostConsciousWithAssoiate(relationship, associate, associateRelationship); } else { result = source.mostConscious(relationship); } } if (result == null) { // Check all meanings of all words. Collection<Relationship> words = relationship.getRelationships(Primitive.WORD); if (words != null) { Set<Vertex> processed = new HashSet<Vertex>(); processed.add(relationship); for (Relationship word : words) { Collection<Relationship> otherMeanings = word.getTarget().getRelationships(Primitive.MEANING); if (otherMeanings != null) { for (Relationship meaning : otherMeanings) { if (!processed.contains(meaning.getTarget())) { processed.add(meaning.getTarget()); result = source.mostConscious(meaning.getTarget()); if (result != null) { break; } } } } } } if (result == null) { result = network.createVertex(Primitive.NULL); } } return result; } /** * Apply the NEW operation. * NEW (:0, :1, ...) * i.e. new Number, Sequence * Create a new vertex as an instance of the argument types. */ public Vertex applyNEW(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex newVertex = null; newVertex = network.createVertex(); for (Relationship argument : arguments) { Vertex type = argument.getTarget().applyQuotient(variables, network); newVertex.addRelationship(Primitive.INSTANTIATION, type); // Assign the name of the type to the default name of the instance. /*Collection<Relationship> names = type.getRelationships(Primitive.WORD); if (names != null) { for (Relationship name : names) { newVertex.addRelationship(Primitive.WORD, name.getTarget()); } }*/ // Check if the type is a classification, if not, make its instantiations, specializations. if (!type.hasRelationship(Primitive.INSTANTIATION, Primitive.CLASSIFICATION)) { Collection<Relationship> specializations = type.getRelationships(Primitive.INSTANTIATION); if (specializations != null) { for (Relationship specialization : specializations) { type.addRelationship(Primitive.SPECIALIZATION, specialization.getTarget()); } type.addRelationship(Primitive.INSTANTIATION, Primitive.CLASSIFICATION); } } } return newVertex; } /** * Apply the call operation. * CALL :0 ON :1 [WITH (:2, :3, ...)] * i.e. CALL #push ON #Context WITH :thing1 * Call out to the named sense, arguments and return value must be vertices. */ @SuppressWarnings("rawtypes") public Vertex applyCALL(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) throws Exception { String methodName = ((Primitive)arguments.get(0).getTarget().applyQuotient(variables, network).getData()).getIdentity(); String senseName = ((Primitive)arguments.get(1).getTarget().applyQuotient(variables, network).getData()).getIdentity(); Object source = network.getBot().awareness().getSense(senseName); if (source == null) { source = network.getBot().mind().getThought(senseName); } if (source == null) { source = network.getBot().awareness().getTool(senseName); } if (source == null) { throw new SelfExecutionException(this, "Missing calling sense, thought, or tool."); } int size = arguments.size() - 1; Object[] methodArguments = new Object[size]; Class[] argumentTypes = new Class[size]; argumentTypes[0] = Vertex.class; methodArguments[0] = this; if (getNetwork() != network) { methodArguments[0] = network.createVertex(this); } for (int index = 2; index < arguments.size(); index++) { Vertex argument = arguments.get(index).getTarget().applyQuotient(variables, network); methodArguments[index - 1] = argument; argumentTypes[index - 1] = Vertex.class; } Method method = source.getClass().getMethod(methodName, argumentTypes); Vertex result = (Vertex)method.invoke(source, methodArguments); if (result == null) { result = network.createVertex(Primitive.NULL); } else { result = network.createVertex(result); } return result; } /** * Apply the LEARN operation. * LEARN :0 THAT :that TOPIC :topic TEMPLATE :1 * Evaluate and add the new response. */ public Vertex applyLEARN(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) throws Exception { Vertex pattern = arguments.get(0).getTarget().applyEval(variables, network); Vertex template = arguments.get(1).getTarget().applyEval(variables, network); Relationship relationship = pattern.addRelationship(Primitive.RESPONSE, template); template.addRelationship(Primitive.QUESTION, pattern); Vertex that = getRelationship(Primitive.THAT); if (that != null) { that = that.applyEval(variables, network); Vertex meta = network.createMeta(relationship); meta.addRelationship(Primitive.PREVIOUS, that); meta.addRelationship(Primitive.REQUIRE, Primitive.PREVIOUS); } Vertex topic = getRelationship(Primitive.TOPIC); if (topic != null) { topic = topic.applyEval(variables, network); Vertex meta = network.createMeta(relationship); meta.addRelationship(Primitive.TOPIC, topic); meta.addRelationship(Primitive.REQUIRE, Primitive.TOPIC); } network.getBot().log(this, "New response learned", Level.FINER, pattern, template, that, topic); if (!pattern.instanceOf(Primitive.PATTERN)) { pattern.associateAll(Primitive.WORD, pattern, Primitive.QUESTION); } else { // Check for state and extend. Vertex state = variables.get(network.createVertex(Primitive.STATE)); if (state != null) { // Get first case that gets sentence from input. List<Vertex> instructions = state.orderedRelations(Primitive.DO); Vertex sentenceState = null; if (instructions != null) { for (Vertex instruction : instructions) { if (instruction.instanceOf(Primitive.CASE)) { Vertex variable = instruction.getRelationship(Primitive.CASE); if ((variable != null) && variable.isVariable() && variable.hasRelationship(Primitive.INPUT)) { sentenceState = instruction.getRelationship(Primitive.GOTO); break; } } } } if (sentenceState != null) { if (sentenceState.getNetwork() != network) { sentenceState = network.createVertex(sentenceState); } Vertex child = AIMLParser.parser().createState(pattern, sentenceState, network); Vertex equation = network.createInstance(Primitive.CASE); equation.addRelationship(Primitive.PATTERN, pattern); if (that != null) { equation.addRelationship(Primitive.THAT, that); } if (topic != null) { equation.addRelationship(Primitive.TOPIC, topic); } equation.addRelationship(Primitive.TEMPLATE, template); child.addRelationship(Primitive.DO, equation); } } } return pattern; } /** * Apply the SRAI operation. * SRAI "Hello" * Return the response to processing the input. */ public Vertex applySRAI(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) throws Exception { Vertex sentence = arguments.get(0).getTarget().applyQuotient(variables, network); if (!sentence.instanceOf(Primitive.SENTENCE) && sentence.instanceOf(Primitive.FRAGMENT)) { sentence.addRelationship(Primitive.INSTANTIATION, Primitive.SENTENCE); } Vertex input = variables.get(network.createVertex(Primitive.INPUT_VARIABLE)); input = input.copy(); input.setRelationship(Primitive.INPUT, sentence); Vertex response = network.getBot().mind().getThought(Language.class).input(input, sentence, variables, network); if (response == null) { return network.createVertex(Primitive.NULL); } return response; } /** * Apply the SRAIX operation. * SRAIX "what is love" BOT "Brain Bot" LIMIT 5 SERVICE #botlibre APIKEY 12345 BOTID 12345 HINT "google" DEFAULT "Brain Bot is offline" * Execute the remote service call, and return the response. */ public Vertex applySRAIX(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) throws Exception { Vertex sentence = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex apikey = getRelationship(Primitive.APIKEY); String apikeyValue = null; if (apikey != null) { apikey = apikey.applyQuotient(variables, network); apikeyValue = apikey.printString(); } Vertex limit = getRelationship(Primitive.LIMIT); int limitValue = -1; if (limit != null) { limit = limit.applyQuotient(variables, network); limitValue = Integer.parseInt(limit.getDataValue()); } Vertex bot = getRelationship(Primitive.BOT); String botValue = null; if (bot != null) { bot = bot.applyQuotient(variables, network); botValue = bot.printString(); } Vertex botid = getRelationship(Primitive.BOTID); String botidValue = null; if (botid != null) { botid = botid.applyQuotient(variables, network); botidValue = botid.printString(); } Vertex server = getRelationship(Primitive.SERVER); String serverValue = null; if (server != null) { server = server.applyQuotient(variables, network); serverValue = server.printString(); } Vertex service = getRelationship(Primitive.SERVICE); Primitive serviceValue = null; if (service != null) { service = service.applyQuotient(variables, network); if (service.isPrimitive()) { serviceValue = (Primitive)service.getData(); } } Vertex hint = getRelationship(Primitive.HINT); String hintValue = null; if (hint != null) { hint = hint.applyQuotient(variables, network); hintValue = hint.printString(); } Vertex defaultResponse = getRelationship(Primitive.DEFAULT); String defaultValue = null; if (defaultResponse != null) { defaultResponse = defaultResponse.applyQuotient(variables, network); defaultValue = defaultResponse.printString(); } try { String message = sentence.printString(); String response = network.getBot().awareness().getSense(RemoteService.class).request(message, botValue, botidValue, serverValue, serviceValue, apikeyValue, limitValue, hintValue, network); if (response == null) { if (defaultValue != null && !defaultValue.isEmpty()) { return network.createSentence(defaultValue); } return network.createVertex(Primitive.NULL); } return network.createSentence(response); } catch (Exception exception) { network.getBot().log(this, exception); if (defaultValue != null && !defaultValue.isEmpty()) { return network.createSentence(defaultValue); } return network.createVertex(Primitive.NULL); } } /** * Check if any of the words have the relationship. */ public Vertex checkRelationTargetForAllWords(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, Vertex left, Vertex right, Vertex relation, Collection<Relationship> words) { // Check all meanings of all words. if (words != null && !right.instanceOf(Primitive.WORD)) { Set<Vertex> processed = new HashSet<Vertex>(); processed.add(right); for (Relationship word : words) { Collection<Relationship> otherMeanings = word.getTarget().getRelationships(Primitive.MEANING); if (otherMeanings != null) { for (Relationship meaning : otherMeanings) { if (!processed.contains(meaning.getTarget())) { processed.add(meaning.getTarget()); if (left.hasOrInheritsRelationship(relation, meaning.getTarget())) { // Left has the relationship, return true. return network.createVertex(Primitive.TRUE); } else if (left.hasOrInheritsInverseRelationship(relation, meaning.getTarget())) { // Left has an inverse relationship to the right, return false. return network.createVertex(Primitive.FALSE); } } } } } } return null; } /** * Check if any of the words have the relationship. */ public Vertex checkRelationRelationshipForAllWords(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, Vertex left, Vertex right, Vertex relation, Collection<Relationship> words) { // Check all meanings of all words. if (words != null && !right.instanceOf(Primitive.WORD)) { Set<Vertex> processed = new HashSet<Vertex>(); processed.add(right); for (Relationship word : words) { Collection<Relationship> otherMeanings = word.getTarget().getRelationships(Primitive.MEANING); if (otherMeanings != null) { for (Relationship meaning : otherMeanings) { if (!processed.contains(meaning.getTarget())) { processed.add(meaning.getTarget()); if (left.hasOrInheritsRelationship(meaning.getTarget(), right)) { // Left has the relationship, return true. return network.createVertex(Primitive.TRUE); } else if (left.hasOrInheritsInverseRelationship(meaning.getTarget(), right)) { // Left has an inverse relationship to the right, return false. return network.createVertex(Primitive.FALSE); } } } } } } return null; } /** * Apply the relation operation. * IS :0 RELATED TO :1 [BY :2] * Return if the left has the relation to the right * i.e. "Bob love's Jill" (does Bob have #loves relationship to Jill) * or also "Bob love's?" (what does Bob have a #loves relationship to?) * or "Bob feels how to Jill?" (what is Bob's relationship to Jill?) */ public Vertex applyRELATION(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex result = null; Vertex relation = null; Vertex left = arguments.get(0).getTarget().applyQuotient(variables, network); Vertex right = arguments.get(1).getTarget().applyQuotient(variables, network); // The relation is optional, if no relation then check any relation if (arguments.size() > 2) { relation = arguments.get(2).getTarget().applyQuotient(variables, network); } if (relation == null) { // If no relation type, then check for any relationship. if (left.hasAnyRelationshipToTarget(right)) { // Left has a relationship to right, return true. result = network.createVertex(Primitive.TRUE); } else if (left.hasRelationship(right)) { // Left has a relationship of type right, return the value. result = left.mostConscious(right); } else if (right.hasRelationship(left)) { // Right has a relationship of type left, return the value. result = right.mostConscious(left); } else if (left.hasAnyRelationshipToTargetOfType(right)) { // Left has a relationship to a target that is an instance of right, return the target. result = left.mostConsciousTargetOfType(right); } else if (right.hasAnyRelationshipToTargetOfType(left)) { // Left has a relationship to a target that is an instance of right, return the target. result = right.mostConsciousTargetOfType(left); } } else { relation = relation.applyQuotient(variables, network); if (left.hasOrInheritsRelationship(relation, right)) { // Left has the relationship, return true. result = network.createVertex(Primitive.TRUE); } else if (left.hasOrInheritsInverseRelationship(relation, right)) { // Left has an inverse relationship to the right, return false. result = network.createVertex(Primitive.FALSE); } else { if (relation.is(Primitive.IS)) { if (left.hasAnyRelationshipToTarget(right)) { // Left has a relationship to right, return true. result = network.createVertex(Primitive.TRUE); } } if (result == null && (right.getData() instanceof String)) { // Check case. Vertex lower = network.createVertex(((String)right.getData()).toLowerCase()); if (left.hasOrInheritsRelationship(relation, lower)) { // Left has the relationship, return true. result = network.createVertex(Primitive.TRUE); } else if (left.hasOrInheritsInverseRelationship(relation, lower)) { // Left has an inverse relationship to the right, return false. result = network.createVertex(Primitive.FALSE); } Vertex caps = network.createVertex(Utils.capitalize(((String)right.getData()).toLowerCase())); if (left.hasOrInheritsRelationship(relation, caps)) { // Left has the relationship, return true. result = network.createVertex(Primitive.TRUE); } else if (left.hasOrInheritsInverseRelationship(relation, caps)) { // Left has an inverse relationship to the right, return false. result = network.createVertex(Primitive.FALSE); } } if (result == null) { // Check all meanings of all words. Collection<Relationship> words = right.getRelationships(Primitive.WORD); result = checkRelationTargetForAllWords(arguments, variables, network, left, right, relation, words); } if (result == null) { // Check synonyms as well. Collection<Relationship> words = right.getRelationships(Primitive.SYNONYM); result = checkRelationTargetForAllWords(arguments, variables, network, left, right, relation, words); } // Check all meanings of all words for relation. if (result == null) { // Check all meanings of all words. Collection<Relationship> words = relation.getRelationships(Primitive.WORD); result = checkRelationRelationshipForAllWords(arguments, variables, network, left, right, relation, words); } if (result == null) { // Check synonyms as well. Collection<Relationship> words = relation.getRelationships(Primitive.SYNONYM); result = checkRelationRelationshipForAllWords(arguments, variables, network, left, right, relation, words); } } // TODO: clean this up, and handle all other cases. } if (result != null) { network.getBot().log(SELF, "Found relation", Level.FINER, left, relation, right, result); } else { result = network.createVertex(Primitive.UNKNOWN); network.getBot().log(SELF, "Relation unknown", Level.FINER, left, relation, right, result); } return result; } /** * Apply the related operation. * RELATED TO :0 [BY :1] * Return what has a relationship to :0 by the relationships :1, * or what has any relationship to :0. */ public Vertex applyRELATED(List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network) { Vertex result = null; Vertex relation = null; Vertex source = arguments.get(0).getTarget().applyQuotient(variables, network); // The relation is optional, if no relation then check any relation if (arguments.size() > 1) { relation = arguments.get(1).getTarget().applyQuotient(variables, network); } List<Relationship> relationships = null; if (relation == null) { relationships = source.getNetwork().findAllRelationshipsTo(source); } else { relationships = source.getNetwork().findAllRelationshipsTo(source, relation); } for (Relationship relationship : relationships) { if (!relationship.isInverse() && ((result == null) || (relationship.getSource().getConsciousnessLevel() > result.getConsciousnessLevel()))) { result = relationship.getSource(); } } if (result != null) { network.getBot().log(SELF, "Found relation", Level.FINER, source, relation, result); } else { result = network.createVertex(Primitive.NULL); network.getBot().log(SELF, "Relation unknown", Level.FINER, source, relation, result); } return result; } /** * Compare if the two vertices match. * Used for rule processing. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public synchronized Boolean matches(Vertex vertex, Map<Vertex, Vertex> variables) { if (this == vertex) { return Boolean.TRUE; } if (hasData() && vertex.hasData()) { if ((this.data instanceof String) && (vertex.getData() instanceof String)) { if (((String)this.data).equalsIgnoreCase((String)vertex.getData())) { return Boolean.TRUE; } } else if ((this.data instanceof Number) && (vertex.getData() instanceof Number)) { if (((Number)this.data).doubleValue() == ((Number)vertex.getData()).doubleValue()) { return Boolean.TRUE; } } } Vertex variable; Vertex match; if (isVariable() && vertex.isVariable()) { // Variables must be identical to match. return Boolean.FALSE; } if (instanceOf(Primitive.ARRAY) || vertex.instanceOf(Primitive.ARRAY)) { Vertex list = this; Vertex item = vertex; if (vertex.instanceOf(Primitive.ARRAY)) { list = vertex; item = this; } Collection<Relationship> elements = list.orderedRelationships(Primitive.ELEMENT); if (elements != null) { for (Relationship element : elements) { if (element.getTarget().matches(item, variables) == Boolean.TRUE) { return Boolean.TRUE; } } } } if (instanceOf(Primitive.LIST) || vertex.instanceOf(Primitive.LIST)) { Vertex list = this; Vertex item = vertex; if (vertex.instanceOf(Primitive.LIST)) { list = vertex; item = this; } Collection<Relationship> elements = list.orderedRelationships(Primitive.SEQUENCE); if (elements != null) { for (Relationship element : elements) { if (element.getTarget().matches(item, variables) == Boolean.TRUE) { return Boolean.TRUE; } } } } if (isVariable()) { variable = (Vertex)(Object)this; match = vertex; } else if (vertex.isVariable()) { variable = vertex; match = (Vertex)(Object)this; } else { if (instanceOf(Primitive.PATTERN)) { return Language.evaluatePattern(this, vertex, Primitive.WILDCARD, new HashMap<Vertex, Vertex>(), this.network); } else if (vertex.instanceOf(Primitive.PATTERN)) { return Language.evaluatePattern(vertex, this, Primitive.WILDCARD, new HashMap<Vertex, Vertex>(), this.network); } // Match primitives to words. if (isPrimitive() && hasRelationship(Primitive.WORD, vertex)) { return Boolean.TRUE; } // Not equal, not variables, don't match. return null; } // Return if variable has already been matched. if (variables.containsKey(variable)) { if (variables.get(variable) == match) { return Boolean.TRUE; } } this.network.getBot().log(variable, " checking match", Level.FINEST, match); // Compare the variables relationships to the match. boolean wasInclude = false; for (Iterator<Relationship> iterator = variable.allRelationships(); iterator.hasNext(); ) { Relationship relationship = iterator.next(); boolean inverse = relationship.isInverse(); if (relationship.getTarget().is(Primitive.VARIABLE) || relationship.getType().is(Primitive.COMMENT)) { // Ignore instance of variable relationship. continue; } if (relationship.getType().is(Primitive.EQUALS)) { // Check includes and excludes. if (relationship.getTarget().equals(match)) { if (inverse) { return Boolean.FALSE; } variables.put(variable, match); variables.put(match, variable); return Boolean.TRUE; } if (!inverse) { wasInclude = true; } continue; } Vertex target = relationship.getTarget(); Vertex type = relationship.getType(); // If neither is a variable, just check if the relationship exists. if (!type.isVariable() && !target.isVariable()) { if (match.hasRelationship(type, target)) { if (inverse) { return Boolean.FALSE; } else { continue; } } } else if (type.isVariable()) { // If the type is a variable, then must check if any types match, and check if their target matches. // If the type is a match, but no targets are, then the type cannot be a match. boolean found = false; for (Vertex typeMatch : match.getRelationships().keySet()) { if (type.matches(typeMatch, variables) == Boolean.TRUE) { if (target.isVariable()) { // Check if any targets match variable. found = matchesTarget(match, typeMatch, target, variables); if (found) { break; } } else { // Check if has exact relationship. if (match.hasRelationship(typeMatch, target)) { found = true; break; } } break; } } if (!inverse && found) { continue; } else if (inverse && found) { this.network.getBot().log(variable, " does not match", Level.FINEST, match); return Boolean.FALSE; } else if (inverse) { this.network.getBot().log(variable, " does not match", Level.FINEST, match); } } else if (target.isVariable()) { // Check if any targets match variable. boolean found = matchesTarget(match, type, target, variables); if (!inverse && found) { continue; } else if (inverse && found) { this.network.getBot().log(variable, " does not match", Level.FINEST, match); return Boolean.FALSE; } else if (inverse) { this.network.getBot().log(variable, " does not match", Level.FINEST, match); } } if (!inverse) { this.network.getBot().log(variable, " does not match", Level.FINEST, match); return null; } } if (wasInclude) { this.network.getBot().log(variable, " does not match", Level.FINEST, match); return Boolean.FALSE; } this.network.getBot().log(variable, " matches", Level.FINER, match); variables.put(variable, match); if (variable.hasName()) { ((Map)variables).put(variable.getName(), match); } variables.put(match, variable); return Boolean.TRUE; } /** * Return if any targets of the match's type relationship match the target variable. */ protected boolean matchesTarget(Vertex match, Vertex type, Vertex target, Map<Vertex, Vertex> variables) { // Check if any targets match variable. List<Relationship> targets = match.orderedRelationshipsByConsciousness(type); if (targets != null) { for (Relationship targetMatch : targets) { if (!targetMatch.isInverse() && (target.matches(targetMatch.getTarget(), variables) == Boolean.TRUE)) { return true; } } } return false; } /** * Compare if the two vertices match. * Depth allows breadth first search for variables. * Used for rule processing. */ public synchronized boolean collectMatches(Vertex vertex, Map<Vertex, Set<Vertex>> variables) { if (this == vertex) { return true; } Vertex variable; Vertex match; if (isVariable() && vertex.isVariable()) { // Variables must be identical to match. return false; } else if (isVariable()) { variable = (Vertex)(Object)this; match = vertex; } else if (vertex.isVariable()) { variable = vertex; match = (Vertex)(Object)this; } else { // Not equal, not variables, don't match. return false; } // Return if variable has already been matched. Set<Vertex> matches = variables.get(variable); if (match == null) { matches = new HashSet<Vertex>(); variables.put(variable, matches); } if (matches.contains(match)) { return true; } this.network.getBot().log(variable, " checking match", Level.FINEST, match); // Keep track of variables that cannot match other values. Map<Vertex, Set<Vertex>> conflicts = new HashMap<Vertex, Set<Vertex>>(); // Compare the variables relationships to the match. for (Iterator<Relationship> iterator = variable.allRelationships(); iterator.hasNext(); ) { Relationship relationship = iterator.next(); if (Primitive.VARIABLE.equals(relationship.getTarget().getData())) { // Ignore instance of variable relationship. continue; } Vertex target = relationship.getTarget(); Vertex type = relationship.getType(); // If neither is a variable, just check if the relationship exists. if (!type.isVariable() && !target.isVariable()) { if (match.hasRelationship(type, target)) { continue; } } if (type.isVariable()) { // If the type is a variable, then must check if any types match, and check if their target matches. // If the type is a match, but no targets are, then the type cannot be a match. boolean found = false; for (Vertex typeMatch : match.getRelationships().keySet()) { if (type.collectMatches(typeMatch, variables)) { boolean localFound = false; if (target.isVariable()) { // Check if any targets match variable. Collection<Relationship> targets = match.getRelationships(typeMatch); if (targets != null) { for (Relationship targetMatch : targets) { if (target.collectMatches(targetMatch.getTarget(), variables)) { found = true; localFound = true; } } } } else { // Check if has exact relationship. if (match.hasRelationship(typeMatch, target)) { found = true; localFound = true; } } if (!localFound) { // Type cannot be a match (if this vertex is a match). Set<Vertex> typeConflicts = conflicts.get(type); if (typeConflicts == null) { typeConflicts = new HashSet<Vertex>(); conflicts.put(type, typeConflicts); } typeConflicts.add(relationship.getType()); } } } if (found) { continue; } } else if (target.isVariable()) { // Check if any targets match variable. Collection<Relationship> targets = match.getRelationships(type); boolean found = false; if (targets != null) { for (Relationship targetMatch : targets) { if (target.collectMatches(targetMatch.getTarget(), variables)) { found = true; } } if (found) { continue; } } } this.network.getBot().log(variable, " does not matches", Level.FINEST, match); return false; } this.network.getBot().log(variable, " matches", Level.FINER, match); matches.add(match); return true; } /** * Compare if the two vertices match. * 0 means perfect match. * -n means n relationships that do not match. * +n means n relationships that do match. */ public synchronized int compare(Vertex vertex) { if (this == vertex) { return 0; } int matches = 0; boolean match = true; for (Iterator<Relationship> iterator = allRelationships(); iterator.hasNext(); ) { Relationship relationship = iterator.next(); if (relationship.isInverse()) { if (!vertex.hasRelationship(relationship.getType(), relationship.getTarget())) { matches ++; } else { matches --; match = false; } } else { if (vertex.hasRelationship(relationship.getType(), relationship.getTarget())) { matches ++; } else { matches --; match = false; } } } for (Iterator<Relationship> iterator = vertex.allRelationships(); iterator.hasNext(); ) { Relationship relationship = iterator.next(); if (relationship.isInverse()) { if (!hasRelationship(relationship.getType(), relationship.getTarget())) { matches ++; } else { matches --; match = false; } } else { if (hasRelationship(relationship.getType(), relationship.getTarget())) { matches ++; } else { matches --; match = false; } } } if (match) { return 0; } return matches; } /** * Fix the corrupted relationship index order. * The order can get corrupted when relationships are forgotten. */ public void fixRelationships(Vertex type) { int index = 0; for (Relationship each : orderedRelationships(type)) { if (each.getIndex() != index) { each.setIndex(index); } index++; } } /** * Return the total number of all relationships. */ public synchronized int totalRelationships() { int size = 0; for (Map<Relationship, Relationship> relationships : getRelationships().values()) { size = size + relationships.size(); } return size; } /** * Return any relationship target of the primitive type. */ public Vertex getRelationship(Primitive type) { return getRelationship(this.network.createVertex(type)); } /** * Return any relationship target of the type. */ public Vertex getRelationship(Vertex type) { Map<Relationship, Relationship> targets = getRelationships().get(type); if (targets == null) { return null; } for (Relationship relationship : targets.values()) { if (relationship.getCorrectness() > 0.0) { return relationship.getTarget(); } } return null; } /** * Return any relationship target of the primitive type. */ public Collection<Relationship> getRelationships(Primitive type) { return getRelationships(this.network.createVertex(type)); } /** * Return all of the relationships of the type. */ public Collection<Relationship> getRelationships(Vertex relationshipType) { Map<Relationship, Relationship> targets = getRelationships().get(relationshipType); if (targets == null) { return null; } return targets.values(); } /** * Return the last of the ordered relationship, or null. */ public Vertex lastRelationship(Vertex type) { if (getRelationships().get(type) == null) { return null; } int max = 0; Relationship last = null; for (Relationship relationship : getRelationships(type)) { if (relationship.getIndex() >= max) { max = relationship.getIndex(); last = relationship; } } if (last == null) { return null; } if ((last.getIndex() + 1) != getRelationships(type).size()) { this.network.getBot().log(this, "Corrupted relationship index detected, correcting", Level.FINE, type); fixRelationships(type); } return last.getTarget(); } /** * Return the fromLast last of the ordered relationship, or null. * i.e. 2nd last, or 3rd last, etc. */ public Vertex lastRelationship(Vertex type, int fromLast) { if (getRelationships().get(type) == null) { return null; } List<Relationship> tail = new LinkedList<Relationship>(); for (Relationship relationship : getRelationships(type)) { Relationship previous = null; int previousIndex = 0; for (int index = 0; index < tail.size(); index++) { Relationship oneOfTheLast = tail.get(index); if (relationship.getIndex() > oneOfTheLast.getIndex()) { previous = oneOfTheLast; previousIndex = index; } } if (previous != null) { tail.add(previousIndex + 1, relationship); } else if (tail.size() < fromLast) { tail.add(0, relationship); } if (tail.size() > fromLast) { tail.remove(0); } } if (tail.size() < fromLast) { return null; } Relationship last = tail.get(tail.size() - 1); if ((last.getIndex() + 1) != getRelationships(type).size()) { this.network.getBot().log(this, "Corrupted relationship index detected, correcting", Level.FINE, type); fixRelationships(type); } return tail.get(0).getTarget(); } /** * Return the fromLast last of the ordered relationship, or null. */ public Vertex lastRelationship(Primitive type) { return lastRelationship(this.network.createVertex(type)); } /** * Return the last of the ordered relationship, or null. */ public Vertex lastRelationship(Primitive type, int fromLast) { return lastRelationship(this.network.createVertex(type), fromLast); } /** * Return all of the relationships of the primitive type, sorted by index. */ public List<Relationship> orderedRelationships(Primitive primitive) { return orderedRelationships(this.network.createVertex(primitive)); } /** * Return all of the relationships of the type, sorted by index. */ public synchronized List<Relationship> orderedRelationships(Vertex relationshipType) { if (getRelationships().get(relationshipType) == null) { return null; } List<Relationship> list = new ArrayList<Relationship>(getRelationships(relationshipType)); Collections.sort(list); return list; } /** * Return all of the relationships of the type, sorted by consciousness level. */ public List<Relationship> orderedRelationshipsByConsciousness(Primitive primitive) { return orderedRelationships(this.network.createVertex(primitive)); } /** * Return all of the relationships of the type, sorted by consciousness level. */ public synchronized List<Relationship> orderedRelationshipsByConsciousness(Vertex relationshipType) { if (getRelationships().get(relationshipType) == null) { return null; } List<Relationship> list = new ArrayList<Relationship>(getRelationships(relationshipType)); Collections.sort(list, new Comparator<Relationship>() { public int compare(Relationship left, Relationship right) { float leftLevel = computeCorrectness(left); float rightLevel = computeCorrectness(right); if (leftLevel == rightLevel) { return 0; } if (leftLevel > rightLevel) { return -1; } return 1; } }); return list; } /** * Return all of the relationships targets of the primitive type, sorted by index. */ public List<Vertex> orderedRelations(Primitive primitive) { return orderedRelations(this.network.createVertex(primitive)); } /** * Return all of the relationship targets of the type, sorted by index. */ public List<Vertex> orderedRelations(Vertex relationshipType) { List<Relationship> relationships = orderedRelationships(relationshipType); if (relationships == null) { return null; } List<Vertex> vertices = new ArrayList<Vertex>(relationships.size()); for (Relationship relationship : relationships) { if (relationship.getCorrectness() > 0.0) { vertices.add(relationship.getTarget()); } } return vertices; } /** * Return the target vertex related by the type, with the high consciousness level greater than the value. */ public Vertex mostConscious(Vertex type, float min) { return nextMostConscious(type, (Vertex)null, min, false); } /** * Return the relationship related by the type, with the high consciousness level. */ public Relationship mostConsciousRelationship(Vertex type) { return nextMostConsciousRelationship(type, (Vertex)null, 0, false); } /** * Return the relationship related by the type, with the high consciousness level. */ public Relationship nextMostConsciousRelationship(Vertex type, Vertex ignoring) { return nextMostConsciousRelationship(type, ignoring, 0, false); } /** * Return the relationship related by the type, with the high consciousness level. */ public Relationship mostConsciousRelationship(Primitive type) { return mostConsciousRelationship(this.network.createVertex(type)); } /** * Return the relationship related by the type, with the high consciousness level. */ public Relationship mostConsciousRelationship(Primitive type, float correctness) { return nextMostConsciousRelationship(this.network.createVertex(type), (Vertex)null, correctness, false); } /** * Return the relationship related by the type, with the high consciousness level. */ public Relationship nextMostConsciousRelationship(Primitive type, Vertex ignoring) { return nextMostConsciousRelationship(this.network.createVertex(type), ignoring); } /** * Return the target vertex related by the type, with the high consciousness level greater than the value. */ public Vertex mostConscious(Primitive type, float min) { return mostConscious(this.network.createVertex(type), min); } /** * Return the target vertex related by the type, with the high consciousness level greater than the value. */ public Vertex mostConscious(Vertex type, float min, boolean inverse) { return nextMostConscious(type, (Vertex)null, min, inverse); } /** * Return the target vertex related by the type, with the high consciousness level greater than the value. */ public Vertex nextMostConscious(Primitive type, Set<Vertex> ignoring) { return nextMostConscious(this.network.createVertex(type), ignoring, 0f, false); } /** * Return the target vertex related by the type, with the high consciousness level greater than the value. */ public Vertex nextMostConscious(Primitive type, Vertex ignoring, float min) { return nextMostConscious(this.network.createVertex(type), ignoring, min); } /** * Return the target vertex related by the type, with the high consciousness level greater than the value. */ public Relationship nextMostConsciousRelationship(Primitive type, Vertex ignoring, float min) { return nextMostConsciousRelationship(this.network.createVertex(type), ignoring, min, false); } /** * Return the target vertex related by the type, with the high consciousness level greater than the value. */ public Vertex nextMostConscious(Vertex type, Vertex ignoring, float min) { return nextMostConscious(type, ignoring, min, false); } /** * Return the target vertex related by the type with the high consciousness level. */ public Vertex mostConscious(Primitive type) { return mostConscious(this.network.createVertex(type)); } /** * Return the target vertex related by the type with the high consciousness level. */ public Vertex mostConscious(Vertex type) { return nextMostConscious(type, (Vertex)null, 0, false); } /** * Return the target vertex inversely/negatively related by the type, with the high consciousness level. * The level is multiplied by the relationship correctness. */ public Vertex nextMostConscious(Primitive type, Vertex ignoring, float min, boolean inverse) { return nextMostConscious(this.network.createVertex(type), ignoring, 0f, false); } /** * Return the target vertex inversely/negatively related by the type, with the high consciousness level. * The level is multiplied by the relationship correctness. */ public Vertex nextMostConscious(Vertex type, Vertex ignoring, float min, boolean inverse) { Relationship relationship = nextMostConsciousRelationship(type, ignoring, min, inverse); if (relationship != null) { return relationship.getTarget(); } return null; } /** * Return the target vertex inversely/negatively related by the type, with the high consciousness level. * The level is multiplied by the relationship correctness. */ public Vertex nextMostConscious(Vertex type, Set<Vertex> ignoring, float min, boolean inverse) { Relationship relationship = nextMostConsciousRelationship(type, ignoring, min, inverse); if (relationship != null) { return relationship.getTarget(); } return null; } public static float computeCorrectness(Relationship relationship) { float correctness = Math.abs(relationship.getCorrectness()); int consciousnessLevel = relationship.getTarget().getConsciousnessLevel(); float level = consciousnessLevel * correctness; // Return most correct if all at 0 level. if (consciousnessLevel == 0) { level = correctness; } return level; } /** * Return the target vertex inversely/negatively related by the type, with the high consciousness level. * The level is multiplied by the relationship correctness. */ public synchronized Relationship nextMostConsciousRelationship(Vertex type, Vertex ignoring, float min, boolean inverse) { Collection<Relationship> relationships = getRelationships(type); if (relationships == null) { return null; } Relationship highest = null; float highestLevel = 0; float highestCorrectness = 0; for (Relationship relationship : relationships) { if ((relationship.isInverse() && inverse) || (!relationship.isInverse() && !inverse)) { if (ignoring != relationship.getTarget()) { float correctness = Math.abs(relationship.getCorrectness()); float level = computeCorrectness(relationship); if ((highest == null) || (level > highestLevel)) { if ((highest == null) || (correctness >= highestCorrectness)) { highest = relationship; highestLevel = level; highestCorrectness = correctness; } } } } } if (highest == null) { return null; } if (Math.abs(highest.getCorrectness()) < min) { this.network.getBot().log(this, "Relationship not sufficiently correct", Level.FINER, highest, highest.getCorrectness(), min); return null; } return highest; } /** * Return the target vertex inversely/negatively related by the type, with the high consciousness level. * The level is multiplied by the relationship correctness. */ public synchronized Relationship nextMostConsciousRelationship(Vertex type, Set<Vertex> ignoring, float min, boolean inverse) { Collection<Relationship> relationships = getRelationships(type); if (relationships == null) { return null; } Relationship highest = null; float highestLevel = 0; float highestCorrectness = 0; for (Relationship relationship : relationships) { if ((relationship.isInverse() && inverse) || (!relationship.isInverse() && !inverse)) { if (!ignoring.contains(relationship.getTarget())) { float correctness = Math.abs(relationship.getCorrectness()); float level = computeCorrectness(relationship); if ((highest == null) || (level > highestLevel)) { if ((highest == null) || (correctness >= highestCorrectness)) { highest = relationship; highestLevel = level; highestCorrectness = correctness; } } } } } if (highest == null) { return null; } if (Math.abs(highest.getCorrectness()) < min) { this.network.getBot().log(this, "Relationship not sufficiently correct", Level.FINER, highest, highest.getCorrectness(), min); return null; } return highest; } /** * Return the most conscious target the vertex has any relationship to that is an instantiation of the classification. */ public synchronized Vertex mostConsciousTargetOfType(Vertex classification) { Iterator<Relationship> relationships = allRelationships(); Vertex highest = null; Vertex instantiation = this.network.createVertex(Primitive.INSTANTIATION); while (relationships.hasNext()) { Relationship relationship = relationships.next(); if (!relationship.isInverse() && (relationship.getTarget().hasRelationship(instantiation, classification)) && ((highest == null) || (relationship.getTarget().getConsciousnessLevel() > highest.getConsciousnessLevel()))) { highest = relationship.getTarget(); } } return highest; } /** * Return the target vertex related by the type, with the high consciousness level. */ public synchronized Vertex mostConscious(Vertex type, Vertex classification) { Collection<Relationship> relationships = getRelationships(type); if (relationships == null) { return null; } Vertex highest = null; Vertex instantiation = this.network.createVertex(Primitive.INSTANTIATION); for (Relationship relationship : relationships) { if (!relationship.isInverse() && (relationship.getTarget().hasRelationship(instantiation, classification)) && ((highest == null) || (relationship.getTarget().getConsciousnessLevel() > highest.getConsciousnessLevel()))) { highest = relationship.getTarget(); } } return highest; } /** * Return the target vertex related by the type, that has the relationship to the previous, otherwise null if not found. */ public synchronized Vertex getAssoiate(Vertex type, Vertex associate, Vertex associateType) { return getAssoiate(type, associate, associateType, null, null, null, null); } /** * Return the target vertex related by the type, that has the relationship to the previous, otherwise null if not found. */ public synchronized Vertex getAssoiate(Vertex type, Vertex associate, Vertex associateType, Vertex defaultAssociate) { return getAssoiate(type, associate, associateType, (Vertex)null, null, (Vertex)null, null, defaultAssociate); } /** * Return the target vertex related by the type, that has the relationship to the previous, otherwise null if not found. */ public synchronized Vertex getAssoiate(Vertex type, Vertex associate, Vertex associateType, Vertex associate2, Vertex associateType2) { return getAssoiate(type, associate, associateType, associate2, associateType2, null, null); } /** * Return the target vertex related by the type, that has the relationship to the previous, otherwise null if not found. */ public synchronized Vertex getAssoiate(Vertex type, Vertex associate, Vertex associateType, Vertex associate2, Vertex associateType2, Vertex associate3, Vertex associateType3) { return getAssoiate(type, associate, associateType, associate2, associateType2, associate3, associateType3, null); } /** * Return the target vertex related by the type, that has the relationship to the previous, otherwise null if not found. * Ideally the target also has associate2. */ public synchronized Vertex getAssoiate(Vertex type, Vertex associate, Vertex associateType, Vertex associate2, Vertex associateType2, Vertex associate3, Vertex associateType3, Vertex defaultAssociate) { Collection<Relationship> relationships = getRelationships(type); if (relationships == null) { return null; } Relationship best = null; float bestMatch = 0; for (Relationship relationship : relationships) { if (relationship.isInverse()) { continue; } Vertex target = relationship.getTarget(); float match = 0; if (target.hasRelationship(associateType, associate)) { match = target.getRelationship(associateType, associate).getCorrectness(); } if ((associate2 != null) && target.hasRelationship(associateType2, associate2)) { match = match + target.getRelationship(associateType2, associate2).getCorrectness(); } if ((associate3 != null) && target.hasRelationship(associateType3, associate3)) { match = match + target.getRelationship(associateType3, associate3).getCorrectness(); } if (match > 0 && match >= bestMatch) { if (best == null || match > bestMatch || relationship.getCorrectness() > best.getCorrectness()) { best = relationship; bestMatch = match; } } } if (best != null) { return best.getTarget(); } return defaultAssociate; } /** * Return the target vertex related by the type, that has the relationship to the previous, otherwise null if not found. * Ideally the target also has associate2. */ public synchronized Vertex getAssoiate(Vertex type, Vertex associate, Vertex associateType, Vertex associate2, Vertex associateType2, Collection<Relationship> associates3, Vertex associateType3, Vertex defaultAssociate) { Collection<Relationship> relationships = getRelationships(type); if (relationships == null) { return null; } Relationship best = null; float bestMatch = 0; for (Relationship relationship : relationships) { if (relationship.isInverse()) { continue; } Vertex target = relationship.getTarget(); float match = 0; if (target.hasRelationship(associateType, associate)) { match = target.getRelationship(associateType, associate).getCorrectness(); } if ((associate2 != null) && target.hasRelationship(associateType2, associate2)) { match = match + target.getRelationship(associateType2, associate2).getCorrectness(); } if (associates3 != null) { float max = 0; for (Relationship associate3 : associates3) { if (target.hasRelationship(associateType3, associate3.getTarget())) { max = Math.max(max, target.getRelationship(associateType3, associate3.getTarget()).getCorrectness()); } } match = match + max; } if (match > 0 && match >= bestMatch) { if (best == null || match > bestMatch || relationship.getCorrectness() > best.getCorrectness()) { best = relationship; bestMatch = match; } } } if (best != null) { return best.getTarget(); } return defaultAssociate; } /** * Return the target vertex related by the type, that has the relationship to the previous, otherwise null if not found. * Ideally the target also has associate2. */ public synchronized Vertex getAssoiate(Vertex type, Vertex associate, Vertex associateType, Collection<Relationship> associates2, Vertex associateType2, Collection<Relationship> associates3, Vertex associateType3, Vertex defaultAssociate) { Collection<Relationship> relationships = getRelationships(type); if (relationships == null) { return null; } Relationship best = null; float bestMatch = 0; for (Relationship relationship : relationships) { if (relationship.isInverse()) { continue; } Vertex target = relationship.getTarget(); float match = 0; if (target.hasRelationship(associateType, associate)) { match = target.getRelationship(associateType, associate).getCorrectness(); } if (associates2 != null) { float max = 0; for (Relationship associate2 : associates2) { if (target.hasRelationship(associateType2, associate2.getTarget())) { max = Math.max(max, target.getRelationship(associateType2, associate2.getTarget()).getCorrectness()); } } match = match + max; } if (associates3 != null) { float max = 0; for (Relationship associate3 : associates3) { if (target.hasRelationship(associateType3, associate3.getTarget())) { max = Math.max(max, target.getRelationship(associateType3, associate3.getTarget()).getCorrectness()); } } match = match + max; } if (match > 0 && match >= bestMatch) { if (best == null || match > bestMatch || relationship.getCorrectness() > best.getCorrectness() || (match == bestMatch && relationship.getCorrectness() == best.getCorrectness() && best.getTarget().getData() instanceof String && Utils.isCaps((String)best.getTarget().getData()))) { best = relationship; bestMatch = match; } } } if (best != null) { return best.getTarget(); } return defaultAssociate; } /** * Return the target vertex related by the type, that is also most correctly related to the associate vertex by the relationship. * If no related vertices are related to the associate, then return the most conscious. */ public synchronized Vertex mostConsciousWithAssoiate(Vertex type, Vertex associate, Vertex associateType) { Collection<Relationship> relationships = getRelationships(type); if (relationships == null) { return null; } Relationship highest = null; Map<Vertex, Relationship> assoicates = new HashMap<Vertex, Relationship>(); Collection<Relationship> associateRelationships = associate.getRelationships(associateType); if (associateRelationships != null) { for (Relationship relationship : associate.getRelationships(associateType)) { assoicates.put(relationship.getTarget(), relationship); } for (Relationship relationship : relationships) { Vertex target = relationship.getTarget(); Relationship associateTarget = assoicates.get(target); if ((associateTarget != null) && (!relationship.isInverse()) && ((highest == null) || (associateTarget.getCorrectness() > highest.getCorrectness()))) { highest = associateTarget; } } } if (highest == null) { return mostConscious(type); } return highest.getTarget(); } /** * Return the target vertex related by the type, that is also most correctly related to the associate vertex by the relationship. * If no related vertices are related to the associate, then return the most conscious. */ public synchronized Vertex mostConsciousWithAssoiates(Vertex type, Vertex associate, Vertex associateType, Vertex associate2, Vertex associateType2) { Collection<Relationship> relationships = getRelationships(type); if (relationships == null) { return null; } Relationship highest = null; Map<Vertex, Relationship> first = new HashMap<Vertex, Relationship>(); Map<Vertex, Relationship> both = new HashMap<Vertex, Relationship>(); Map<Vertex, Relationship> all = new HashMap<Vertex, Relationship>(); Collection<Relationship> associateRelationships = associate.getRelationships(associateType); if (associateRelationships != null) { for (Relationship relationship : associateRelationships) { first.put(relationship.getTarget(), relationship); all.put(relationship.getTarget(), relationship); } } Collection<Relationship> associate2Relationships = associate2.getRelationships(associateType2); if (associate2Relationships != null) { for (Relationship relationship : associate2Relationships) { if (first.containsKey(relationship.getTarget())) { both.put(relationship.getTarget(), relationship); } all.put(relationship.getTarget(), relationship); } } if (!both.isEmpty()) { for (Relationship relationship : relationships) { Vertex target = relationship.getTarget(); Relationship associateTarget = both.get(target); if ((associateTarget != null) && (!relationship.isInverse()) && ((highest == null) || (associateTarget.getCorrectness() > highest.getCorrectness()))) { highest = associateTarget; } } if (highest != null) { return highest.getTarget(); } } if (!all.isEmpty()) { for (Relationship relationship : relationships) { Vertex target = relationship.getTarget(); Relationship associateTarget = all.get(target); if ((associateTarget != null) && (!relationship.isInverse()) && ((highest == null) || (associateTarget.getCorrectness() > highest.getCorrectness()))) { highest = associateTarget; } } } if (highest == null) { return mostConscious(type); } return highest.getTarget(); } /** * Associate each of the relationship target vertices with the target vertex by the type. */ public synchronized void weakAssociateAll(Primitive associate, Vertex target, Primitive type, float correctnessMultiplier) { weakAssociateAll(this.network.createVertex(associate), target, this.network.createVertex(type), correctnessMultiplier); } /** * Associate each of the relationship target vertices with the target vertex by the type. */ public synchronized void weakAssociateAll(Vertex associate, Vertex target, Vertex type, float correctnessMultiplier) { Collection<Relationship> relationships = getRelationships(associate); if (relationships == null) { return; } for (Relationship relationship : relationships) { relationship.getTarget().addWeakRelationship(type, target, correctnessMultiplier); } } /** * Associate each of the relationship target vertices with the target vertex by the type. */ public synchronized void associateAll(Primitive associate, Vertex target, Primitive type) { associateAll(this.network.createVertex(associate), target, this.network.createVertex(type)); } /** * Associate each of the relationship target vertices with the target vertex by the type. */ public synchronized void associateAll(Vertex associate, Vertex target, Vertex type) { Collection<Relationship> relationships = getRelationships(associate); if (relationships == null) { return; } for (Relationship relationship : relationships) { Vertex relation = relationship.getTarget(); if (!relation.isVariable()) { if (relation.isArray()) { Collection<Relationship> elements = getRelationships(Primitive.ELEMENT); if (elements == null) { continue; } for (Relationship element : elements) { element.getTarget().addRelationship(type, target); } } else { relation.addRelationship(type, target); } } } } /** * Dissociate the source with each of the relationship targets by the type. */ public synchronized void inverseAssociateAll(Primitive associate, Vertex target, Primitive type) { inverseAssociateAll(this.network.createVertex(associate), target, this.network.createVertex(type)); } /** * Dissociate the source with each of the relationship targets by the type. */ public synchronized void inverseAssociateAll(Vertex associate, Vertex target, Vertex type) { Collection<Relationship> relationships = getRelationships(associate); if (relationships == null) { return; } for (Relationship relationship : relationships) { relationship.getTarget().removeRelationship(type, target); } } /** * Return if any of the associates of the vertex have an inverse/negative relationship of the type to the target. */ public synchronized boolean hasAnyAssociatedInverseRelationship(Primitive associate, Vertex target, Primitive type) { return hasAnyAssociatedInverseRelationship(this.network.createVertex(associate), target, this.network.createVertex(type)); } /** * Return if any of the associates of the vertex have an inverse/negative relationship of the type to the target. */ public synchronized boolean hasAnyAssociatedInverseRelationship(Vertex associate, Vertex target, Vertex type) { Collection<Relationship> relationships = getRelationships(associate); if (relationships == null) { return false; } for (Relationship relationship : relationships) { if (relationship.getTarget().hasInverseRelationship(type, target)) { return true; } } return false; } /** * Remove the relationship of the relation type to the target vertex. * This records the relationships with a negative correctness, * or subtracts from the current correctness. */ public synchronized Relationship removeRelationship(Vertex type, Vertex target) { return removeRelationship(new BasicRelationship(this, type, target)); } /** * Remove the relationship of the relation primitive type to the target vertex. * This records the relationships with a negative correctness, * or subtracts from the current correctness. */ public synchronized Relationship removeRelationship(Primitive type, Vertex target) { return removeRelationship(this.network.createVertex(type), target); } /** * Remove the relationship of the relation primitive type to the target vertex. * This records the relationships with a negative correctness, * or subtracts from the current correctness. */ public synchronized Relationship removeRelationship(Primitive type, Primitive target) { return removeRelationship(this.network.createVertex(type), this.network.createVertex(target)); } /** * Remove the relationship. * This records the relationships with a negative correctness, * or subtracts from the current correctness. */ public synchronized Relationship removeRelationship(Relationship relationship) { relationship = addRelationship(relationship, true); float correctness = relationship.getCorrectness(); // Either switch to negative as the inverse value, // or increment its incorrectness by 1/2. if (correctness > 0) { relationship.setCorrectness((1.0f - correctness) * -1.0f); } else { correctness = correctness + ((-1.0f - correctness) * 0.5f); if (correctness <= -0.99) { correctness = -1; } relationship.setCorrectness(correctness); } return relationship; } /** * Remove the relationship. */ public synchronized void internalRemoveRelationship(Relationship relationship) { if (relationship == null) { return; } Map<Relationship, Relationship> relationships = getRelationships().get(relationship.getType()); if (relationships == null) { if (this.allRelationships != null && this.allRelationships.contains(relationship)) { this.network.removeRelationship(relationship); this.allRelationships.remove(relationship); } return; } Relationship existing = relationships.remove(relationship); if (existing == null) { if (this.allRelationships != null && this.allRelationships.contains(relationship)) { this.network.removeRelationship(relationship); this.allRelationships.remove(relationship); } return; } this.network.removeRelationship(existing); // Also remove from allRelationships if (this.allRelationships != null) { this.allRelationships.remove(existing); } if (relationships.isEmpty()) { getRelationships().remove(relationship.getType()); return; } // Fix indexes. for (Relationship each : relationships.values()) { if (each.getIndex() > relationship.getIndex()) { each.setIndex(each.getIndex() - 1); } } } /** * Remove the relationship. */ public synchronized void internalRemoveRelationship(Primitive type, Primitive target) { Relationship relationship = getRelationship(type, target); if (relationship != null) { internalRemoveRelationship(relationship); } } /** * Remove the relationship. */ public synchronized void internalRemoveRelationship(Vertex type, Vertex target) { Relationship relationship = getRelationship(type, target); if (relationship != null) { internalRemoveRelationship(relationship); } } /** * Remove the relationships of the type. */ public synchronized void internalRemoveRelationships(Primitive type) { internalRemoveRelationships(this.network.createVertex(type)); } /** * Remove the relationships of the type. */ public synchronized void internalRemoveRelationships(Vertex type) { Map<Relationship, Relationship> relationships = getRelationships().get(type); if (relationships == null) { return; } for (Relationship relationship : relationships.values()) { this.network.removeRelationship(relationship); // Also remove from allRelationships if (this.allRelationships != null) { this.allRelationships.remove(relationship); } } getRelationships().remove(type); } /** * Pin the targets of all relationships to memory. */ public synchronized void pinChildren() { for (Iterator<Relationship> iterator = allRelationships(); iterator.hasNext(); ) { iterator.next().getTarget().setPinned(true); } } /** * Unpin the targets of all relationships from memory. */ public synchronized void unpinChildren() { for (Iterator<Relationship> iterator = allRelationships(); iterator.hasNext(); ) { iterator.next().getTarget().setPinned(false); } } /** * Remove all relationships. */ public synchronized void internalRemoveAllRelationships() { for (Iterator<Relationship> iterator = allRelationships(); iterator.hasNext(); ) { this.network.removeRelationship(iterator.next()); } getRelationships().clear(); if (this.allRelationships != null) { this.allRelationships.clear(); } } /** * Replace the relationship with the new target at the same index. */ public synchronized void replaceRelationship(Relationship oldRelationship, Vertex newTarget) { Map<Relationship, Relationship> relationships = getRelationships().get(oldRelationship.getType()); if (relationships == null) { return; } Relationship existing = relationships.remove(oldRelationship); if (existing == null) { return; } // Also remove from allRelationships if (this.allRelationships != null) { this.allRelationships.remove(existing); } addRelationship(oldRelationship.getType(), newTarget, oldRelationship.getIndex()); } /** * Set the relationship, removing the old value. */ public synchronized void setRelationship(Primitive type, Vertex newValue) { setRelationship(this.network.createVertex(type), newValue); } /** * Set the relationship, removing the old value. */ public synchronized void setRelationship(Primitive type, Primitive newValue) { setRelationship(this.network.createVertex(type), this.network.createVertex(newValue)); } /** * Set the relationship, removing the old value. */ public synchronized void setRelationship(Vertex type, Vertex newValue) { Map<Relationship, Relationship> relationships = getRelationships().get(type); if (relationships != null) { for (Iterator<Relationship> iterator = relationships.values().iterator(); iterator.hasNext(); ) { Relationship existingValue = iterator.next(); iterator.remove(); if (this.allRelationships != null) { this.allRelationships.remove(existingValue); } this.network.removeRelationship(existingValue); } } addRelationship(type, newValue); } protected void setRelationships(Map<Vertex, Map<Relationship, Relationship>> relationships) { this.relationships = relationships; } /** * Provides an easier method of traversing all the relations of all types of a vertex. */ public synchronized Iterator<Relationship> allRelationships() { return new RelationshipIterator(false); } /** * Iterator over all related vertices to the vertex. */ public void iterate(VertexIterator iterator) { if ((iterator.getDepth() == 0) && (iterator.getPath() == Path.BreadthFirst)) { Map<Vertex, Vertex> currentLevel = new IdentityHashMap<Vertex, Vertex>(); iterator.setBreadthSet(currentLevel); iterator.incrementDepth(); iterate(iterator); iterator.decrementDepth(); Map<Vertex, Vertex> nextLevel = currentLevel; while (!nextLevel.isEmpty()) { iterator.incrementDepth(); if (iterator.isMaxDepth()) { return; } currentLevel = nextLevel; nextLevel = new IdentityHashMap<Vertex, Vertex>(); iterator.setBreadthSet(nextLevel); for (Vertex vertex : currentLevel.values()) { vertex.iterate(iterator); if (iterator.isMaxIterations()) { return; } } } } else { if (iterator.getTraversed().containsKey(this)) { return; } if (iterator.isMaxIterations()) { return; } if (iterator.getIgnorePrimitives() && isPrimitive()) { return; } iterator.getTraversed().put(this, this); boolean iterateRelationships = iterator.iterate(this); if (!iterateRelationships) { return; } if (getRelationships().isEmpty()) { return; } if (iterator.getPath() == Path.BreadthFirst) { for (Map<Relationship, Relationship> relationships : getRelationships().values()) { for (Relationship relationship : relationships.values()) { iterator.addBreadth(relationship.getTarget()); } } } else { // Depth first if (iterator.isMaxDepth()) { return; } iterator.incrementDepth(); for (Map<Relationship, Relationship> relationships : getRelationships().values()) { for (Relationship relationship : relationships.values()) { relationship.getTarget().iterate(iterator); if (iterator.isMaxIterations()) { return; } } } iterator.decrementDepth(); } } } /** * Pin the vertex and all of its descendants into memory. * This can be used for important data such as language rules. */ public void pinDescendants() { iterate(new AbstractVertexIterator() { public boolean iterate(Vertex vertex) { if (vertex.isPinned() || (vertex.getCreationDate().getTime() > (System.currentTimeMillis() - 60000))) { network.getBot().log(vertex, "pinned", Level.FINEST); vertex.setPinned(true); return true; } else { return false; } } }); } /** * Unpin the vertex and all of its descendants from memory. * This can be used to release removed language rules. */ public void unpinDescendants() { final long creationTime = getCreationDate().getTime(); iterate(new AbstractVertexIterator() { public boolean iterate(Vertex vertex) { if (vertex.isPinned() && (vertex.getCreationDate().getTime() > (creationTime - 60000)) && (vertex.getCreationDate().getTime() < (creationTime + 60000))) { network.getBot().log(vertex, "unpinned", Level.FINEST); vertex.setPinned(false); return true; } else { return false; } } }); } /** * Provides an easier method of traversing all the relations of all types of a vertex. */ public synchronized Iterator<Relationship> orderedAllRelationships() { return new RelationshipIterator(true); } public String displayString() { StringWriter writer = new StringWriter(); writer.write(String.valueOf(this.id)); if (hasData()) { writer.write(" : "); if (isPrimitive()) { writer.write("#"); } if (this.data instanceof String) { writer.write("\""); } writer.write(getDataValue()); if (this.data instanceof String) { writer.write("\""); } } else { if (hasName()) { writer.write(" : {"); writer.write(getName()); writer.write("}"); } } return writer.toString(); } public static void writeHeader(Vertex vertex, PrintWriter writer) { writer.print("<"); writer.print(vertex.getId()); if (vertex.hasName()) { writer.print(" {"); writer.print(vertex.getName()); writer.print("}"); } if (vertex.hasData()) { writer.print(" "); if (vertex.isPrimitive()) { writer.print("#"); } writer.print(vertex.getDataValue()); } writer.print(" "); if (vertex.isDirty()) { writer.print("*,"); } writer.print("a:" + vertex.getAccessCount()); writer.print(",c:" + vertex.getConsciousnessLevel()); if (vertex.isPinned()) { writer.print(",p"); } writer.print(">"); } /** * Return if the vertex is a system primitive. */ public boolean isPrimitive() { return this.data instanceof Primitive; } /** * Return if the vertex is for a meta relationship. */ public boolean isMeta() { return hasRelationship(Primitive.INSTANTIATION, Primitive.META); } /** * Return if the vertex is a variable. */ public boolean isVariable() { return hasRelationship(Primitive.INSTANTIATION, Primitive.VARIABLE); } /** * Return if the vertex is a list. */ public boolean isList() { return hasRelationship(Primitive.INSTANTIATION, Primitive.LIST); } /** * Return if the vertex is an array. */ public boolean isArray() { return hasRelationship(Primitive.INSTANTIATION, Primitive.ARRAY); } /** * Return if the vertex is a equation. */ public boolean isEquation() { return hasRelationship(Primitive.INSTANTIATION, Primitive.EQUATION); } /** * Return if the vertex data is equal to the data. */ public synchronized boolean is(Object data) { return (data != null) && data.equals(this.data); } /** * Return if the vertex is an instantiation of the primitive type. */ public synchronized boolean instanceOf(Primitive type) { return instanceOf(this.network.createVertex(type)); } /** * Return if the vertex is an instantiation of the type. */ public synchronized boolean instanceOf(Vertex type) { return hasRelationship(this.network.createVertex(Primitive.INSTANTIATION), type); } /** * Return if the vertex has a relationship of the type primitive. */ public boolean hasRelationship(Primitive type) { return hasRelationship(this.network.createVertex(type)); } /** * Return if the vertex has a relationship of the type primitive to the target primitive. */ public boolean hasRelationship(Primitive type, Primitive target) { return hasRelationship(this.network.createVertex(type), this.network.createVertex(target)); } /** * Return if the vertex has a relationship of the type primitive to the target. */ public boolean hasRelationship(Primitive type, Vertex target) { return hasRelationship(this.network.createVertex(type), target); } /** * Return the relationship of the type primitive to the target. */ public Relationship getRelationship(Primitive type, Vertex target) { return getRelationship(this.network.createVertex(type), target); } /** * Return the relationship of the type primitive to the target. */ public Relationship getRelationship(Primitive type, Primitive target) { return getRelationship(this.network.createVertex(type), this.network.createVertex(target)); } /** * Return if the vertex has a relationship of the type to the target. */ public boolean hasRelationship(Vertex type, Vertex target) { Relationship relationship = getRelationship(type, target); return (relationship != null) && (!relationship.isInverse()); } /** * Return if the vertex has a relationship of the type to the target. */ public boolean hasOrInheritsRelationship(Vertex type, Vertex target) { return hasOrInheritsRelationship(type, target, null); } /** * Return if the vertex has a relationship of the type to the target. */ public synchronized boolean hasOrInheritsRelationship(Vertex type, Vertex target, Map<Vertex, Vertex> recursion) { Relationship relationship = getRelationship(type, target); if (relationship == null) { // Check for variables. if (target.isVariable()) { Collection<Relationship> relationships = getRelationships(type); if (relationships != null) { if (recursion == null) { recursion = new HashMap<Vertex, Vertex>(); } boolean inverse = true; for (Relationship each : relationships) { if (target.matches(each.getTarget(), recursion) == Boolean.TRUE) { if (!each.isInverse()) { return true; } else { inverse = true; } } } if (inverse) { return false; } } } // If no relationship, check its classifications. Collection<Relationship> classifications = null; if (instanceOf(Primitive.CLASSIFICATION)) { classifications = getRelationships(Primitive.SPECIALIZATION); } else { classifications = getRelationships(Primitive.INSTANTIATION); } if (classifications != null) { // Switch instantiation to specialization. if (type.isPrimitive() && type.getData().equals(Primitive.INSTANTIATION)) { type = this.network.createVertex(Primitive.SPECIALIZATION); } for (Relationship classification : classifications) { if (recursion == null) { recursion = new HashMap<Vertex, Vertex>(); } recursion.put(this, this); if (!recursion.containsKey(classification.getTarget()) && classification.getTarget().hasOrInheritsRelationship(type, target, recursion)) { return true; } } } } return (relationship != null) && (!relationship.isInverse()); } /** * Return the relationship of the type primitive to the target. */ public synchronized Relationship getRelationship(Vertex type, Vertex target) { Map<Relationship, Relationship> relationships = getRelationships().get(type); if (relationships == null) { return null; } return relationships.get(new BasicRelationship(this, type, target)); } /** * Return if the vertex has a relationship of the type to the target. * Include inverses. */ public synchronized boolean internalHasRelationship(Vertex type, Vertex target) { Map<Relationship, Relationship> relationships = getRelationships().get(type); if (relationships == null) { return false; } boolean b = relationships.containsKey(new BasicRelationship(this, type, target)); if (b) { return b; } return b; } /** * Return if the vertex has any (non-inverse) relationship of the type. */ public synchronized boolean hasRelationship(Vertex type) { Collection<Relationship> relationships = getRelationships(type); if (relationships == null) { return false; } for (Relationship relationship : relationships) { if (!relationship.isInverse()) { return true; } } return false; } /** * Return if the vertex has any relationship to any target. */ public synchronized boolean hasAnyRelationshipToTarget(Vertex target) { Iterator<Relationship> relationships = allRelationships(); while (relationships.hasNext()) { Relationship relationship = relationships.next(); if (!relationship.isInverse() && relationship.getTarget().equals(target)) { return true; } } return false; } /** * Return if the vertex has any relationship to any target that is an instantiation of the classification. */ public synchronized boolean hasAnyRelationshipToTargetOfType(Vertex classification) { Iterator<Relationship> relationships = allRelationships(); while (relationships.hasNext()) { Relationship relationship = relationships.next(); if (!relationship.isInverse() && relationship.getTarget().hasRelationship(Primitive.INSTANTIATION, classification)) { return true; } } return false; } /** * Return if the vertex has an inverse relationship of the type to the target. */ public boolean hasInverseRelationship(Primitive type, Primitive target) { return hasInverseRelationship(this.network.createVertex(type), this.network.createVertex(target)); } /** * Return if the vertex has an inverse relationship of the type to the target. */ public boolean hasInverseRelationship(Primitive type, Vertex target) { return hasInverseRelationship(this.network.createVertex(type), target); } /** * Return if the vertex has an inverse relationship of the type to the target. */ public synchronized boolean hasInverseRelationship(Vertex type, Vertex target) { Relationship relationship = getRelationship(type, target); return (relationship != null) && (relationship.isInverse()); } /** * Return if the vertex has a relationship of the type to the target. */ public boolean hasOrInheritsInverseRelationship(Vertex type, Vertex target) { return hasOrInheritsInverseRelationship(type, target, null); } /** * Return if the vertex has a relationship of the type to the target. */ public synchronized boolean hasOrInheritsInverseRelationship(Vertex type, Vertex target, Map<Vertex, Vertex> recursion) { Relationship relationship = getRelationship(type, target); if (relationship == null) { // Check for variables. if (target.isVariable()) { Collection<Relationship> relationships = getRelationships(type); if (relationships != null) { if (recursion == null) { recursion = new HashMap<Vertex, Vertex>(); } for (Relationship each : relationships) { if (target.matches(each.getTarget(), recursion) == Boolean.TRUE) { return each.isInverse(); } } } } // If no relationship, check its classifications. Collection<Relationship> classifications = null; if (instanceOf(Primitive.CLASSIFICATION)) { classifications = getRelationships(Primitive.SPECIALIZATION); } else { classifications = getRelationships(Primitive.INSTANTIATION); } if (classifications != null) { // Switch instantiation to specialization. if (type.isPrimitive() && type.getData().equals(Primitive.INSTANTIATION)) { type = this.network.createVertex(Primitive.SPECIALIZATION); } for (Relationship classification : classifications) { if (recursion == null) { recursion = new HashMap<Vertex, Vertex>(); } recursion.put(this, this); if (!recursion.containsKey(classification.getTarget()) && classification.getTarget().hasOrInheritsInverseRelationship(type, target, recursion)) { return true; } } } } return (relationship != null) && (relationship.isInverse()); } public String description() { StringWriter stringWriter = new StringWriter(); PrintWriter writer = new PrintWriter(stringWriter); writeHeader(this, writer); writer.println(); if (this.relationships != null) { for (Map.Entry<Vertex, Map<Relationship, Relationship>> entry : getRelationships().entrySet()) { Vertex type = (Vertex) entry.getKey(); Map<Relationship, Relationship> targets = entry.getValue(); writer.print("\t"); writeHeader(type, writer); writer.print(" -> "); boolean first = true; for (Relationship relationship : targets.values()) { if (first) { first = false; } else { writer.write(", "); } writer.print("(0."); writer.print((int)(relationship.getCorrectness() * 100)); writer.print(")"); writeHeader(relationship.getTarget(), writer); } writer.println(); } } writer.flush(); stringWriter.flush(); return stringWriter.toString(); } public String toString() { StringWriter stringWriter = new StringWriter(); PrintWriter writer = new PrintWriter(stringWriter); writeHeader(this, writer); writer.flush(); stringWriter.flush(); return stringWriter.toString(); } public String getDataType() { if (this.data == null) { return this.dataType; } return convertDataType(this.data); } public String getDataValue() { return convertDataValue(this.data); } @SuppressWarnings("unchecked") protected void setDataValue(String value) { if (value == null) { this.data = null; return; } if (this.dataType instanceof String) { try { if (this.dataType.equals("Primitive")) { this.data = new Primitive(value); } else if (this.dataType.equals("String")) { this.data = value; } else if (this.dataType.equals("Time")) { this.data = Utils.parseTime((String)value); } else if (this.dataType.equals("Date")) { this.data = Utils.parseDate((String)value); } else if (this.dataType.equals("Timestamp")) { this.data = Utils.parseTimestamp(value); } else if (this.dataType.equals("Image")) { this.data = new BinaryData((String)value); } else if (this.dataType.equals("Binary")) { this.data = new BinaryData((String)value); } else if (this.dataType.equals("Text")) { this.data = new TextData((String)value); } else if (this.dataType.equals("URI")) { this.data = new URI((String)value); } else { Class<Object> typeClass = (Class<Object>)Class.forName((String)this.dataType); this.data = typeClass.getConstructor(String.class).newInstance(value); if (this.data instanceof URL) { try { this.data = ((URL) (this.data)).toURI(); } catch (Exception invalid) { URL url = (URL) this.data; this.data = new URI(url.getProtocol(), url.getAuthority(), url.getPath(), url.getQuery(), url.getRef()); } } } } catch (Exception error) { if (this.network == null) { System.out.println("DataValue error:" + this.id + "-" + value); error.printStackTrace(); } else { this.network.getBot().log(this.id, "DataValue error", Bot.WARNING, value); this.network.getBot().log(this, error); } } } else { this.data = value; } } /** * Set the internal data-type of the vertex. */ public void setType(String type) { this.dataType = type; } @SuppressWarnings("unchecked") protected void setDataType(String type) { this.dataType = type; if (this.data instanceof String) { try { if (type.equals("Primitive")) { this.data = new Primitive((String)this.data); } else if (type.equals("String")) { //this.data = this.data; } else if (type.equals("Time")) { this.data = Utils.parseTime((String)this.data); } else if (type.equals("Date")) { this.data = Utils.parseDate((String)this.data); } else if (type.equals("Timestamp")) { this.data = Utils.parseTimestamp((String)this.data); } else if (type.equals("Image")) { this.data = new BinaryData((String)this.data); } else if (type.equals("Binary")) { this.data = new BinaryData((String)this.data); } else if (type.equals("Text")) { this.data = new TextData((String)this.data); } else if (type.equals("URI")) { this.data = new URI((String)this.data); } else { Class<Object> typeClass = (Class<Object>)Class.forName(type); this.data = typeClass.getConstructor(String.class).newInstance(this.data); } } catch (Exception error) { if (this.network == null) { error.printStackTrace(); } else { this.network.getBot().log(this, error); } } } } public static String convertDataValue(Object data) { if (data == null) { return null; } else if (data instanceof String) { return (String)data; } else if (data instanceof Primitive) { // TODO: prefix a # return ((Primitive) data).getIdentity(); } else if (data instanceof BinaryData) { return String.valueOf(((BinaryData)data).getId()); } else if (data instanceof TextData) { return String.valueOf(((TextData)data).getId()); } else { return data.toString(); } } public static String convertDataType(Object data) { if (data == null) { return null; } else if (data instanceof String) { return "String"; } else if (data instanceof Primitive) { return "Primitive"; } else if (data instanceof Time) { return "Time"; } else if (data instanceof Timestamp) { return "Timestamp"; } else if (data instanceof java.sql.Date) { return "Date"; } else if (data instanceof BinaryData) { return "Binary"; } else if (data instanceof TextData) { return "Text"; } else if (data instanceof URI) { return "URI"; } else { return data.getClass().getName(); } } /** * Create a copy of the vertex with all of the same relationships. * Since data is unique, this should only be used on vertices without data. */ public synchronized Vertex copy() { Vertex copy = this.network.createVertex(); for (Iterator<Relationship> iterator = allRelationships(); iterator.hasNext(); ) { Relationship relationship = iterator.next(); copy.addRelationship(relationship.getType(), relationship.getTarget()); } return copy; } /** * Create a copy of the vertex with only the id. */ public Vertex detach() { BasicVertex vertex = new BasicVertex(); vertex.setId(this.id); return vertex; } public synchronized Collection<Relationship> getAllRelationships() { // Should not be required, as allRelationships is maintained. /*if (this.relationships != null) { this.allRelationships = new ArrayList<Relationship>(); for (Iterator<Relationship> iterator = allRelationships(); iterator.hasNext(); ) { this.allRelationships.add(iterator.next()); } this.relationships = null; }*/ return this.allRelationships; } protected void setAllRelationships(Collection<Relationship> allRelationships) { this.allRelationships = allRelationships; this.relationships = null; } /** * Return the name of the vertex. * The name is used as a hint to refer to what the vertex represents. */ public String getName() { return name; } /** * Set the name of the vertex. * The name is used as a hint to refer to what the vertex represents. */ public void setName(String name) { if ((name != null) && (name.length() > AbstractNetwork.MAX_TEXT)) { name = name.substring(0, AbstractNetwork.MAX_TEXT); } this.name = name; } /** * Some vertices have no name, * this provides an easy test method. */ public boolean hasName() { return this.name != null; } /** * Return if the vertex is pinned to memory, and will not be forgotten. */ public boolean isPinned() { return pinned; } /** * Set if the vertex should be pinned to memory. * Pinned vertices will not be forgotten. */ public void setPinned(boolean pinned) { this.pinned = pinned; } /** * Print the object's data such as a sentence or paragraph. */ public String printString() { return printString(0); } /** * Print the object's data such as a sentence or paragraph. */ public String printString(int depth) { if (depth > 100) { return ""; } StringWriter writer = new StringWriter(); if (instanceOf(Primitive.PARAGRAPH) && this.data == null) { Collection<Vertex> sentences = orderedRelations(Primitive.SENTENCE); if (sentences != null) { boolean first = true; String last = ""; for (Vertex each : sentences) { if (last.length() > 0) { Character terminator = last.charAt(last.length() - 1); if (Character.isLetterOrDigit(terminator)) { writer.write("."); } } if (!first) { writer.write(" "); } last = each.printString(depth++); writer.write(last); first = false; } } } else if (instanceOf(Primitive.ARRAY)) { Collection<Vertex> elements = orderedRelations(Primitive.ELEMENT); writer.write("["); if (elements != null) { boolean first = true; for (Vertex each : elements) { if (!first) { writer.write(", "); } writer.write(each.printString(depth++)); first = false; } } writer.write("]"); } else if (instanceOf(Primitive.LIST)) { Collection<Vertex> elements = orderedRelations(Primitive.SEQUENCE); writer.write("("); if (elements != null) { boolean first = true; for (Vertex each : elements) { if (!first) { writer.write(", "); } writer.write(each.printString(depth++)); first = false; } } writer.write(")"); } else if (this.data != null) { writer.write(this.data.toString()); } else if (instanceOf(Primitive.FRAGMENT) || instanceOf(Primitive.SENTENCE)) { return Language.printFragment(this, this.network.createVertex(Primitive.NULL), this.network.createVertex(Primitive.NULL), network); } else if (getName() != null) { writer.write(getName()); } else { writer.write("{" + String.valueOf(getId()) + "}"); } return writer.toString(); } }