All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jadex.rules.rulesystem.rete.nodes.AlphaNode Maven / Gradle / Ivy

Go to download

Jadex Rules is a small lightweight rule engine, which currently employs the well-known Rete algorithm for highly efficient rule matching. Jadex rules is therefore similar to other rule engines like JESS and Drools. Despite the similarities there are also important differences between these systems: * Jadex Rules is very small and intended to be used as component of other software. Even though rules can be specified in a Java dialect as well as (a small variation of) the CLIPS language its primary usage is on the API level. Jadex Rules is currently the core component of the Jadex BDI reasoning engine. * Jadex Rules cleanly separates between state and rule representation. This allows the state implementation as well as the matcher to be flexibly exchanged. Some experiments have e.g. been conducted with a Jena representation. Regarding the matcher, it is planned to support also the Treat algorithm, which has a lower memory footprint than Rete. * Jadex Rules pays close attention to rule debugging. The state as well as the rete engine can be observed at runtime. The rule debugger provides functionalities to execute a rule program stepwise and also use rule breakpoints to stop the execution at those points.

There is a newer version: 2.4
Show newest version
package jadex.rules.rulesystem.rete.nodes;

import jadex.commons.SUtil;
import jadex.rules.rulesystem.AbstractAgenda;
import jadex.rules.rulesystem.rete.constraints.IConstraintEvaluator;
import jadex.rules.rulesystem.rete.extractors.AttributeSet;
import jadex.rules.state.IOAVState;
import jadex.rules.state.IProfiler;
import jadex.rules.state.OAVAttributeType;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 *  An alpha node is a 1-input -> 1-output node which
 *  propagates objects matching its constraints. 
 */
public class AlphaNode extends AbstractNode implements IObjectConsumerNode, IObjectSourceNode
{
	//-------- attributes --------
	
	/** The object source. */
	protected IObjectSourceNode osource;
	
	/** The object consumers. */
	protected IObjectConsumerNode[]	oconsumers;

	/** The constraint evaluator. */
	protected IConstraintEvaluator[] evaluators;
	
	/** The set of relevant attributes. */
	protected AttributeSet	relevants;

	/** The set of indirect attributes. */
	protected AttributeSet indirects;

	//-------- constructors --------
	
	/**
	 *  Create a new node.
	 *  @param evaluators The evaluators.
	 */
	public AlphaNode(int nodeid, IConstraintEvaluator[] evaluators)
	{
		super(nodeid);
		this.evaluators	= evaluators;
	}

	//-------- object consumer interface --------
	
	/**
	 *  Send a new object to this node.
	 *  @param object The object.
	 */
	public void addObject(Object object, IOAVState state, ReteMemory mem, AbstractAgenda agenda)
	{
		//System.out.println("Add object called: "+this+" "+object);
		
//		if(object.getClass().toString().indexOf("Order")!=-1)
//			System.out.println("here: "+object);
//		if(state.getType(object).getName().indexOf("goal")!=-1)
//			System.out.println("here: "+object);
		
		state.getProfiler().start(IProfiler.TYPE_NODE, this);
		state.getProfiler().start(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_OBJECTADDED);
		
		assert !mem.hasNodeMemory(this) || !((Collection)mem.getNodeMemory(this)).contains(object) : "New objects shouldn't be contained.";
		
		if(checkConstraints(object, state))
		{
			((Collection)mem.getNodeMemory(this)).add(object);
			//System.out.println("Object passed constraint check: "+this+" "+object);
			propagateAdditionToObjectConsumers(object, state, mem, agenda);
		}

		state.getProfiler().stop(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_OBJECTADDED);
		state.getProfiler().stop(IProfiler.TYPE_NODE, this);
	}
	
	/**
	 *  Send a removed object to this node.
	 *  @param object The object.
	 */
	public void removeObject(Object object, IOAVState state, ReteMemory mem, AbstractAgenda agenda)
	{
		//System.out.println("Remove object called: "+this+" "+object);
		state.getProfiler().start(IProfiler.TYPE_NODE, this);
		state.getProfiler().start(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_OBJECTREMOVED);
		
		if(mem.hasNodeMemory(this) && ((Collection)mem.getNodeMemory(this)).remove(object))
		{
			//System.out.println("Object passed constraint check: "+this+" "+object);
			propagateRemovalToObjectConsumers(object, state, mem, agenda);
		}

		state.getProfiler().stop(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_OBJECTREMOVED);
		state.getProfiler().stop(IProfiler.TYPE_NODE, this);
	}
	
