package org.drools.chance.reteoo.nodes;
import org.drools.chance.degree.simple.SimpleDegree;
import org.drools.chance.evaluation.MockEvaluation;
import org.drools.chance.reteoo.tuples.ImperfectRuleTerminalNodeLeftTuple;
import org.drools.chance.rule.constraint.core.connectives.ConnectiveCore;
import org.drools.chance.degree.Degree;
import org.drools.chance.evaluation.CompositeEvaluation;
import org.drools.chance.evaluation.Evaluation;
import org.drools.chance.reteoo.ChanceFactHandle;
import org.drools.chance.reteoo.tuples.ImperfectLeftTuple;
import org.drools.chance.reteoo.tuples.ImperfectTuple;
import org.drools.common.*;
import org.drools.reteoo.*;
import org.drools.reteoo.builder.BuildContext;
import org.drools.spi.PropagationContext;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Arrays;
public class LogicalBetaOperatorNode extends LeftTupleSource
implements
LeftTupleSinkNode {
private ConnectiveCore connective;
private int arity;
private int[] argIndexes;
private String label;
/** The left input <code>TupleSource</code>. */
protected LeftTupleSource leftInput;
private LeftTupleSinkNode previousLeftTupleSinkNode;
private LeftTupleSinkNode nextLeftTupleSinkNode;
private boolean tupleMemoryEnabled;
private boolean fromLIA;
public LogicalBetaOperatorNode( int id, String label, ConnectiveCore conn, int arity, int[] indexes, LeftTupleSource tupleSource, BuildContext context ) {
super( id,
context.getPartitionId(),
context.getRuleBase().getConfiguration().isMultithreadEvaluation() );
this.connective = conn;
this.arity = arity;
this.argIndexes = indexes;
this.label = label;
this.leftInput = tupleSource;
this.fromLIA = tupleSource instanceof LeftInputAdapterNode;
this.tupleMemoryEnabled = context.isTupleMemoryEnabled();
initMasks( context, leftInput );
}
public int getArity() {
return arity;
}
public ConnectiveCore getConnective() {
return connective;
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
super.readExternal( in );
connective = (ConnectiveCore) in.readObject();
arity = in.readInt();
argIndexes = (int[]) in.readObject();
}
public void writeExternal(ObjectOutput out) throws IOException {
super.writeExternal(out);
out.writeObject( connective );
out.writeInt( arity );
out.writeObject( argIndexes );
}
public void attach() {
this.leftInput.addTupleSink(this);
}
public void networkUpdated(UpdateContext updateContext) {
updateContext.startVisitNode(leftInput);
updateContext.endVisit();
if ( !updateContext.isVisiting( leftInput ) ) {
leftInput.networkUpdated( updateContext );
}
}
@Override
protected void doCollectAncestors( NodeSet baseNodes ) {
this.leftInput.collectAncestors( baseNodes );
}
@Override
protected void doRemove( RuleRemovalContext ruleRemovalContext, ReteooBuilder reteooBuilder, InternalWorkingMemory[] internalWorkingMemories ) {
this.leftInput.remove( ruleRemovalContext,
reteooBuilder,
internalWorkingMemories );
}
public void attach( BuildContext context ) {
attach();
}
@Override
public void updateSinkOnAttach( BuildContext context, PropagationContext propagationContext, InternalWorkingMemory workingMemory ) {
this.leftInput.updateSink( this,
propagationContext,
workingMemory );
}
protected void doRemove(final RuleRemovalContext context,
final ReteooBuilder builder,
final BaseNode node,
final InternalWorkingMemory[] workingMemories) {
if ( !node.isInUse() ) {
removeTupleSink( (LeftTupleSink) node );
}
if ( !this.isInUse() || context.getCleanupAdapter() != null ) {
context.setCleanupAdapter( null );
}
this.leftInput.remove( context,
builder,
workingMemories );
}
public LeftTupleSinkNode getPreviousLeftTupleSinkNode() {
return previousLeftTupleSinkNode;
}
public void setPreviousLeftTupleSinkNode(LeftTupleSinkNode previousLeftTupleSinkNode) {
this.previousLeftTupleSinkNode = previousLeftTupleSinkNode;
}
public LeftTupleSinkNode getNextLeftTupleSinkNode() {
return nextLeftTupleSinkNode;
}
public void setNextLeftTupleSinkNode(LeftTupleSinkNode nextLeftTupleSinkNode) {
this.nextLeftTupleSinkNode = nextLeftTupleSinkNode;
}
public String toString() {
return "[" + getId() +"] Operator " + connective;
}
public int hashCode() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LogicalBetaOperatorNode that = (LogicalBetaOperatorNode) o;
if (connective != that.connective) return false;
if (arity != that.arity) return false;
return true;
}
@Override
public void updateSink( LeftTupleSink sink, PropagationContext context, InternalWorkingMemory workingMemory ) {
throw new UnsupportedOperationException( "Logical Beta Operator Node Pass-through, not implemented yet!" );
}
protected ObjectTypeNode getObjectTypeNode() {
ObjectTypeNode objectTypeNode = null;
ObjectSource source = ((LeftInputAdapterNode) this.getLeftTupleSource()).getParentObjectSource();
while ( source != null ) {
if ( source instanceof ObjectTypeNode ) {
objectTypeNode = (ObjectTypeNode) source;
break;
}
source = source.getParentObjectSource();
}
return objectTypeNode;
}
public short getType() {
return NodeTypeEnums.OperatorNode;
}
public void assertLeftTuple( LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory ) {
//TODO Fixme Until all nodes have been made imperfect, tuples might come without evaluations
if ( ((ImperfectTuple)leftTuple).getEvaluation() != null && ! ((ImperfectTuple)leftTuple).getDegree().toBoolean()) {
return;
}
this.sink.propagateAssertLeftTuple( leftTuple, context, workingMemory, isLeftTupleMemoryEnabled() );
}
public void retractLeftTuple(LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory) {
this.sink.propagateRetractLeftTuple( leftTuple, context, workingMemory );
}
public boolean isLeftTupleMemoryEnabled() {
return tupleMemoryEnabled;
}
public void setLeftTupleMemoryEnabled( boolean tupleMemoryEnabled ) {
throw new UnsupportedOperationException( "Logical Beta Operator Node Pass-through, not implemented yet!" );
}
public LeftTupleSource getLeftTupleSource() {
return leftInput;
}
public void modifyLeftTuple( LeftTuple leftTuple, PropagationContext context, InternalWorkingMemory workingMemory ) {
if ( leftTuple.getFirstChild() == null ) {
return;
}
if ( ! fromLIA ) {
//TODO FIXME
if ( leftTuple.getParent() instanceof ImperfectTuple ) {
Evaluation eval = reevaluate( (ImperfectTuple) leftTuple.getParent(), (ImperfectTuple) leftTuple.getRightParent() );
if ( ! eval.getDegree().toBoolean() ) {
return;
}
if ( leftTuple.getFirstChild() != null ) {
((ImperfectTuple) leftTuple.getFirstChild()).addEvaluation( eval );
}
}
}
this.sink.propagateModifyChildLeftTuple( leftTuple, context, workingMemory, isLeftTupleMemoryEnabled() );
}
public LeftTuple createLeftTuple( InternalFactHandle factHandle, LeftTupleSink sink, boolean leftTupleMemoryEnabled ) {
ImperfectTuple tuple = new ImperfectLeftTuple( factHandle, sink, leftTupleMemoryEnabled );
tuple.setEvaluation( ((ChanceFactHandle) factHandle ).getCachedEvaluation( argIndexes[0] ) );
return (LeftTuple) tuple;
}
public LeftTuple createLeftTuple( LeftTuple leftTuple, LeftTupleSink sink, boolean leftTupleMemoryEnabled ) {
ImperfectRuleTerminalNodeLeftTuple tuple = new ImperfectRuleTerminalNodeLeftTuple( leftTuple, sink, leftTupleMemoryEnabled );
//
//TODO FIXME
if ( leftTuple instanceof ImperfectTuple ) {
tuple.setEvaluation( ((ImperfectTuple) leftTuple ).getEvaluation( ) );
}
//
return tuple;
// throw new UnsupportedOperationException( "Not impl yet" );
}
public LeftTuple createLeftTuple( LeftTuple leftTuple, RightTuple rightTuple, LeftTupleSink sink ) {
ImperfectTuple tuple = new ImperfectLeftTuple( leftTuple, rightTuple, sink );
Evaluation eval = reevaluate( (ImperfectTuple) leftTuple, (ImperfectTuple) rightTuple );
tuple.setEvaluation( eval );
return (LeftTuple) tuple;
}
public LeftTuple createLeftTuple(LeftTuple leftTuple, RightTuple rightTuple, LeftTuple currentLeftChild, LeftTuple currentRightChild, LeftTupleSink sink, boolean leftTupleMemoryEnabled) {
ImperfectTuple tuple = new ImperfectLeftTuple( leftTuple, rightTuple, currentLeftChild, currentRightChild, sink, leftTupleMemoryEnabled );
//TODO FIXME
if ( leftTuple instanceof ImperfectTuple) {
tuple.setEvaluation( reevaluate( (ImperfectTuple) leftTuple, (ImperfectTuple) rightTuple ) );
}
return (LeftTuple) tuple;
}
private Evaluation reevaluate( ImperfectTuple left, ImperfectTuple right ) {
Degree[] bits = new Degree[arity];
Evaluation[] children = new Evaluation[arity];
for ( int j = 0; j < arity - 1; j ++ ) {
//TODO FIXME NULL CHECKS
Evaluation arg = left.getCachedEvaluation( this.argIndexes[j] );
children[ j ] = arg != null ? arg : new MockEvaluation( -1, SimpleDegree.TRUE );
bits[ j ] = arg != null ? arg.getDegree() : SimpleDegree.TRUE;
}
Evaluation rightEval = right.getCachedEvaluation( this.argIndexes[ arity - 1 ] );
children[ arity - 1 ] = rightEval;
bits[ arity - 1 ] = rightEval.getDegree();
Degree res = this.connective.eval( bits );
// System.err.println( "LOP" + res );
return new CompositeEvaluation( this.id,
connective.toString() + Arrays.toString( children ),
res,
connective,
children,
label );
}
}