Package org.drools.core.beliefsystem.defeasible

Source Code of org.drools.core.beliefsystem.defeasible.DefeasibleBeliefSet

package org.drools.core.beliefsystem.defeasible;

import org.drools.core.beliefsystem.BeliefSystem;
import org.drools.core.beliefsystem.jtms.JTMSBeliefSet;
import org.drools.core.beliefsystem.jtms.JTMSBeliefSetImpl.MODE;
import org.drools.core.common.EqualityKey;
import org.drools.core.common.InternalFactHandle;
import org.drools.core.common.LogicalDependency;
import org.drools.core.common.QueryElementFactHandle;
import org.drools.core.common.WorkingMemoryAction;
import org.drools.core.definitions.rule.impl.RuleImpl;
import org.drools.core.spi.PropagationContext;
import org.drools.core.util.Entry;
import org.drools.core.util.FastIterator;
import org.drools.core.util.LinkedListNode;
import org.kie.api.runtime.rule.FactHandle;

import java.util.Arrays;
import java.util.List;

public class DefeasibleBeliefSet<M extends DefeasibleMode<M>> implements JTMSBeliefSet<M> {
    private BeliefSystem beliefSystem;

    public static final String DEFEATS = Defeats.class.getSimpleName();

    private static final FastIterator iterator = new IteratorImpl();

    private InternalFactHandle rootHandle;
    private InternalFactHandle positiveFactHandle;
    private InternalFactHandle negativeFactHandle;

    private M                  rootUndefeated;
    private M                  tailUndefeated;

    private int definitelyPosCount;
    private int definitelyNegCount;
    private int defeasiblyPosCount;
    private int defeasiblyNegCount;
    private int defeatedlyPosCount;
    private int defeatedlyNegCount;

    private static final int DEFINITELY_POS_BIT = 1;
    private static final int DEFINITELY_NEG_BIT = 2;
    private static final int DEFEASIBLY_POS_BIT = 4;
    private static final int DEFEASIBLY_NEG_BIT = 8;
    private static final int DEFEATEDLY_POS_BIT = 16;
    private static final int DEFEATEDLY_NEG_BIT = 32;

    private static final int POS_MASK = DEFINITELY_POS_BIT | DEFEASIBLY_POS_BIT | DEFEATEDLY_POS_BIT;
    private static final int NEG_MASK = DEFINITELY_NEG_BIT | DEFEASIBLY_NEG_BIT | DEFEATEDLY_NEG_BIT;

    private static final int WEAK_POS_MASK = DEFEASIBLY_POS_BIT | DEFEATEDLY_POS_BIT;
    private static final int WEAK_NEG_MASK = DEFEASIBLY_NEG_BIT | DEFEATEDLY_NEG_BIT;

    private int statusMask = 0;

    private DefeasibilityStatus status;

    public DefeasibleBeliefSet(BeliefSystem<M> beliefSystem, InternalFactHandle rootHandle) {
        this.beliefSystem = beliefSystem;
        this.rootHandle = rootHandle;
    }

    public DefeasibleLogicalDependency getLogicalDependency() {
        return getLogicalDependency();
    }

    public BeliefSystem<M> getBeliefSystem() {
        return beliefSystem;
    }

    public InternalFactHandle getFactHandle() {
        return rootHandle;
    }

    public M getFirst() {
        return rootUndefeated;
    }

    public DefeasibleMode<M> getLast() {
        return tailUndefeated;
    }

    public InternalFactHandle getPositiveFactHandle() {
        return positiveFactHandle;
    }

    public void setPositiveFactHandle(InternalFactHandle positiveFactHandle) {
        this.positiveFactHandle = positiveFactHandle;
    }

    public InternalFactHandle getNegativeFactHandle() {
        return negativeFactHandle;
    }

    public void setNegativeFactHandle(InternalFactHandle negativeFactHandle) {
        this.negativeFactHandle = negativeFactHandle;
    }

    public void add( M node) {
        M newDep = node;
        newDep.setStatus( resolveStatus( newDep ) );

        RuleImpl rule = newDep.getLogicalDependency().getJustifier().getRule();

        // first iterate to see if this new dep is defeated. If it's defeated, it can no longer impacts any deps
        // if we checked what it defeats, and later this was defeated, we would have undo action. So we do the cheaper work first.
        boolean wasDefeated = false;
        for (DefeasibleMode<M> existingDep = rootUndefeated; existingDep != null; existingDep = existingDep.getNext()) {
            wasDefeated = checkIsDefeated( newDep, rule, existingDep );
            if (wasDefeated) {
                existingDep.addDefeated( newDep );
                break;
            }
        }

        if (!wasDefeated) {
            M stagedDeps = null;
            for ( M existingDep = rootUndefeated; existingDep != null;) {
                M next = existingDep.getNext();

                if ( checkIsDefeated( existingDep, existingDep.getLogicalDependency().getJustifier().getRule(), newDep ) ) {
                    // fist remove it from the undefeated list
                    removeUndefeated( existingDep );
                    newDep.addDefeated( existingDep );
                    if (existingDep.getRootDefeated() != null) {
                        // build up the list of staged deps, that will need to be reprocessed
                        if (stagedDeps == null) {
                            stagedDeps = existingDep.getRootDefeated();
                        } else {
                            stagedDeps.setPrevious( existingDep.getTailDefeated() );
                            stagedDeps = existingDep.getRootDefeated();
                        }
                    }
                    existingDep.clearDefeated();
                }
                existingDep = next;
            }
            addUndefeated(newDep);
            // now process the staged
            reprocessDefeated(stagedDeps);
        }
        updateStatus();
    }

    private void reprocessDefeated( M deps ) {
        for ( M dep = deps; dep != null; ) {
            M next = dep.getNext();
            dep.nullPrevNext(); // it needs to be removed, before it can be processed
            add( dep ); // adding back in, effectively reprocesses the dep
            dep = next;
        }
    }

    public void remove( M node) {
        DefeasibleMode<M> dep = node;

        if (dep.getDefeatedBy() != null) {
            // Defeated deps do not have defeated defeated lists of their own, so just remove.
            DefeasibleMode<M> defeater = dep.getDefeatedBy();
            defeater.removeDefeated(dep);
        } else {
            // ins undefeated, process it's defeated list if they exist
            removeUndefeated(dep);
            if (dep.getRootDefeated() != null) {
                reprocessDefeated( dep.getRootDefeated() );
            }
        }
        updateStatus();
    }

    private boolean checkIsDefeated( DefeasibleMode potentialInferior, RuleImpl rule, DefeasibleMode potentialSuperior ) {
        if ( potentialSuperior.getDefeats() == null ) {
            return false;
        }
        if ( potentialSuperior.getStatus() == DefeasibilityStatus.DEFINITELY && potentialInferior.getStatus() != DefeasibilityStatus.DEFINITELY ) {
            return true;
        }
        // adds the references that defeat the current node
        if (Arrays.binarySearch(potentialSuperior.getDefeats(), rule.getName()) >= 0 ||
            Arrays.binarySearch(potentialSuperior.getDefeats(), rule.getPackage() + "." + rule.getName()) >= 0) {
            if ( "neg".equals( potentialSuperior.getValue() ) ^ "neg".equals( potentialInferior.getValue() ) ) {
                return true;
            }
        }
        return false;
    }

    public void addUndefeated( M dep ) {
        boolean pos = ! ( dep.getValue() != null && MODE.NEGATIVE.getId().equals( dep.getValue().toString() ) );
        switch( dep.getStatus() ) {
            case DEFINITELY:
                if ( pos ) {
                    definitelyPosCount++;
                    statusMask = statusMask | DEFINITELY_POS_BIT;
                } else {
                    definitelyNegCount++;
                    statusMask = statusMask | DEFINITELY_NEG_BIT;
                }
                break;
            case DEFEASIBLY:
                if ( pos ) {
                    defeasiblyPosCount++;
                    statusMask = statusMask | DEFEASIBLY_POS_BIT;
                } else {
                    defeasiblyNegCount++;
                    statusMask = statusMask | DEFEASIBLY_NEG_BIT;
                }
                break;
            case DEFEATEDLY:
                if ( pos ) {
                    defeatedlyPosCount++;
                    statusMask = statusMask | DEFEATEDLY_POS_BIT;
                } else {
                    defeatedlyNegCount++;
                    statusMask = statusMask | DEFEATEDLY_NEG_BIT;
                }
                break;
            case UNDECIDABLY:
                throw new IllegalStateException("Individual logical dependencies cannot be undecidably");
        }

        if (rootUndefeated == null) {
            rootUndefeated = dep;
            tailUndefeated = dep;
        } else {
            if ( dep.getStatus() == DefeasibilityStatus.DEFINITELY ) {
                // Strict dependencies at to the front
                rootUndefeated.setPrevious(dep);
                dep.setNext(rootUndefeated);
                rootUndefeated = dep;
            } else {
                // add to end
                tailUndefeated.setNext(dep);
                dep.setPrevious(tailUndefeated);
                tailUndefeated = dep;
            }
        }
    }

    public void removeUndefeated(DefeasibleMode dep) {
        boolean pos = ! ( dep.getValue() != null && MODE.NEGATIVE.getId().equals( dep.getValue().toString() ) );
        switch( dep.getStatus() ) {
            case DEFINITELY:
                if ( pos ) {
                    definitelyPosCount--;
                    if ( definitelyPosCount == 0 ) {
                        statusMask = statusMask ^ DEFINITELY_POS_BIT;
                    }
                } else {
                    definitelyNegCount--;
                    if ( definitelyNegCount == 0 ) {
                        statusMask = statusMask ^ DEFINITELY_NEG_BIT;
                    }
                }
                break;
            case DEFEASIBLY:
                if ( pos ) {
                    defeasiblyPosCount--;
                    if ( defeasiblyPosCount == 0 ) {
                        statusMask = statusMask ^ DEFEASIBLY_POS_BIT;
                    }
                } else {
                    defeasiblyNegCount--;
                    if ( defeasiblyNegCount == 0 ) {
                        statusMask = statusMask ^ DEFEASIBLY_NEG_BIT;
                    }
                }
                break;
            case DEFEATEDLY:
                if ( pos ) {
                    defeatedlyPosCount--;
                    if ( defeatedlyPosCount == 0 ) {
                        statusMask = statusMask ^ DEFEATEDLY_POS_BIT;
                    }
                } else {
                    defeatedlyNegCount--;
                    if ( defeatedlyNegCount == 0 ) {
                        statusMask = statusMask ^ DEFEATEDLY_NEG_BIT;
                    }
                }
                break;
            case UNDECIDABLY:
                throw new IllegalStateException("Individual logical dependencies cannot be undecidably");
        }

        if (this.rootUndefeated == dep) {
            removeFirst();
        } else if (this.tailUndefeated == dep) {
            removeLast();
        } else {
            dep.getPrevious().setNext(dep.getNext());
            ((DefeasibleMode)dep.getNext()).setPrevious(dep.getPrevious());
            dep.nullPrevNext();
        }
    }

    public M removeFirst() {
        if (this.rootUndefeated == null) {
            return null;
        }
        final M dep = this.rootUndefeated;
        this.rootUndefeated = dep.getNext();
        dep.setNext(null);
        if (this.rootUndefeated != null) {
            this.rootUndefeated.setPrevious(null);
        } else {
            this.tailUndefeated = null;
        }
        return dep;
    }

    public M removeLast() {
        if (this.tailUndefeated == null) {
            return null;
        }
        final M dep = this.tailUndefeated;
        this.tailUndefeated = dep.getPrevious();
        dep.setPrevious(null);
        if (this.tailUndefeated != null) {
            this.tailUndefeated.setNext(null);
        } else {
            this.rootUndefeated = this.tailUndefeated;
        }
        return dep;
    }

    public LinkedListNode getRootUndefeated() {
        return this.rootUndefeated;
    }

    public LinkedListNode getTailUnDefeated() {
        return this.tailUndefeated;
    }

    public boolean isEmpty() {
        return rootUndefeated == null;
    }

    public int size() {
        return definitelyPosCount + definitelyNegCount + defeasiblyPosCount + defeasiblyNegCount + defeatedlyPosCount + defeatedlyNegCount;
    }

    public int undefeatdSize() {
        int i = 0;
        for (DefeasibleMode existingNode = rootUndefeated; existingNode != null; existingNode = (DefeasibleMode) existingNode.getNext()) {
            i++;
        }
        return i;
    }

    public void cancel(PropagationContext propagationContext) {
        // get all but last, as that we'll do via the BeliefSystem, for cleanup
        // note we don't update negative, conflict counters. It's needed for the last cleanup operation
        FastIterator it = iterator();
        for ( M node =  getFirst(); node != tailUndefeated;  ) {
            M temp = (M) it.next(node); // get next, as we are about to remove it

            LogicalDependency<M> dep = node.getLogicalDependency();

            dep.getJustifier().getLogicalDependencies().remove( dep );
            remove( node );
            node = temp;
        }

        DefeasibleMode<M> node = getFirst();
        LogicalDependency<M> dep = node.getLogicalDependency();
        dep.getJustifier().getLogicalDependencies().remove( dep );
        //beliefSystem.delete( node, this, context );
        positiveFactHandle = null;
        negativeFactHandle = null;
    }

    public void clear(PropagationContext propagationContext) {
    }

    public void setWorkingMemoryAction(WorkingMemoryAction wmAction) {
    }

    public boolean isDefinitelyPosProveable() {
        return  (statusMask &  DEFINITELY_POS_BIT) != 0;
    }

    public boolean isDefinitelyNegProveable() {
        return  (statusMask &  DEFINITELY_NEG_BIT) != 0;
    }

    public boolean isDefeasiblyPosProveable() {
        return  (statusMask &  DEFEASIBLY_POS_BIT) != 0;
    }

    public boolean isDefeasiblyNegProveable() {
        return  (statusMask &  DEFEASIBLY_NEG_BIT) != 0;
    }

    public boolean isDefeatedlyPosProveable() {
        return  (statusMask &  DEFEATEDLY_POS_BIT) != 0;
    }

    public boolean isDefeatedlyNegProveable() {
        return  (statusMask &  DEFEATEDLY_NEG_BIT) != 0;
    }
    public DefeasibilityStatus getStatus() {
        return status;
    }

    public void updateStatus() {
        if ( isDefinitelyPosProveable() ^ isDefinitelyNegProveable() ) {
            status = DefeasibilityStatus.DEFINITELY;
            return;
        }

        if ( isConflicting() ) {
            status = DefeasibilityStatus.UNDECIDABLY;
            return;
        }

        if ( isDefeasiblyPosProveable() ^ isDefeasiblyNegProveable() ) {
            status = DefeasibilityStatus.DEFEASIBLY;
            return;
        }

        if ( isDefeatedlyPosProveable() ^ isDefeatedlyNegProveable() ) {
            status = DefeasibilityStatus.DEFEATEDLY;
            return;
        }

        status = DefeasibilityStatus.UNDECIDABLY;
    }

//    public boolean isHeld() {
//        //isUndecided() ||  isDefinitelyPosProveable() ||isDefinitelyNegProveable()
//    }

    public boolean isNegated() {
        return ((statusMask & POS_MASK ) == 0 ) &&  ((statusMask & NEG_MASK ) != 0 );
    }

    public boolean isPositive() {
        return ((statusMask & POS_MASK ) != 0 ) &&  ((statusMask & NEG_MASK ) == 0 );
    }

