/*
* Copyright 2011 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.chance.distribution;
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.LogicConnectives;
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.degree.simple.SimpleDegree;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.Set;
/**
* Strategy and level III factory for discrete probability distributions
* @param <T>
*/
public class BasicDistributionStrategy<T> implements DistributionStrategies<T> {
private ConnectiveFactory connFactory;
private DegreeType degreeType;
private Class<T> domainType;
private Constructor degreeStringConstr = null;
private Degree tru;
private Degree fal;
private Degree unk;
public BasicDistributionStrategy( DegreeType degreeType, Class<T> domainType, ConnectiveFactory connFactory ) {
this.connFactory = connFactory;
this.degreeType = degreeType;
this.domainType = domainType;
try {
this.tru = ChanceDegreeTypeRegistry.getSingleInstance().getDegreeClass( degreeType ).newInstance().True();
} catch( Exception e ) {
this.tru = SimpleDegree.TRUE;
}
try {
this.fal = ChanceDegreeTypeRegistry.getSingleInstance().getDegreeClass( degreeType ).newInstance().False();
} catch( Exception e ) {
this.fal = SimpleDegree.FALSE;
}
try {
this.unk = ChanceDegreeTypeRegistry.getSingleInstance().getDegreeClass( degreeType ).newInstance().Unknown();
} catch( Exception e ) {
this.unk = new SimpleDegree(0.5);
}
}
private Constructor getDegreeStringConstructor() {
if (degreeStringConstr == null) {
degreeStringConstr = ChanceDegreeTypeRegistry.getSingleInstance().getConstructorByString( degreeType );
}
return degreeStringConstr;
}
public Distribution<T> toDistribution(T value) {
return new BasicDistribution<T>( value, tru );
}
public Distribution<T> toDistribution(T value, String strategy) {
return new BasicDistribution<T>( value, tru );
}
public Distribution<T> toDistribution(T value, Object... params) {
return new BasicDistribution<T>( value, (Degree) params[0] );
}
public Distribution<T> parse(String distrAsString) {
int idx = distrAsString.indexOf('/');
T val;
Degree deg;
try {
if ( idx < 0 ) {
val = domainType.getConstructor(String.class).newInstance( distrAsString.trim() );
deg = tru;
} else {
val = domainType.getConstructor(String.class).newInstance( distrAsString.substring( 0, idx ) );
deg = (Degree) ChanceDegreeTypeRegistry.getSingleInstance().getConstructorByString( degreeType ).newInstance( distrAsString.substring( idx + 1 ) );
}
return new BasicDistribution<T>( val, deg );
} catch (NoSuchMethodException nsme) {
nsme.printStackTrace();
} catch (IllegalAccessException iae) {
iae.printStackTrace();
} catch (InstantiationException ie) {
ie.printStackTrace();
} catch (InvocationTargetException ite) {
ite.printStackTrace();
}
return null;
}
public Distribution<T> newDistribution() {
if ( Boolean.class.equals( domainType ) ) {
return (Distribution<T>) new BasicDistribution<Boolean>( true, unk );
} else {
return new BasicDistribution<T>( null, fal );
}
}
public Distribution<T> newDistribution(Set<T> focalElements) {
T value = focalElements.iterator().next();
return new BasicDistribution<T>( value, tru );
}
public Distribution<T> newDistribution(Map<? extends T, ? extends Degree> elements) {
T value = elements.keySet().iterator().next();
Degree deg = elements.get( value );
try {
return new BasicDistribution<T>( value, deg );
} catch( Exception e ) {
return new BasicDistribution<T>( value, deg );
}
}
public T toCrispValue(Distribution<T> dist) {
return ((BasicDistribution<T>) dist).getValue();
}
public T toCrispValue(Distribution<T> dist, String strategy) {
return ((BasicDistribution<T>) dist).getValue();
}
public T toCrispValue(Distribution<T> dist, Object... params) {
return ((BasicDistribution<T>) dist).getValue();
}
public T sample(Distribution<T> dist) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public T sample(Distribution<T> dist, String strategy) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public T sample(Distribution<T> dist, Object... params) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Distribution<T> merge(Distribution<T> current, Distribution<T> newBit) {
return merge( current, newBit, "operator=OR" );
}
public Distribution<T> merge(Distribution<T> current, Distribution<T> newBit, String strategy) {
return merge( current, newBit, new Object[] {strategy} );
}
public Distribution<T> merge(Distribution<T> current, Distribution<T> newBit, Object... params) {
BasicDistribution<T> src = (BasicDistribution<T>) current;
BasicDistribution<T> bit = (BasicDistribution<T>) newBit;
T val = src.getValue();
if ( val == null ) {
val = ((BasicDistribution<T>) newBit).getValue();
src.set( val, newBit.getDegree( val ) );
} else if ( val.equals( bit.getValue() ) ) {
ConnectiveCore op = null;
if ( params.length > 0 ) {
op = parseParams( params );
} else {
op = connFactory.getOr();
}
Degree c = op.eval( src.getDegree(val), bit.getDegree( val ) );
src.setDegree( c.getValue() > 0.99 ? c.True() : c );
} else {
ConnectiveCore op = connFactory.getConnective( LogicConnectives.AND, MvlFamilies.PRODUCT.value() );
Degree a = src.getDegree( val );
Degree b = bit.getDegree( val );
Degree c = op.eval( a, b );
if ( c.equals( c.False() ) ) {
src.set( ((BasicDistribution<T>) newBit).getValue(), c.True() );
} else {
src.setDegree( c );
}
}
return src;
}
private ConnectiveCore parseParams(Object[] params) {
LogicConnectives conn = LogicConnectives.OR;
String family = MvlFamilies.PRODUCT.value();
for ( int j = 0; j < params.length; j++ ) {
String param = (String) params[j];
int idx = param.indexOf( '=' );
if ( idx > 0 ) {
String key = param.substring( 0, idx ).trim();
if ( "family".equals( key ) ) {
family = param.substring( idx + 1 );
} else if ( "operator".equals( key ) ) {
conn = LogicConnectives.valueOf(param.substring(idx + 1));
}
}
}
return connFactory.getConnective( conn, family );
}
public Distribution<T> mergeAsNew(Distribution<T> current, Distribution<T> newBit) {
BasicDistribution<T> src = (BasicDistribution<T>) current;
BasicDistribution<T> bit = (BasicDistribution<T>) newBit;
T val = src.getValue();
if ( val == null || ! val.equals( bit.getValue() ) ) {
src.clear();
return src;
}
Degree a = src.getDegree( val );
Degree b = bit.getDegree( val );
Degree deg = ( a.sum( b ) ).sub( a.mul( b ) );
BasicDistribution<T> dist = new BasicDistribution<T>( val, deg );
return dist;
}
public Distribution<T> mergeAsNew(Distribution<T> current, Distribution<T> newBit, String strategy) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Distribution<T> mergeAsNew(Distribution<T> current, Distribution<T> newBit, Object... params) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Distribution<T> remove(Distribution<T> current, Distribution<T> newBit) {
return remove( current, newBit, new Object[0] );
}
// w -> w/a
//
// 1-a -> (1-a)/(1-b) ---> (1-a) -> 1 - (1-a)/(1-b) -----> (1-b -1 +a)/(1-b) --> (a-b)/(1-b)
public Distribution<T> remove(Distribution<T> current, Distribution<T> newBit, String strategy) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Distribution<T> remove(Distribution<T> current, Distribution<T> newBit, Object... params) {
BasicDistribution<T> src = (BasicDistribution<T>) current;
BasicDistribution<T> bit = (BasicDistribution<T>) newBit;
T val = src.getValue();
if ( val == null ) {
} else if ( val.equals( bit.getValue() ) ) {
Degree a = src.getDegree(val);
Degree b = bit.getDegree( val );
Degree c;
if ( a.equals( a.True() ) && b.getValue() > 0 ) {
a = a.fromConst( 0.99 );
}
c = ( a.sub( b ) ).div( a.True().sub( b ) );
src.setDegree( c );
} else {
//do nothing
}
return src;
}
public Distribution<T> removeAsNew(Distribution<T> current, Distribution<T> newBit) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Distribution<T> removeAsNew(Distribution<T> current, Distribution<T> newBit, String strategy) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Distribution<T> removeAsNew(Distribution<T> current, Distribution<T> newBit, Object... params) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public void normalize(Distribution<T> distr) {
//To change body of implemented methods use File | Settings | File Templates.
}
}