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

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

package jadex.rules.rulesystem.rete.nodes;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import jadex.rules.rulesystem.AbstractAgenda;
import jadex.rules.rulesystem.rete.Tuple;
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;

/**
 *  The purpose of a collect node is to compress a number of tuples to a
 *  new tuple, which contains a multi slot.
 *  Example: Incoming tuples are:
 *  [a, b, d1]
 *  [a, b, d2]
 *  [a, c, d3]
 *  [a, c, d1]
 *  -> 
 *  [a, b, {d1, d2}]
 *  [a, c, {d3, d1}]
 */
public class CollectNode extends AbstractNode implements ITupleConsumerNode, ITupleSourceNode
{
	//-------- attributes --------
	
	/** The tuple consumers. */
	protected ITupleConsumerNode[] tconsumers;
	
	/** The tuple source. */
	protected ITupleSourceNode tsource;
	
	/** The constraint evaluator. */
	protected IConstraintEvaluator[] evaluators;
	
	/** The set of relevant attributes. */
	protected volatile AttributeSet relevants;
	
	/** The set of indirect attributes. */
	protected volatile AttributeSet indirects;
	
	/** The tuple index to collect. */
	protected int tupleindex;

	//-------- constructors --------
	
	/**
	 *  Create a new beta node.
	 */
	public CollectNode(int nodeid, int tupleindex, IConstraintEvaluator[] evaluators)
	{
		super(nodeid);
		this.tupleindex = tupleindex;
		this.evaluators	= evaluators;
	}
	
	//-------- tuple source interface --------
	
	/**
	 *  Add an tuple consumer node.
	 *  @param node A new consumer node.
	 */
	public void addTupleConsumer(ITupleConsumerNode node)
	{
		if(tconsumers==null)
		{
			tconsumers = new ITupleConsumerNode[]{node};
		}
		else
		{
			ITupleConsumerNode[]	tmp	= new ITupleConsumerNode[tconsumers.length+1];
			System.arraycopy(tconsumers, 0, tmp, 0, tconsumers.length);
			tmp[tconsumers.length]	= node;
			tconsumers	= tmp;
		}

		relevants	= null;	// Will be recalculated on next access;
	}
	
