Newer
Older
AlgebraicDataflowArchitectureModel / AlgebraicDataflowArchitectureModel / src / models / dataFlowModel / DataTransferChannel.java
package models.dataFlowModel;

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

import models.algebra.Expression;
import models.algebra.InvalidMessage;
import models.algebra.Parameter;
import models.algebra.ParameterizedIdentifierIsFutureWork;
import models.algebra.Position;
import models.algebra.Term;
import models.algebra.UnificationFailed;
import models.algebra.ValueUndefined;
import models.algebra.Variable;
import models.dataConstraintModel.*;

public class DataTransferChannel extends Channel {
	protected Set<ChannelMember> inputChannelMembers = null;
	protected Set<ChannelMember> outputChannelMembers = null;
	protected Set<ChannelMember> referenceChannelMembers = null;
	
	public DataTransferChannel(String channelName) {
		this(null, channelName);
	}
	
	public DataTransferChannel(String channelName, Variable variable) {
		this(null, channelName, variable);
	}

	public DataTransferChannel(String channelName, List<Variable> variables) {
		this(null, channelName, variables);
	}
	
	public DataTransferChannel(DataTransferChannel parent, String channelName) {
		super(parent, channelName);
		inputChannelMembers = new HashSet<>();
		outputChannelMembers = new HashSet<>();
		referenceChannelMembers = new HashSet<>();
	}
	
	public DataTransferChannel(DataTransferChannel parent, String channelName, Variable variable) {
		super(parent, channelName, variable);
		inputChannelMembers = new HashSet<>();
		outputChannelMembers = new HashSet<>();
		referenceChannelMembers = new HashSet<>();
	}
	
	public DataTransferChannel(DataTransferChannel parent, String channelName, List<Variable> variables) {
		super(parent, channelName, variables);
		inputChannelMembers = new HashSet<>();
		outputChannelMembers = new HashSet<>();
		referenceChannelMembers = new HashSet<>();
	}

	public Set<ChannelMember> getInputChannelMembers() {
		return inputChannelMembers;
	}
	
	public void setInputChannelMembers(Set<ChannelMember> inputChannelMembers) {
		this.inputChannelMembers = inputChannelMembers;
	}
	
	public void addInputChannelMember(ChannelMember inputChannelMember) {
		inputChannelMembers.add(inputChannelMember);
	}
	
	public Set<ChannelMember> getOutputChannelMembers() {
		return outputChannelMembers;
	}
	
	public void setOutputChannelMembers(Set<ChannelMember> outputChannelMembers) {
		this.outputChannelMembers = outputChannelMembers;
	}
	
	public void addOutputChannelMember(ChannelMember outputChannelMember) {
		outputChannelMembers.add(outputChannelMember);
	}
	
	public Set<ChannelMember> getReferenceChannelMembers() {
		return referenceChannelMembers;
	}
	
	public void setReferenceChannelMembers(Set<ChannelMember> referenceChannelMembers) {
		this.referenceChannelMembers = referenceChannelMembers;
	}
	
	public void addReferenceChannelMember(ChannelMember referenceChannelMember) {
		referenceChannelMembers.add(referenceChannelMember);
	}
		
	public void addChannelMemberAsInput(ChannelMember inputChannelMember) {
		addChannelMember(inputChannelMember);
		addInputChannelMember(inputChannelMember);
	}
	
	public void addChannelMemberAsOutput(ChannelMember outputChannelMember) {
		addChannelMember(outputChannelMember);
		addOutputChannelMember(outputChannelMember);
	}
	
	public void addChannelMemberAsReference(ChannelMember referenceChannelMember) {
		addChannelMember(referenceChannelMember);
		addReferenceChannelMember(referenceChannelMember);
	}
	
	public void removeChannelMember(ResourcePath id) {
		for (ChannelMember cm: inputChannelMembers) {
			if (cm.getResource() == id) {
				inputChannelMembers.remove(cm);
				super.removeChannelMember(id);
				return;
			}
		}
		for (ChannelMember cm: outputChannelMembers) {
			if (cm.getResource() == id) {
				outputChannelMembers.remove(cm);
				super.removeChannelMember(id);
				return;
			}
		}
		for (ChannelMember cm: referenceChannelMembers) {
			if (cm.getResource() == id) {
				referenceChannelMembers.remove(cm);
				super.removeChannelMember(id);
				return;
			}
		}
	}
	
	public Set<ResourcePath> getInputResources() {
		Set<ResourcePath> inputResources = new HashSet<>();
		for (ChannelMember member: inputChannelMembers) {
			inputResources.add(member.getResource());
		}
		return inputResources;
	}
	
	public Set<ResourcePath> getOutputResources() {
		Set<ResourcePath> outputResources = new HashSet<>();
		for (ChannelMember member: outputChannelMembers) {
			outputResources.add(member.getResource());
		}
		return outputResources;
	}
	
	public Set<ResourcePath> getReferenceResources() {
		Set<ResourcePath> referenceResources = new HashSet<>();
		for (ChannelMember member: referenceChannelMembers) {
			referenceResources.add(member.getResource());
		}
		return referenceResources;
	}
	
	/**
	 * Derive the update expression of the state of the target channel member.
	 * @param targetMember a channel member whose state is to be updated
	 * @return the derived update expression
	 * @throws ParameterizedIdentifierIsFutureWork
	 * @throws ResolvingMultipleDefinitionIsFutureWork
	 * @throws InvalidMessage
	 * @throws UnificationFailed
	 * @throws ValueUndefined
	 */
	public Expression deriveUpdateExpressionOf(ChannelMember targetMember) throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined {
		IResourceStateAccessor defaultStateAccessor = new IResourceStateAccessor() {
			HashMap<String, Parameter> curStateParams = new HashMap<>();
			HashMap<String, Parameter> nextStateParams = new HashMap<>();

			@Override
			public Expression getCurrentStateAccessorFor(ResourcePath target, ResourcePath from) {
				String resource = target.getResourceName();
				Parameter curStateParam = curStateParams.get(resource);
				if (curStateParam == null) {
					curStateParam = new Parameter("cur" + resource);
					curStateParams.put(resource, curStateParam);
				}
				return curStateParam;
			}

			@Override
			public Expression getNextStateAccessorFor(ResourcePath target, ResourcePath from) {
				String resource = target.getResourceName();
				Parameter nextStateParam = nextStateParams.get(resource);
				if (nextStateParam == null) {
					nextStateParam = new Parameter("next" + resource);
					nextStateParams.put(resource, nextStateParam);
				}
				return nextStateParam;
			}
		};
		return deriveUpdateExpressionOf(targetMember, defaultStateAccessor);
	}
	
	/**
	 * Derive the update expression of the state of the target channel member with a given resource state accessor.
	 * @param targetMember a channel member whose state is to be updated
	 * @param stateAccessor a resource state accessor
	 * @return the derived update expression
	 * @throws ParameterizedIdentifierIsFutureWork
	 * @throws ResolvingMultipleDefinitionIsFutureWork
	 * @throws InvalidMessage
	 * @throws UnificationFailed
	 * @throws ValueUndefined
	 */
	public Expression deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor) 
			throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined {
		return deriveUpdateExpressionOf(targetMember, stateAccessor, null);
	}

	public Expression deriveUpdateExpressionOf(ChannelMember targetMember, IResourceStateAccessor stateAccessor, HashMap<ResourcePath, IResourceStateAccessor> inputResourceToStateAccessor) 
			throws ParameterizedIdentifierIsFutureWork, ResolvingMultipleDefinitionIsFutureWork, InvalidMessage, UnificationFailed, ValueUndefined {
		if (!getOutputChannelMembers().contains(targetMember)) return null;
		HashSet<Term> messageConstraints = new HashSet<>();
		
		// Calculate message constraints from input state transitions
		for (ChannelMember inputMember: getInputChannelMembers()) {
			ResourcePath inputResource = inputMember.getResource();
//			if (inputResource.getNumberOfParameters() > 0) {
//				throw new ParameterizedIdentifierIsFutureWork();
//			}
			Expression curInputStateAccessor = null;
			Expression nextInputStateAccessor = null;
			if (inputResourceToStateAccessor == null) {
				curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(inputResource, targetMember.getResource());
				nextInputStateAccessor = stateAccessor.getNextStateAccessorFor(inputResource, targetMember.getResource());
			} else {
				curInputStateAccessor = inputResourceToStateAccessor.get(inputResource).getCurrentStateAccessorFor(inputResource, targetMember.getResource());
				nextInputStateAccessor = inputResourceToStateAccessor.get(inputResource).getNextStateAccessorFor(inputResource, targetMember.getResource());
			}
			Expression messageConstraintByInput = inputMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor, nextInputStateAccessor);
			messageConstraints.add((Term) messageConstraintByInput);
		}

		// Calculate message constraints from reference state transitions
		for (ChannelMember referenceMember: getReferenceChannelMembers()) {
			ResourcePath referenceResource = referenceMember.getResource();
//			if (referenceResource.getNumberOfParameters() > 0) {
//				throw new ParameterizedIdentifierIsFutureWork();
//			}
			Expression curInputStateAccessor = null;
			if (inputResourceToStateAccessor == null) {
				curInputStateAccessor = stateAccessor.getCurrentStateAccessorFor(referenceResource, targetMember.getResource());
			} else {
				curInputStateAccessor = inputResourceToStateAccessor.get(referenceResource).getCurrentStateAccessorFor(referenceResource, targetMember.getResource());
			}
			Expression messageConstraintByReference = referenceMember.getStateTransition().deriveMessageConstraintFor(curInputStateAccessor);
			messageConstraints.add((Term) messageConstraintByReference);
		}

		// Unify message constraints
		Term unifiedMessage = null;
		for (Term messageContraint: messageConstraints) {
			if (unifiedMessage == null) {
				unifiedMessage = messageContraint;
			} else {
				unifiedMessage = (Term) unifiedMessage.unify(messageContraint);
				if (unifiedMessage == null) {
					throw new UnificationFailed();
				}
			}
		}
		
		// Calculate the next state of target resource from the unified message and the current resource state
		ResourcePath targetResource = targetMember.getResource();
//		if (targetResource.getNumberOfParameters() > 0) {
//			throw new ParameterizedIdentifierIsFutureWork();
//		}
		Expression curOutputStateAccessor = stateAccessor.getCurrentStateAccessorFor(targetResource, targetResource);
		if (unifiedMessage == null) {
			// for IOChannel
			if (targetMember.getStateTransition().getMessageExpression() instanceof Term) {
				unifiedMessage = (Term) targetMember.getStateTransition().getMessageExpression();
			}
		}
		return targetMember.getStateTransition().deriveNextStateExpressionFor(curOutputStateAccessor, unifiedMessage);
	}
	
	@Override
	public String toString() {
		String channelSource = "channel " + getChannelName() + " {\n";
		for (ChannelMember inputMember: inputChannelMembers) {
			channelSource += "\t in " + inputMember + "\n";
		}
		for (ChannelMember refMember: referenceChannelMembers) {
			channelSource += "\t ref " + refMember + "\n";
		}
		for (ChannelMember outputMember: outputChannelMembers) {
			channelSource += "\t out " + outputMember + "\n";
		}
		channelSource += "}\n";
		return channelSource;
	}
	
	public interface IResourceStateAccessor {
		Expression getCurrentStateAccessorFor(ResourcePath target, ResourcePath from);
		Expression getNextStateAccessorFor(ResourcePath target, ResourcePath from);
	}
}