001    /*
002     * Created on Dec 4, 2004
003     *
004     */
005    package aima.logic.propositional.visitors;
006    
007    import aima.logic.propositional.parsing.AbstractPLVisitor;
008    import aima.logic.propositional.parsing.ast.BinarySentence;
009    import aima.logic.propositional.parsing.ast.Sentence;
010    import aima.logic.propositional.parsing.ast.UnarySentence;
011    
012    /**
013     * @author Ravi Mohan
014     * 
015     */
016    public class CNFTransformer extends AbstractPLVisitor {
017            @Override
018            public Object visitBinarySentence(BinarySentence bs, Object arg) {
019                    if (bs.isBiconditional()) {
020                            return transformBiConditionalSentence(bs);
021                    } else if (bs.isImplication()) {
022                            return transformImpliedSentence(bs);
023                    } else if (bs.isOrSentence()
024                                    && (bs.firstTermIsAndSentence() || bs.secondTermIsAndSentence())) {
025                            return distributeOrOverAnd(bs);
026                    } else {
027                            return super.visitBinarySentence(bs, arg);
028                    }
029            }
030    
031            @Override
032            public Object visitNotSentence(UnarySentence us, Object arg) {
033                    return transformNotSentence(us);
034            }
035    
036            public Sentence transform(Sentence s) {
037                    Sentence toTransform = s;
038                    while (!(toTransform.equals(step(toTransform)))) {
039                            toTransform = step(toTransform);
040                    }
041    
042                    return toTransform;
043            }
044    
045            private Sentence step(Sentence s) {
046                    return (Sentence) s.accept(this, null);
047            }
048    
049            private Sentence transformBiConditionalSentence(BinarySentence bs) {
050                    Sentence first = new BinarySentence("=>", (Sentence) bs.getFirst()
051                                    .accept(this, null), (Sentence) bs.getSecond().accept(this,
052                                    null));
053                    Sentence second = new BinarySentence("=>", (Sentence) bs.getSecond()
054                                    .accept(this, null), (Sentence) bs.getFirst()
055                                    .accept(this, null));
056                    return new BinarySentence("AND", first, second);
057            }
058    
059            private Sentence transformImpliedSentence(BinarySentence bs) {
060                    Sentence first = new UnarySentence((Sentence) bs.getFirst().accept(
061                                    this, null));
062                    return new BinarySentence("OR", first, (Sentence) bs.getSecond()
063                                    .accept(this, null));
064            }
065    
066            private Sentence transformNotSentence(UnarySentence us) {
067                    if (us.getNegated() instanceof UnarySentence) {
068                            return (Sentence) ((UnarySentence) us.getNegated()).getNegated()
069                                            .accept(this, null);
070                    } else if (us.getNegated() instanceof BinarySentence) {
071                            BinarySentence bs = (BinarySentence) us.getNegated();
072                            if (bs.isAndSentence()) {
073                                    Sentence first = new UnarySentence((Sentence) bs.getFirst()
074                                                    .accept(this, null));
075                                    Sentence second = new UnarySentence((Sentence) bs.getSecond()
076                                                    .accept(this, null));
077                                    return new BinarySentence("OR", first, second);
078                            } else if (bs.isOrSentence()) {
079                                    Sentence first = new UnarySentence((Sentence) bs.getFirst()
080                                                    .accept(this, null));
081                                    Sentence second = new UnarySentence((Sentence) bs.getSecond()
082                                                    .accept(this, null));
083                                    return new BinarySentence("AND", first, second);
084                            } else {
085                                    return (Sentence) super.visitNotSentence(us, null);
086                            }
087                    } else {
088                            return (Sentence) super.visitNotSentence(us, null);
089                    }
090            }
091    
092            private Sentence distributeOrOverAnd(BinarySentence bs) {
093                    BinarySentence andTerm = bs.firstTermIsAndSentence() ? (BinarySentence) bs
094                                    .getFirst()
095                                    : (BinarySentence) bs.getSecond();
096                    Sentence otherterm = bs.firstTermIsAndSentence() ? bs.getSecond() : bs
097                                    .getFirst();
098                    // (alpha or (beta and gamma) = ((alpha or beta) and (alpha or gamma))
099                    Sentence alpha = (Sentence) otherterm.accept(this, null);
100                    Sentence beta = (Sentence) andTerm.getFirst().accept(this, null);
101                    Sentence gamma = (Sentence) andTerm.getSecond().accept(this, null);
102                    Sentence distributed = new BinarySentence("AND", new BinarySentence(
103                                    "OR", alpha, beta), new BinarySentence("OR", alpha, gamma));
104                    return distributed;
105            }
106    
107    }