	/**
	 *  Remove an tuple consumer.
	 *  @param node The consumer node.
	 */
	public void removeTupleConsumer(ITupleConsumerNode node)
	{
		if(tconsumers!=null)
		{
			for(int i=0; i0)
							System.arraycopy(tconsumers, 0, tmp, 0, i);
						if(i add
			if(!nodemem.resultMemoryContains(resulttuple))
			{
				nodemem.addResultTuple(resulttuple);
				propagateAdditionToTupleConsumers(resulttuple, state, mem, agenda);
			}
			// If constraints passed and in result -> modify
			else
			{
				// todo: 
				propagateModificationToTupleConsumers(resulttuple, null, null, resulttuple, state, mem, agenda);
			}
		}
		else
		{
			// If constraints not passed and in result -> remove
			if(nodemem.resultMemoryContains(resulttuple))
			{
				nodemem.removeResultTuple(resulttuple);
				propagateRemovalToTupleConsumers(resulttuple, state, mem, agenda);
			}
			// If constraints not passed and not in result -> nop
		}
		
		state.getProfiler().stop(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_TUPLEADDED);
		state.getProfiler().stop(IProfiler.TYPE_NODE, this);
		
//		System.out.println(nodemem);
	}

	/**
	 *  Remove a tuple from this node.
	 *  @param tuple The tuple.
	 */
	public void removeTuple(Tuple left, IOAVState state, ReteMemory mem, AbstractAgenda agenda)
	{
//		if(getNodeId()==531)
//			System.out.println("Remove tuple called: "+this+" "+left);
		state.getProfiler().start(IProfiler.TYPE_NODE, this);
		state.getProfiler().start(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_TUPLEREMOVED);

		Tuple indextuple = createIndexTuple(state, left, mem);
		CollectMemory nodemem = (CollectMemory)mem.getNodeMemory(this);
		Tuple resulttuple = nodemem.getWorkingTuple(indextuple);
		
		assert resulttuple!=null: "No working tuple found: "+indextuple;
		
		Object val = left.getObject(tupleindex);
		Set vals = (Set)resulttuple.getObject(tupleindex);
		
		boolean removed = vals.remove(val);
		
		// Remove tuple when last element is removed from set. 
		if(vals.isEmpty())
		{
			nodemem.removeWorkingTuple(indextuple);
			if(nodemem.resultMemoryContains(resulttuple))
			{
				nodemem.removeResultTuple(resulttuple);
				propagateRemovalToTupleConsumers(resulttuple, state, mem, agenda);
			}
		}
		// Check constraints if at least one element.
		else
		{
			assert removed: "Value not found in result tuple: "+val;
			
			if(checkConstraints(resulttuple, state))
			{
				// If constraints passed and not in result -> add
				if(!nodemem.resultMemoryContains(resulttuple))
				{
					nodemem.addResultTuple(resulttuple);
					propagateAdditionToTupleConsumers(resulttuple, state, mem, agenda);
				}
				// If constraints passed and in result -> modify
				else
				{
					// todo: 
					propagateModificationToTupleConsumers(resulttuple, null, null, resulttuple, state, mem, agenda);
				}
			}
			else
			{
				// If constraints not passed and in result -> remove
				if(nodemem.resultMemoryContains(resulttuple))
				{
					nodemem.removeResultTuple(resulttuple);
					propagateRemovalToTupleConsumers(resulttuple, state, mem, agenda);
				}
				// If constraints not passed and not in result -> nop
			}
		}
		
		state.getProfiler().stop(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_TUPLEREMOVED);
		state.getProfiler().stop(IProfiler.TYPE_NODE, this);
	
//		System.out.println(nodemem);
	}

	/**
	 *  Modify a tuple in this node.
	 *  @param left The tuple.
	 */
	public void modifyTuple(Tuple left, int tupleindex, OAVAttributeType type,
		Object oldvalue, Object newvalue, IOAVState state, ReteMemory mem, AbstractAgenda agenda)
	{
//		if(getNodeId()==531)
//			System.out.println("Modify tuple called: "+this+" "+left);

		if(!getRelevantAttributes().contains(type))
			return;

		// Problem: changed tuple could produce changed indextuple -> no identification of old value
		Tuple indextuple = createIndexTuple(state, left, mem);
		CollectMemory nodemem = (CollectMemory)mem.getNodeMemory(this);
		Tuple resulttuple = nodemem.getWorkingTuple(indextuple);
		assert resulttuple!=null: "No working tuple found: "+indextuple;

		// Check if modification changes node memory.
		boolean affected = isAffected(type);
	
		if(affected)
		{
			boolean	contains = nodemem.resultMemoryContains(resulttuple);
			boolean check = checkConstraints(resulttuple, state);
			
			// Object no longer valid -> remove
			if(contains && !check)
			{
				nodemem.removeResultTuple(resulttuple);
				propagateRemovalToTupleConsumers(resulttuple, state, mem, agenda);
			}
	
			// Tuple newly valid -> add
			else if(!contains && check)
			{
				nodemem.addResultTuple(resulttuple);
				propagateAdditionToTupleConsumers(resulttuple, state, mem, agenda);
			}
			
			else if(contains)
			{
				propagateModificationToTupleConsumers(resulttuple, type, oldvalue, newvalue, 
					state, mem, agenda);
			}
		}
		else
		{
			// Tuple changed in memory -> propagate modification
			boolean	contains = nodemem.resultMemoryContains(resulttuple);
			if(contains)
			{
				propagateModificationToTupleConsumers(resulttuple, type, oldvalue, newvalue, 
					state, mem, agenda);
			}
		}
		
		state.getProfiler().start(IProfiler.TYPE_NODE, this);
		state.getProfiler().start(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_TUPLEMODIFIED);

		state.getProfiler().stop(IProfiler.TYPE_NODEEVENT, IProfiler.NODEEVENT_TUPLEMODIFIED);
		state.getProfiler().stop(IProfiler.TYPE_NODE, this);
	
//		System.out.println(nodemem);
	}

	/**
	 *  Propagate an indirect object change to this node.
	 *  @param object The changed object.
	 */
	public void modifyIndirectObject(Object object, OAVAttributeType type, Object oldvalue, Object newvalue, IOAVState state, ReteMemory mem, AbstractAgenda agenda)
	{
		throw new UnsupportedOperationException("Unsupported method.");
	}

	/**
	 *  Set the tuple source of this node.
	 *  @param node The tuple source node.
	 */
	public void setTupleSource(ITupleSourceNode node)
	{
		this.tsource = node;
	}
	
	/**
	 *  Get the tuple source of this node.
	 *  @return The object source node.
	 */
	public ITupleSourceNode getTupleSource()
	{
		return tsource;
	}
	
	//-------- methods --------
	
	/**
	 *  Create the node memory.
	 *  @param state	The state.
	 *  @return The node memory.
	 */
	public Object createNodeMemory(IOAVState state)
	{
		return new CollectMemory();
	}
	
	/**
	 *  Get the evaluators.
	 *  @return The evaluators.
	 */
	public IConstraintEvaluator[] getConstraintEvaluators()
	{
		return evaluators;
	}
	
	//-------- methods --------
	
	/**
	 *  Test if the node is affected from a modification.
	 *  @param type The attribute type.
	 *  @return True, if possibly affected.
	 */
	public boolean isAffected(OAVAttributeType attr)
	{
		boolean ret = false;
		for(int i=0; !ret && evaluators!=null && i© 2015 - 2025 Weber Informatics LLC | Privacy Policy