All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aima.core.logic.propositional.kb.data.Clause Maven / Gradle / Ivy

Go to download

AIMA-Java Core Algorithms from the book Artificial Intelligence a Modern Approach 3rd Ed.

The newest version!
package aima.core.logic.propositional.kb.data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import aima.core.logic.propositional.parsing.ast.PropositionSymbol;
import aima.core.util.SetOps;

/**
 * Artificial Intelligence A Modern Approach (3rd Edition): page 253.
*
* A Clause: A disjunction of literals. Here we view a Clause as a set of * literals. This respects the restriction, under resolution, that a resulting * clause should contain only 1 copy of a resulting literal. In addition, * clauses, as implemented, are immutable. * * * @author Ciaran O'Reilly * */ public class Clause { public static final Clause EMPTY = new Clause(); // private Set literals = new LinkedHashSet(); // private Set cachedPositiveSymbols = new LinkedHashSet(); private Set cachedNegativeSymbols = new LinkedHashSet(); private Set cachedSymbols = new LinkedHashSet(); // private Boolean cachedIsTautologyResult = null; private String cachedStringRep = null; private int cachedHashCode = -1; /** * Default constructor - i.e. the empty clause, which is 'False'. */ public Clause() { // i.e. the empty clause this(new ArrayList()); } /** * Construct a clause from the given literals. Note: literals the are always * 'False' (i.e. False or ~True) are not added to the instantiated clause. * * @param literals * the literals to be added to the clause. */ public Clause(Literal... literals) { this(Arrays.asList(literals)); } /** * Construct a clause from the given literals. Note: literals the are always * 'False' (i.e. False or ~True) are not added to the instantiated clause. * * @param literals */ public Clause(Collection literals) { for (Literal l : literals) { if (l.isAlwaysFalse()) { // Don't add literals of the form // False | ~True continue; } if (this.literals.add(l)) { // Only add to caches if not already added if (l.isPositiveLiteral()) { this.cachedPositiveSymbols.add(l.getAtomicSentence()); } else { this.cachedNegativeSymbols.add(l.getAtomicSentence()); } } } cachedSymbols.addAll(cachedPositiveSymbols); cachedSymbols.addAll(cachedNegativeSymbols); // Make immutable this.literals = Collections.unmodifiableSet(this.literals); cachedSymbols = Collections.unmodifiableSet(cachedSymbols); cachedPositiveSymbols = Collections .unmodifiableSet(cachedPositiveSymbols); cachedNegativeSymbols = Collections .unmodifiableSet(cachedNegativeSymbols); } /** * If a clause is empty - a disjunction of no disjuncts - it is equivalent * to 'False' because a disjunction is true only if at least one of its * disjuncts is true. * * @return true if an empty clause, false otherwise. */ public boolean isFalse() { return isEmpty(); } /** * * @return true if the clause is empty (i.e. 'False'), false otherwise. */ public boolean isEmpty() { return literals.size() == 0; } /** * Determine if a clause is unit, i.e. contains a single literal. * * @return true if the clause is unit, false otherwise. */ public boolean isUnitClause() { return literals.size() == 1; } /** * Determine if a definite clause. A definite clause is a disjunction of * literals of which exactly one is positive. For example, the * clause (¬L1,1 ∨ ¬Breeze ∨ B1,1) is a * definite clause, whereas (¬B1,1 ∨ P1,2 ∨ * P2,1) is not. * * * @return true if a definite clause, false otherwise. */ public boolean isDefiniteClause() { return cachedPositiveSymbols.size() == 1; } /** * Determine if an implication definite clause. An implication definite * clause is disjunction of literals of which exactly 1 is positive and * there is 1 or more negative literals. * * @return true if an implication definite clause, false otherwise. */ public boolean isImplicationDefiniteClause() { return isDefiniteClause() && cachedNegativeSymbols.size() >= 1; } /** * Determine if a Horn clause. A horn clause is a disjunction of literals of * which at most one is positive. * * @return true if a Horn clause, false otherwise. */ public boolean isHornClause() { return !isEmpty() && cachedPositiveSymbols.size() <= 1; } /** * Clauses with no positive literals are called goal clauses. * * @return true if a Goal clause, false otherwise. */ public boolean isGoalClause() { return !isEmpty() && cachedPositiveSymbols.size() == 0; } /** * Determine if the clause represents a tautology, of which the following * are examples:
* *
	 * {..., True, ...}
	 * {..., ~False, ...} 
	 * {..., P, ..., ~P, ...}
	 * 
* * @return true if the clause represents a tautology, false otherwise. */ public boolean isTautology() { if (cachedIsTautologyResult == null) { for (Literal l : literals) { if (l.isAlwaysTrue()) { // {..., True, ...} is a tautology. // {..., ~False, ...} is a tautology cachedIsTautologyResult = true; } } // If we still don't know if (cachedIsTautologyResult == null) { if (SetOps.intersection(cachedPositiveSymbols, cachedNegativeSymbols) .size() > 0) { // We have: // P | ~P // which is always true. cachedIsTautologyResult = true; } else { cachedIsTautologyResult = false; } } } return cachedIsTautologyResult; } /** * * @return the number of literals contained by the clause. */ public int getNumberLiterals() { return literals.size(); } /** * * @return the number of positive literals contained by the clause. */ public int getNumberPositiveLiterals() { return cachedPositiveSymbols.size(); } /** * * @return the number of negative literals contained by the clause. */ public int getNumberNegativeLiterals() { return cachedNegativeSymbols.size(); } /** * * @return the set of literals making up the clause. */ public Set getLiterals() { return literals; } /** * * @return the set of symbols from the clause's positive and negative literals. */ public Set getSymbols() { return cachedSymbols; } /** * * @return the set of symbols from the clause's positive literals. */ public Set getPositiveSymbols() { return cachedPositiveSymbols; } /** * * @return the set of symbols from the clause's negative literals. */ public Set getNegativeSymbols() { return cachedNegativeSymbols; } @Override public String toString() { if (cachedStringRep == null) { StringBuilder sb = new StringBuilder(); boolean first = true; sb.append("{"); for (Literal l : literals) { if (first) { first = false; } else { sb.append(", "); } sb.append(l); } sb.append("}"); cachedStringRep = sb.toString(); } return cachedStringRep; } @Override public boolean equals(Object othObj) { if (null == othObj) { return false; } if (this == othObj) { return true; } if (!(othObj instanceof Clause)) { return false; } Clause othClause = (Clause) othObj; return othClause.literals.equals(this.literals); } @Override public int hashCode() { if (cachedHashCode == -1) { cachedHashCode = literals.hashCode(); } return cachedHashCode; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy