package org.drools.chance.reteoo.nodes; import org.drools.base.DroolsQuery; import org.drools.chance.common.ChanceStrategyFactory; import org.drools.chance.degree.Degree; import org.drools.chance.degree.simple.SimpleDegree; import org.drools.chance.evaluation.CompositeEvaluation; import org.drools.chance.evaluation.Evaluation; import org.drools.chance.evaluation.MockEvaluation; import org.drools.chance.evaluation.SimpleEvaluationImpl; import org.drools.chance.reteoo.ChanceFactHandle; import org.drools.chance.reteoo.tuples.ImperfectFromNodeLeftTuple; import org.drools.chance.reteoo.tuples.ImperfectRightTuple; import org.drools.chance.reteoo.tuples.ImperfectTuple; import org.drools.chance.rule.constraint.ImperfectAlphaConstraint; import org.drools.chance.rule.constraint.ImperfectBetaConstraint; import org.drools.chance.rule.constraint.ImperfectConstraint; import org.drools.chance.rule.constraint.OperatorConstraint; import org.drools.chance.rule.constraint.core.connectives.ConnectiveCore; import org.drools.common.BaseNode; import org.drools.common.BetaConstraints; import org.drools.common.InternalFactHandle; import org.drools.common.InternalWorkingMemory; import org.drools.core.util.Iterator; import org.drools.core.util.LinkedList; import org.drools.core.util.LinkedListEntry; import org.drools.reteoo.*; import org.drools.reteoo.builder.BuildContext; import org.drools.rule.From; import org.drools.spi.AlphaNodeFieldConstraint; import org.drools.spi.BetaNodeFieldConstraint; import org.drools.spi.DataProvider; import org.drools.spi.PropagationContext; import java.util.LinkedHashMap; import java.util.Map; import java.util.Stack; public class ChanceFromNode extends FromNode { private ConnectiveCore and; public ChanceFromNode( int id, DataProvider dataProvider, LeftTupleSource tupleSource, AlphaNodeFieldConstraint[] alphaNodeFieldConstraints, BetaConstraints betaConstraints, boolean tupleMemoryEnabled, BuildContext context, From from) { super( id, dataProvider, tupleSource, alphaNodeFieldConstraints, betaConstraints, tupleMemoryEnabled, context, from ); //TODO FIXME consume config! and = ChanceStrategyFactory.getConnectiveFactory( null,null ).getAnd(); } @Override public LeftTuple createLeftTuple(InternalFactHandle factHandle, LeftTupleSink sink, boolean leftTupleMemoryEnabled) { ImperfectTuple tup = new ImperfectFromNodeLeftTuple(factHandle, sink, leftTupleMemoryEnabled); int src = ((LeftInputAdapterNode) this.getLeftTupleSource()).getParentObjectSource().getId(); tup.addEvaluation( ((ChanceFactHandle) factHandle).getCachedEvaluation( src ) ); return (LeftTuple) tup; } @Override public LeftTuple createLeftTuple(LeftTuple leftTuple, LeftTupleSink sink, boolean leftTupleMemoryEnabled) { ImperfectTuple tup = new ImperfectFromNodeLeftTuple(leftTuple, sink, leftTupleMemoryEnabled); tup.addEvaluation( ((ImperfectTuple) leftTuple).getEvaluation() ); return (LeftTuple) tup; } @Override public LeftTuple createLeftTuple(LeftTuple leftTuple, RightTuple rightTuple, LeftTupleSink sink) { ImperfectTuple tup = new ImperfectFromNodeLeftTuple(leftTuple, rightTuple, sink); tup.addEvaluation( ((ImperfectTuple) leftTuple).getEvaluation() ); tup.addEvaluation( ((ImperfectTuple) rightTuple).getEvaluation() ); return (LeftTuple) tup; } @Override public LeftTuple createLeftTuple(LeftTuple leftTuple, RightTuple rightTuple, LeftTuple currentLeftChild, LeftTuple currentRightChild, LeftTupleSink sink, boolean leftTupleMemoryEnabled) { ImperfectTuple tup = new ImperfectFromNodeLeftTuple(leftTuple, rightTuple, currentLeftChild, currentRightChild, sink, leftTupleMemoryEnabled); tup.addEvaluation( ((ImperfectTuple) leftTuple).getEvaluation() ); tup.addEvaluation( ((ImperfectTuple) rightTuple).getEvaluation() ); return (LeftTuple) tup; } protected RightTuple newRightTuple(InternalFactHandle handle, Object o) { return new ImperfectRightTuple( handle, null ); } @Override public void modifyLeftTuple(LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) { super.modifyLeftTuple(leftTuple, context, workingMemory); } protected void checkConstraintsAndPropagate( final LeftTuple leftTuple, final RightTuple rightTuple, final PropagationContext context, final InternalWorkingMemory workingMemory, final FromMemory memory, final boolean useLeftMemory ) { Stack<Evaluation> results = new Stack<Evaluation>(); results.push( new SimpleEvaluationImpl( this.id, SimpleDegree.TRUE ) ); // emulate OTN //<Evaluation[ this.alphaConstraints.length + this.betaConstraints.getConstraints().size() ]; int ccounter = 0; boolean canPropagate = true; if ( this.alphaConstraints != null ) { // First alpha node filters for ( int i = 0, length = this.alphaConstraints.length; i < length; i++ ) { AlphaNodeFieldConstraint constraint = this.alphaConstraints[i]; ChanceFactHandle factHandle = (ChanceFactHandle) rightTuple.getFactHandle(); if ( constraint instanceof ImperfectConstraint) { Degree degree; if ( constraint instanceof OperatorConstraint ) { OperatorConstraint opc = (OperatorConstraint) constraint; int n = opc.getArity(); Evaluation[] args = new Evaluation[ n ]; for ( int j = 0; j < n; j++ ) { if ( results.isEmpty() ) { args[j] = new MockEvaluation( id, SimpleDegree.TRUE ); } else { args[j] = results.pop(); } } degree = opc.getConnective().eval( args ); results.push( new CompositeEvaluation( getId(), degree, opc.getConnective(), args ) ); } else { ImperfectAlphaConstraint alpha = (ImperfectAlphaConstraint) constraint; degree = alpha.match( (InternalFactHandle) factHandle, workingMemory, memory.alphaContexts[i] ); results.push( new SimpleEvaluationImpl( getId(), constraint.toString(), degree, alpha.getLabel() ) ); } canPropagate = canPropagate && degree.toBoolean(); } else { boolean allowed = constraint.isAllowed( (InternalFactHandle) factHandle, workingMemory, memory.alphaContexts[i] ); results.push( new SimpleEvaluationImpl( getId(), constraint.toString(), SimpleDegree.fromBooleanLiteral(allowed) ) ); canPropagate = canPropagate && allowed; } ccounter++; } } BetaNodeFieldConstraint[] constraintList = this.betaConstraints.getConstraints(); for ( int j = 0; j < constraintList.length; j++ ) { Degree degree; BetaNodeFieldConstraint con = constraintList[j]; if ( con instanceof ImperfectBetaConstraint) { if ( con instanceof OperatorConstraint ) { OperatorConstraint opc = (OperatorConstraint) con; int n = opc.getArity(); Evaluation[] args = new Evaluation[ n ]; for ( int k = 0; k < n; k++ ) { args[k] = results.pop(); } results.push( new CompositeEvaluation( getId(), opc.getConnective().eval( args ), opc.getConnective(), args ) ); } else { ImperfectBetaConstraint ibc = (ImperfectBetaConstraint) con; degree = ibc.matchCachedLeft( memory.betaMemory.getContext()[j], rightTuple.getFactHandle() ); results.push( new SimpleEvaluationImpl( ibc.getNodeId(), con.toString(), degree, ibc.getLabel() ) ); canPropagate = canPropagate && degree.toBoolean(); } } else { boolean allowed = ((BetaNodeFieldConstraint) con).isAllowedCachedRight( leftTuple, memory.betaMemory.getContext()[j] ); if ( ! allowed ) { canPropagate = false; } } j++; ccounter++; } //TODO FIXME Support inner operators if ( results.size() > 0 ) { Evaluation[] args = results.toArray( new Evaluation[ results.size() ] ); Evaluation composite = new CompositeEvaluation( this.getId(), and.eval( args ), and, args ); ((ImperfectRightTuple) rightTuple).addEvaluation( composite ); } else { ((ImperfectRightTuple) rightTuple).addEvaluation( new SimpleEvaluationImpl( this.id, SimpleDegree.TRUE ) ); } if ( canPropagate ) { if ( rightTuple.firstChild == null ) { // this is a new match, so propagate as assert this.sink.propagateAssertLeftTuple( leftTuple, rightTuple, null, null, context, workingMemory, useLeftMemory ); } else { // this is an existing match, so propagate as a modify this.sink.propagateModifyChildLeftTuple( rightTuple.firstChild, leftTuple, context, workingMemory, useLeftMemory ); } } else { retractMatch( leftTuple, rightTuple, context, workingMemory ); } } }