001    package aima.logic.fol.kb.data;
002    
003    import java.util.ArrayList;
004    import java.util.Collections;
005    import java.util.List;
006    import java.util.Set;
007    
008    import aima.logic.fol.inference.proof.ProofStep;
009    import aima.logic.fol.inference.proof.ProofStepChainContrapositive;
010    import aima.logic.fol.inference.proof.ProofStepPremise;
011    
012    /**
013     * @see http://logic.stanford.edu/classes/cs157/2008/lectures/lecture13.pdf
014     * 
015     * A Chain is a sequence of literals (while a clause is a set) - order is important for a chain.
016     */
017    
018    /**
019     * @author Ciaran O'Reilly
020     * 
021     */
022    public class Chain {
023            private static List<Literal> _emptyLiteralsList = Collections
024                            .unmodifiableList(new ArrayList<Literal>());
025            //
026            private List<Literal> literals = new ArrayList<Literal>();
027            private ProofStep proofStep = null;
028    
029            public Chain() {
030                    // i.e. the empty chain
031            }
032    
033            public Chain(List<Literal> literals) {
034                    this.literals.addAll(literals);
035            }
036    
037            public Chain(Set<Literal> literals) {
038                    this.literals.addAll(literals);
039            }
040    
041            public ProofStep getProofStep() {
042                    if (null == proofStep) {
043                            // Assume was a premise
044                            proofStep = new ProofStepPremise(this);
045                    }
046                    return proofStep;
047            }
048    
049            public void setProofStep(ProofStep proofStep) {
050                    this.proofStep = proofStep;
051            }
052    
053            public boolean isEmpty() {
054                    return literals.size() == 0;
055            }
056    
057            public void addLiteral(Literal literal) {
058                    literals.add(literal);
059            }
060    
061            public Literal getHead() {
062                    if (0 == literals.size()) {
063                            return null;
064                    }
065                    return literals.get(0);
066            }
067    
068            public List<Literal> getTail() {
069                    if (0 == literals.size()) {
070                            return _emptyLiteralsList;
071                    }
072                    return Collections.unmodifiableList(literals
073                                    .subList(1, literals.size()));
074            }
075    
076            public int getNumberLiterals() {
077                    return literals.size();
078            }
079    
080            public List<Literal> getLiterals() {
081                    return Collections.unmodifiableList(literals);
082            }
083    
084            /**
085             * A contrapositive of a chain is a permutation in which a different literal
086             * is placed at the front. The contrapositives of a chain are logically
087             * equivalent to the original chain.
088             * 
089             * @return a list of contrapositives for this chain.
090             */
091            public List<Chain> getContrapositives() {
092                    List<Chain> contrapositives = new ArrayList<Chain>();
093                    List<Literal> lits = new ArrayList<Literal>();
094    
095                    for (int i = 1; i < literals.size(); i++) {
096                            lits.clear();
097                            lits.add(literals.get(i));
098                            lits.addAll(literals.subList(0, i));
099                            lits.addAll(literals.subList(i + 1, literals.size()));
100                            Chain cont = new Chain(lits);
101                            cont.setProofStep(new ProofStepChainContrapositive(cont, this));
102                            contrapositives.add(cont);
103                    }
104    
105                    return contrapositives;
106            }
107    
108            public String toString() {
109                    StringBuilder sb = new StringBuilder();
110                    sb.append("<");
111    
112                    for (int i = 0; i < literals.size(); i++) {
113                            if (i > 0) {
114                                    sb.append(",");
115                            }
116                            sb.append(literals.get(i).toString());
117                    }
118    
119                    sb.append(">");
120    
121                    return sb.toString();
122            }
123    }