	/**
	 *  Propagate an object change to this node.
	 *  @param object The new object.
	 */
	public void modifyObject(Object object, OAVAttributeType type, Object oldvalue, Object newvalue, 
		IOAVState state, ReteMemory mem, AbstractAgenda agenda)
	{
		//System.out.println("Modify object called: "+this+" "+object);
		state.getProfiler().start(IProfiler.TYPE_NODE, this);
		state.getProfiler().start(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_OBJECTMODIFIED);

		if(getRelevantAttributes().contains(type))
		{
			// Check if modification changes node memory.
			boolean affected = isAffected(type);
			boolean	contains	= mem.hasNodeMemory(this) && ((Collection)mem.getNodeMemory(this)).contains(object);
		
			if(affected)
			{
				boolean check = checkConstraints(object, state);
				
				// Object no longer valid -> remove
				if(contains && !check)
				{
					((Collection)mem.getNodeMemory(this)).remove(object);
					propagateRemovalToObjectConsumers(object, state, mem, agenda);
				}
		
				// Object newly valid -> add
				else if(!contains && check)
				{
					((Collection)mem.getNodeMemory(this)).add(object);
					propagateAdditionToObjectConsumers(object, state, mem, agenda);
				}
				
				// Propagate modification for deeper nodes if here no change.
				else if(contains)
				{
					propagateModificationToObjectConsumers(object, type, oldvalue, newvalue, 
						state, mem, agenda);
				}
			}
			else
			{
				// Object changed in memory -> propagate modification
				if(contains)
				{
					propagateModificationToObjectConsumers(object, type, oldvalue, newvalue, 
						state, mem, agenda);
				}
			}
		}

		state.getProfiler().stop(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_OBJECTMODIFIED);
		state.getProfiler().stop(IProfiler.TYPE_NODE, this);
	}

	/**
	 *  Propagate an indirect object change to this node.
	 *  @param id The changed object.
	 */
	public void modifyIndirectObject(Object id, OAVAttributeType type, Object oldvalue, Object newvalue, IOAVState state, ReteMemory mem, AbstractAgenda agenda)
	{
		Collection	oldmem	= getNodeMemory(mem);
		Collection	input	= getObjectSource().getNodeMemory(mem);
		if(input!=null)
		{
			// Todo: Use index for avoiding the need for checking all objects.
			for(Iterator it=input.iterator(); it.hasNext(); )
			{
				Object	object	= it.next();
				boolean	contains	= oldmem!=null && oldmem.contains(object);		
				boolean check = checkConstraints(object, state);

				// Object no longer valid -> remove
				if(contains && !check)
				{
					((Collection)mem.getNodeMemory(this)).remove(object);
					propagateRemovalToObjectConsumers(object, state, mem, agenda);
				}

				// Object newly valid -> add
				else if(!contains && check)
				{
					((Collection)mem.getNodeMemory(this)).add(object);
					propagateAdditionToObjectConsumers(object, state, mem, agenda);
				}
			}
		}
	}

	/**
	 *  Set the object source of this node.
	 *  @param node The object source node.
	 */
	public void setObjectSource(IObjectSourceNode node)
	{
		this.osource = node;
	}
	
	/**
	 *  Get the object source of this node.
	 *  @return The object source node.
	 */
	public IObjectSourceNode getObjectSource()
	{
		return osource;
	}
	
	//-------- object source interface --------
		
	/**
	 *  Add an object consumer node.
	 *  @param node A new consumer node.
	 */
	public void addObjectConsumer(IObjectConsumerNode node)
	{
		if(oconsumers==null)
		{
			oconsumers = new IObjectConsumerNode[]{node};
		}
		else
		{
			IObjectConsumerNode[]	tmp	= new IObjectConsumerNode[oconsumers.length+1];
			System.arraycopy(oconsumers, 0, tmp, 0, oconsumers.length);
			tmp[oconsumers.length]	= node;
			oconsumers	= tmp;
		}

		relevants	= null;	// Will be recalculated on next access;
	}
	
	/**
	 *  Remove an object consumer.
	 *  @param node The consumer node.
	 */
	public void removeObjectConsumer(IObjectConsumerNode node)
	{
		if(oconsumers!=null)
		{
			for(int i=0; i0)
							System.arraycopy(oconsumers, 0, tmp, 0, i);
						if(i© 2015 - 2025 Weber Informatics LLC | Privacy Policy