    public boolean isConflicting() {
        return ((statusMask & POS_MASK ) != 0 ) &&  ((statusMask & NEG_MASK ) != 0 );
    }

    public boolean isUndecided() {
        return getStatus() == DefeasibilityStatus.UNDECIDABLY || getStatus() == DefeasibilityStatus.DEFEATEDLY;
    }

    public FastIterator iterator() {
        return iterator;
    }

    private static class IteratorImpl implements FastIterator {

        public Entry next(Entry object) {
            DefeasibleMode dep = (DefeasibleMode) object;
            if ( dep.getRootDefeated() != null ) {
                // try going down the list of defeated first
                return dep.getRootDefeated();
            }

            if ( dep.getNext() != null ) {
                return dep.getNext();
            }

            if ( dep.getDefeatedBy() != null ) {
                // go back up to the parent undefeated, and try the next undefeated
                return dep.getDefeatedBy().getNext();
            }

            return null; // nothing more to iterate too.

        }

        public boolean isFullIterator() {
            return true;
        }
    }

    private DefeasibilityStatus resolveStatus( DefeasibleMode node ) {
        List<? extends FactHandle> premise = node.getLogicalDependency().getJustifier().getFactHandles();

        DefeasibilityStatus status = DefeasibilityStatus.resolve( node.getValue() );

        if ( status == null ) {
            DefeasibleRuleNature defeasibleType = DefeasibleRuleNature.STRICT;
            if ( node.getLogicalDependency().getJustifier().getRule().getMetaData().containsKey( DefeasibleRuleNature.DEFEASIBLE.getLabel() ) ) {
                defeasibleType = DefeasibleRuleNature.DEFEASIBLE;
            } else if ( node.getLogicalDependency().getJustifier().getRule().getMetaData().containsKey( DefeasibleRuleNature.DEFEATER.getLabel() ) ) {
                defeasibleType = DefeasibleRuleNature.DEFEATER;
            }

            switch ( defeasibleType ) {
                case DEFEASIBLE :
                    status = checkDefeasible(premise);
                    break;
                case DEFEATER   :
                    status = checkDefeater(premise);
                    break;
                case STRICT     :
                default         :
                    status = checkStrict(premise );
                    break;
            }
        }
        return status;
    }

    private DefeasibilityStatus checkDefeasibleList<? extends FactHandle> premise ) {
        return DefeasibilityStatus.DEFEASIBLY;
    }

    private DefeasibilityStatus checkDefeaterList<? extends FactHandle> premise ) {
        return DefeasibilityStatus.DEFEATEDLY;
    }

    private DefeasibilityStatus checkStrictList<? extends FactHandle> premise ) {
        // The rule is strict. To prove that the derivation is strict we have to check that all the premises are
        // either facts or strictly proved facts
        for ( FactHandle h : premise ) {
            if ( h instanceof QueryElementFactHandle ) {
                return DefeasibilityStatus.DEFINITELY;
            }
            EqualityKey key = ((InternalFactHandle) h).getEqualityKey();
            if ( key != null && key.getStatus() == EqualityKey.JUSTIFIED ) {
                //DefeasibleBeliefSet bs = (DefeasibleBeliefSet) getTruthMaintenanceSystem().getJustifiedMap().get(((DefaultFactHandle) h).getId());

                DefeasibleBeliefSet bs = (DefeasibleBeliefSet) key.getBeliefSet();


                if ( bs.getStatus() != DefeasibilityStatus.DEFINITELY ) {
                    // to make a fact "definitely provable", all the supporting non-factual premises must be definitely provable.
                    return DefeasibilityStatus.DEFEASIBLY;
                }
            }
            // else it's a fact, so it's a good candidate for definite entailment
        }
        return DefeasibilityStatus.DEFINITELY;
    }


}
TOP

Related Classes of org.drools.core.beliefsystem.defeasible.DefeasibleBeliefSet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.