package org.drools.chance.rule.constraint.core.evaluators;
import org.drools.base.BaseEvaluator;
import org.drools.base.ValueType;
import org.drools.base.evaluators.Operator;
import org.drools.chance.common.ChanceStrategyFactory;
import org.drools.chance.common.ImperfectField;
import org.drools.chance.rule.constraint.core.connectives.ConnectiveCore;
import org.drools.chance.rule.constraint.core.connectives.ConnectiveFactory;
import org.drools.chance.rule.constraint.core.connectives.impl.MvlFamilies;
import org.drools.chance.degree.ChanceDegreeTypeRegistry;
import org.drools.chance.degree.Degree;
import org.drools.chance.degree.DegreeType;
import org.drools.chance.distribution.DiscreteDomainDistribution;
import org.drools.chance.distribution.Distribution;
import org.drools.chance.distribution.ImpKind;
import org.drools.chance.distribution.ImpType;
import org.drools.common.InternalFactHandle;
import org.drools.common.InternalWorkingMemory;
import org.drools.rule.VariableRestriction;
import org.drools.spi.FieldValue;
import org.drools.spi.InternalReadAccessor;
import java.util.*;
public abstract class BaseImperfectEvaluator extends BaseEvaluator implements ImperfectEvaluator {
protected ConnectiveCore and;
protected ConnectiveCore or;
protected ConnectiveCore not;
protected Degree baseDegree;
private boolean imperfectOn;
protected boolean negated;
public void setParameterText( String parameterText ) {
}
public BaseImperfectEvaluator( ValueType type, Operator operator ) {
this( type, operator, true );
}
public BaseImperfectEvaluator( ValueType type, Operator operator, boolean enableImperfection ) {
this( type, operator, Collections.<String>emptyList(), enableImperfection );
}
public BaseImperfectEvaluator( ValueType type, Operator operator, boolean isNegated, boolean enableImperfection ) {
this( type, operator, isNegated, Collections.<String>emptyList(), enableImperfection );
}
public BaseImperfectEvaluator( ValueType type, Operator operator, List<String> parameters, boolean enableImperfection ) {
this( type, operator, false, parameters, enableImperfection );
}
public BaseImperfectEvaluator( ValueType type, Operator operator, boolean negated, List<String> parameters, boolean enableImperfection ) {
super( type, operator );
this.imperfectOn = enableImperfection;
this.negated = negated;
if ( parameters != null && parameters.size() > 0 ) {
Map<String,String> paramMap = processParameters( parameters );
initialize( paramMap );
} else {
initializeDefaults();
}
}
protected void initializeDefaults() {
ConnectiveFactory factory = ChanceStrategyFactory.getConnectiveFactory( null, null );
and = factory.getAnd();
or = factory.getOr();
not = factory.getNot();
baseDegree = ChanceDegreeTypeRegistry.getSingleInstance().buildDegree( ChanceDegreeTypeRegistry.getDefaultDegree(), 0 );
}
protected void initialize( Map<String, String> paramMap ) {
MvlFamilies mvf = MvlFamilies.parse( paramMap.get( MvlFamilies.name ) );
ImpKind impKind = ImpKind.parse( paramMap.get( ImpKind.name ) );
ImpType impType = ImpType.parse( paramMap.get( ImpType.name ) );
DegreeType degT = DegreeType.parse( paramMap.get( DegreeType.name ) );
String family = mvf != null ? mvf.value() : null;
ConnectiveFactory factory = ChanceStrategyFactory.getConnectiveFactory( impKind, impType );
and = family != null ? factory.getAnd( family ) : factory.getAnd();
or = family != null ? factory.getOr( family ) : factory.getOr();
not = family != null ? factory.getNot( family ) : factory.getNot();
baseDegree = ChanceDegreeTypeRegistry.getSingleInstance().buildDegree( degT, 0 );
}
protected Map<String,String> processParameters( List<String> parameters ) {
Map<String,String> params = new HashMap<String,String>( parameters.size() );
for ( String p : parameters ) {
int index = p.indexOf( '=' );
if ( index >= 0 ) {
String key = p.substring( 0, index );
String val = p.substring( index + 1 );
params.put( key, val );
} else {
params.put( p, p );
}
}
return params;
}
public boolean evaluate(InternalWorkingMemory workingMemory, InternalReadAccessor extractor, InternalFactHandle object, FieldValue value) {
return match( workingMemory, extractor, object, value ).toBoolean();
}
public boolean evaluate(InternalWorkingMemory workingMemory, InternalReadAccessor leftExtractor, InternalFactHandle left, InternalReadAccessor rightExtractor, InternalFactHandle right) {
return match( workingMemory, leftExtractor, left, rightExtractor, right ).toBoolean();
}
public boolean evaluateCachedLeft( InternalWorkingMemory workingMemory, VariableRestriction.VariableContextEntry context, InternalFactHandle left ) {
return matchCachedLeft(workingMemory, context, left).toBoolean();
}
public boolean evaluateCachedRight( InternalWorkingMemory workingMemory, VariableRestriction.VariableContextEntry context, InternalFactHandle left ) {
return matchCachedRight( workingMemory, context, left ).toBoolean();
}
public Degree match( InternalWorkingMemory workingMemory,
InternalReadAccessor extractor, InternalFactHandle handle, FieldValue value ) {
Object object = handle.getObject();
Object objectValue = null;
if ( object != null ) {
objectValue = extractor.getValue( workingMemory, object );
}
return compare( objectValue, value == null ? null : value.getValue(), workingMemory );
}
public Degree match( InternalWorkingMemory workingMemory,
InternalReadAccessor leftExtractor, InternalFactHandle leftHandle,
InternalReadAccessor rightExtractor, InternalFactHandle rightHandle ) {
Object left = leftHandle.getObject();
Object right = rightHandle.getObject();
final Object value1 = leftExtractor.getValue(workingMemory, left);
final Object value2 = rightExtractor.getValue(workingMemory, right);
Object source = value1;
Object target = value2;
return compare( source, target, workingMemory );
}
public Degree matchCachedLeft( InternalWorkingMemory workingMemory,
VariableRestriction.VariableContextEntry context, InternalFactHandle rightHandle ) {
Object right = rightHandle.getObject();
Object target;
if ( ! context.isLeftNull() ) {
target = ( (VariableRestriction.ObjectVariableContextEntry) context).left;
} else {
if ( context.getVariableDeclaration() != null ) {
target = context.getVariableDeclaration().getExtractor().getValue( workingMemory, right );
} else {
target = right;
}
}
// Object source = context.getFieldExtractor().getValue( prepareLeftObject( context.getTuple().getHandle() ) );
Object source = context.getFieldExtractor().getValue( right );
return compare( source, target, workingMemory );
}
public Degree matchCachedRight( InternalWorkingMemory workingMemory,
VariableRestriction.VariableContextEntry context, InternalFactHandle leftHandle ) {
Object source = context.getFieldExtractor().getValue( context.getObject() );
Object target = leftHandle.getObject();
if ( context.getVariableDeclaration() != null ) {
target = context.getVariableDeclaration().getExtractor().getValue( workingMemory, target );
}
return compare( source, target, workingMemory );
}
protected Degree compare( Object source, Object target, InternalWorkingMemory workingMemory ) {
Distribution leftDist = null;
Distribution rightDist = null;
Object leftValue = null;
Object rightValue = null;
if ( source instanceof ImperfectField ) {
leftDist = ((ImperfectField) source).getCurrent();
} else if ( source instanceof Distribution ) {
leftDist = (Distribution) source;
} else {
leftValue = source;
}
if ( target instanceof ImperfectField ) {
rightDist = ((ImperfectField) target).getCurrent();
} else if ( target instanceof Distribution ) {
rightDist = (Distribution) target;
} else {
rightValue = target;
}
Degree result;
if ( leftDist != null && rightDist != null ) {
result = matchDistributions( leftDist, rightDist, workingMemory );
} else if ( leftDist != null && rightDist == null ) {
result = matchDistributionToValue( leftDist, rightValue, workingMemory );
} else if ( leftDist == null && rightDist != null ) {
result = matchValueToDistribution( leftValue, rightDist, workingMemory );
} else {
result = matchValueToValue( leftValue, rightValue, workingMemory );
}
if ( result != null ) {
return imperfectOn ? result : result.fromBoolean(result.toBoolean());
}
throw new UnsupportedOperationException( "Unable to match " + source + " with " + target );
}
protected Degree matchValueToDistribution( Object leftValue, Distribution rightDist, InternalWorkingMemory workingMemory ) {
Degree deg = getBaseDegree().False();
if ( rightDist.isDiscrete() ) {
if ( rightDist.domainSize().intValue() == 0 ) {
return deg;
}
DiscreteDomainDistribution discr = (DiscreteDomainDistribution) rightDist;
Iterator iter = discr.iterator();
while ( iter.hasNext() ) {
Object right = iter.next();
Degree m = discr.get( right );
if ( m.toBoolean() ) {
deg = or.eval( deg, and.eval( matchValueToValue( leftValue, right, workingMemory ), m ) );
}
}
} else {
throw new UnsupportedOperationException( "Unable to match a value with a continuous distribution!" );
}
return deg;
}
protected Degree matchDistributions( Distribution leftDist, Distribution rightDist, InternalWorkingMemory workingMemory ) {
Degree deg = getBaseDegree().False();
if ( rightDist.isDiscrete() && leftDist.isDiscrete() ) {
DiscreteDomainDistribution ldiscr = (DiscreteDomainDistribution) leftDist;
DiscreteDomainDistribution rdiscr = (DiscreteDomainDistribution) rightDist;
Iterator liter = ldiscr.iterator();
Iterator riter = rdiscr.iterator();
if ( rightDist.domainSize().intValue() == 0 || leftDist.domainSize().intValue() == 0 ) {
return deg;
}
while ( liter.hasNext() ) {
Object left = liter.next();
Degree l = ldiscr.get( left );
if ( l.toBoolean() ) {
while ( riter.hasNext() ) {
Object right = riter.next();
Degree r = rdiscr.get( right );
if ( r.toBoolean() ) {
Degree comp = matchValueToValue( left, right, workingMemory );
if ( comp.toBoolean() ) {
deg = or.eval( deg, and.eval( comp, l, r ) );
}
}
}
}
}
} else {
throw new UnsupportedOperationException( "Unable to match a value with a continuous distribution!" );
}
return deg;
}
protected Degree matchDistributionToValue( Distribution leftDist, Object rightValue, InternalWorkingMemory workingMemory ) {
Degree deg = getBaseDegree().False();
if ( leftDist.isDiscrete() ) {
if ( leftDist.domainSize().intValue() == 0 ) {
return deg;
}
DiscreteDomainDistribution discr = (DiscreteDomainDistribution) leftDist;
Iterator iter = discr.iterator();
while ( iter.hasNext() ) {
Object left = iter.next();
Degree m = discr.get( left );
if ( m.toBoolean() ) {
deg = or.eval( deg, and.eval( m, matchValueToValue( left, rightValue, workingMemory ) ) );
}
}
} else {
throw new UnsupportedOperationException( "Unable to match a value with a continuous distribution!" );
}
return deg;
}
protected abstract Degree matchValueToValue( Object leftValue, Object rightValue, InternalWorkingMemory workingMemory );
public Degree getBaseDegree() {
return baseDegree;
}
}