public class Arrival implements Serializable {
	
	//Members
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1079479343537123673L;
	private SymbolicFunction rho;
	private SymbolicFunction sigma;
	private Set<Integer> Arrivaldependencies;
	private Set<Integer> Servicedependencies;
        private Network nw; // TODO: Maybe exchange for Node/Flow
	
	//Constructors
	
	/**
	 * Creates an <code>Arrival</code> instance, with 
	 * <code>rho</code> and <code>sigma</code> being 
	 * {@link ZeroFunction}s.
     * @param nw
	 */
	public Arrival(Network nw){ 
		rho = new ConstantFunction(0);
		sigma = new ConstantFunction(0);
		Arrivaldependencies = new HashSet<>();
		Servicedependencies = new HashSet<>();
                this.nw = nw;
	}

	/**
	 * Creates an <code>Arrival</code> instance with functions 
	 * <code>rho</code> and <code>sigma</code>. 
	 * <code>thetastar</code> is deduced from the two functions.
	 * @param rho the time dependent part of the MGF-bound.
	 * @param sigma the time independent part of the MGF-bound.
     * @param nw
	 * @see SymbolicFunction
	 */
	public Arrival(SymbolicFunction sigma, SymbolicFunction rho, Network nw) {
		this.rho = rho;
		this.sigma = sigma;
		Arrivaldependencies = new HashSet<Integer>();
		Servicedependencies = new HashSet<Integer>();
                this.nw = nw;
	}
	
	/**
	 * Creates an <code>Arrival</code> instance with functions 
	 * <code>rho</code> and <code>sigma</code>.
	 * <code>thetastar</code> is deduced from the two functions.
	 * Further the arrival is dependent on the given <code>flow_id
	 * </code>. The purpose of this constructor is to easily 
	 * associate the arrival as initial arrival in a <code>Flow
	 * </code>, which is dependent on itself.
	 * @param rho the time dependent part of the MGF-bound.
	 * @param sigma the time independent part of the MGF-bound.
	 * @param flow_id id of the flow, which has this arrival as
	 * initial arrival
     * @param nw
	 * @see SymbolicFunction
	 * @see Flow
	 */
	public Arrival(SymbolicFunction sigma, SymbolicFunction rho, int flow_id, Network nw) {
		this.rho = rho;
		this.sigma = sigma;
		Arrivaldependencies = new HashSet<Integer>();
		Arrivaldependencies.add(flow_id);
		Servicedependencies = new HashSet<Integer>();
                this.nw = nw;
	}
	
	//Methods
	
	/**
	 * Adds a stochastic dependency between this instance and some 
	 * {@link Flow}.
	 * @param flow_id the flow-id, which is stochastically dependent
	 * of the instance.
	 */
	public void addArrivalDependency(int flow_id){
		Arrivaldependencies.add(flow_id);
	}
	
	/**
	 * Adds multiple stochastically dependent {@link Flow}s to the
	 * set of stochastically dependent arrivals.
	 * @param flow_ids the set of flow-ids, which are stochastically
	 * dependent of the instance.
	 */
	public void addArrivalDependency(Set<Integer> flow_ids){
		Arrivaldependencies.addAll(flow_ids);
	}
	
	/**
	 * Adds a stochastic dependency between the instance and some 
	 * {@link Vertex}.
	 * @param vertex_id the vertex-id, which is stochastically 
	 * dependent of the instance.
	 */
	public void addServiceDependency(int vertex_id){
		Servicedependencies.add(vertex_id);
	}
	
	/**
	 * Adds multiple stochastically dependent {@link Vertex} to 
	 * the set of stochastically dependent vertices.
	 * @param vertex_ids the set of vertex-ids processes, which are 
	 * stochastically dependent of the instance.
	 */
	public void addServiceDependency(Set<Integer> vertex_ids){
		Servicedependencies.addAll(vertex_ids);
	}
	
	/**
	 * The return is the evaluation of the MGF-bound at the points 
	 * <code>sigmaparameters</code> and <code>rhoparameters</code>,
	 * within the time interval (m,n].
     * @param theta
	 * @param sigmaparameters the point at which the MGF is
	 * evaluated. It has to match the number of parameters needed 
	 * to calculate sigma. The first parameter needs to be theta.
	 * @param rhoparameters the point at which the MGF is evaluated. 
	 * It has to match the number of parameters needed to calculate 
	 * rho. The first parameter needs to be theta.
	 * @param n the end of the time interval (m,n]
	 * @param m the beginning of the time interval (m,n]
	 * @return the value of the MGF at the given point
     * @throws unikl.disco.calculator.symbolic_math.ThetaOutOfBoundException
     * @throws unikl.disco.calculator.symbolic_math.ParameterMismatchException
	 * @throws ServerOverloadException 
	 */
	public double evaluate(double theta, Map<Integer, Hoelder> sigmaparameters, Map<Integer, Hoelder> rhoparameters, int n, int m)
			throws ThetaOutOfBoundException, ParameterMismatchException, ServerOverloadException {
		
		double value;
		
		try{
			value = Math.exp(theta*sigma.getValue(theta, sigmaparameters) + theta*rho.getValue(theta, rhoparameters)*(n-m));
		}
		catch (ParameterMismatchException e){
			value = Double.NaN;
			System.out.println("Parameter Mismatch Error: "+e.getMessage());
			System.out.println("Possible reasons: The network is not stable, " +
					"\ni.e. at least one node has not enough capacity to serve its arrivals.");
		}
		return value;
	}
	
    /**
     *
     * @param theta
     * @param n
     * @param m
     * @return
     * @throws ThetaOutOfBoundException
     * @throws ParameterMismatchException
     * @throws ServerOverloadException
     */
    public double evaluate(double theta, int n, int m) throws ThetaOutOfBoundException, ParameterMismatchException, ServerOverloadException{
		double value = evaluate(theta, sigma.getParameters(), rho.getParameters(), n, m);
		return value;
	}
	
	/**
	 * Returns a flow {@link arrrival}, which is the result
	 * of multiplexing <code>arrival1</code> and <code>arrival2
	 * </code>. Stochastic dependencies are taken into account.
	 * In the stochastic dependent case this leads to the 
	 * introduction of a new Hoelder-coefficient.
	 * @param arrival1 the first flow being multiplexed
	 * @param arrival2 the second flow being multiplexed 
	 * @return the multiplexed arrival
	 */
	public Arrival multiplex(Arrival arrival1, Arrival arrival2){
		
		Arrival arrival;
		
		//Dependent case
		if(!SetUtils.getIntersection(arrival1.getServicedependencies(),arrival2.getServicedependencies()).isEmpty() || !SetUtils.getIntersection(arrival1.getArrivaldependencies(), arrival2.getArrivaldependencies()).isEmpty()){
			Hoelder hoelder = nw.createHoelder();
			SymbolicFunction givensigma = new AdditiveComposition(arrival1.getSigma(),arrival2.getSigma(),hoelder);
			SymbolicFunction givenrho = new AdditiveComposition(arrival1.getRho(), arrival2.getRho(), hoelder);
			arrival = new Arrival(givensigma, givenrho, nw);
		}
		
		//Independent case
		else{
			SymbolicFunction givensigma = new AdditiveComposition(arrival1.getSigma(),arrival2.getSigma());
			SymbolicFunction givenrho = new AdditiveComposition(arrival1.getRho(), arrival2.getRho());
			arrival = new Arrival(givensigma, givenrho, nw);
		}
		
		//Keeps track of stochastic dependencies
		arrival.addArrivalDependency(arrival1.getArrivaldependencies());
		arrival.addArrivalDependency(arrival2.getArrivaldependencies());
		arrival.addServiceDependency(arrival2.getServicedependencies());
		arrival.addServiceDependency(arrival1.getServicedependencies());
		
		return arrival;
	}
	
	/**
	 * Returns the <code>output</code>, resulting from a server
	 * with some {@link service}, working on an {@link Arrival}.
	 * Stochastic dependencies are taken into account.
	 * In the stochastic dependent case this leads to the 
	 * introduction of a new Hoelder-coefficient.
	 * @param arrival the arrival being served
	 * @param service the service of the service element
	 * @return the output of the service element
	 */
	public Arrival output(Arrival arrival, Service service){
		
		Arrival output;

		//Dependent case
		if(!SetUtils.getIntersection(arrival.getServicedependencies(),service.getServicedependencies()).isEmpty() || !SetUtils.getIntersection(service.getArrivaldependencies(), arrival.getArrivaldependencies()).isEmpty()){
			Hoelder hoelder = nw.createHoelder();
			SymbolicFunction givensigma = new AdditiveComposition(new AdditiveComposition(arrival.getSigma(),service.getSigma(),hoelder),new BFunction(new AdditiveComposition(arrival.getRho(),service.getRho(),hoelder)));
			SymbolicFunction givenrho = new scaledFunction(arrival.getRho(),hoelder, false);
			output = new Arrival(givensigma, givenrho, nw);
			//System.out.println("Dependent Case Output calculated");
		}
		
		//Independent case
		else{
			SymbolicFunction givensigma = new AdditiveComposition(new AdditiveComposition(arrival.getSigma(),service.getSigma()),new BFunction(new AdditiveComposition(arrival.getRho(),service.getRho())));
			SymbolicFunction givenrho = arrival.getRho();
			output = new Arrival(givensigma, givenrho, nw);
			//System.out.println("Independent Case Output calculated");
		}
		
		//Keeps track of stochastic dependencies
		output.addArrivalDependency(arrival.getArrivaldependencies());
		output.addArrivalDependency(service.getArrivaldependencies());
		output.addServiceDependency(service.getServicedependencies());
		output.addServiceDependency(arrival.getServicedependencies());
		
		return output;
	}
	
	/**
	 * Returns a String representation of the arrival in MGF-
	 * Notation. This means, if the MGF of an arrival in an
	 * intervall (m,n] is bounded by: 
	 * <code>exp(t*f + t*g*(n-m))</code>
	 * the corresponding bound is expressed by:
	 * <code>(f,g)</code>
     * @return 
	 */
	@Override
	public String toString(){
		
		String first = sigma.toString();
		String second = rho.toString();
		
		String output = "("+first+","+second+")";
		return output;
	}
	
	//Getter and Setter
	
    /**
     *
     * @return
     */
    	
	public double getThetastar() {
		return Math.min(rho.getmaxTheta(), sigma.getmaxTheta());
	}

    /**
     *
     * @return
     */
    public SymbolicFunction getRho() {
		return rho;
	}

    /**
     *
     * @param rho
     */
    public void setRho(SymbolicFunction rho) {
		this.rho = rho;
		
	}

    /**
     *
     * @return
     */
    public SymbolicFunction getSigma() {
		return sigma;
	}

    /**
     *
     * @param sigma
     */
    public void setSigma(SymbolicFunction sigma) {
		this.sigma = sigma;
	}

    /**
     *
     * @return
     */
    public Set<Integer> getArrivaldependencies() {
		return Arrivaldependencies;
	}

    /**
     *
     * @return
     */
    public Set<Integer> getServicedependencies() {
		return Servicedependencies;
	}

}
 public class BadInitializationException extends Exception {
	/**
	 * 
	 */
	private static final long serialVersionUID = -2904109072521845677L;
	
	//Members
	
	double initvalue;
	
	//Constructor
	
    /**
     *
     * @param s
     * @param initvalue
     */
    	
	public BadInitializationException(String s, double initvalue){
		super(s);
		this.initvalue = initvalue;
	}

}
 public class AdditiveComposition extends BinaryFunction implements SymbolicFunction {
	
	//Members

	private static final long serialVersionUID = -5148906758692197626L;
	
	//Constructors
	
	/**
	 * Constructs an <code>AddedFunctions</code> entity. If 
	 * <code>independent</code> is set <code>true</code> the 
	 * independent version is constructed.
	 * If <code>independent</code> is set <code>false</code> the 
	 * stochastically dependent version is invoked by using the 
	 * next HoelderID of the {@link Analysis}-Class.
	 * In the case of stochastically dependent adding, the <code>
	 * first</code> atom-function uses the Hoelder-Coefficient p
	 * directly, while the <code>second</code> atom-function uses
	 * the corresponding coefficient given by: 1/(1-1/p)). 
	 * @param first the first atom function
	 * @param second the second atom function
	 */
	public AdditiveComposition(SymbolicFunction first, SymbolicFunction second){
	    super(first, second);
	}

	/**
	 * Constructs an <code>AddedFunctions</code> entity. If 
	 * <code>HoelderID</code> equals <code>0</code>, the 
	 * independent version is constructed.
	 * If <code>HoelderID</code> takes another value, the 
	 * stochastically dependent version is invoked with the given
	 * HoelderID.
	 * In the case of stochastically dependent adding, the <code>
	 * first</code> atom-function uses the Hoelder-Coefficient p
	 * directly, while the <code>second</code> atom-function uses
	 * the corresponding coefficient given by: 1/(1-1/p)). 
	 * @param first the first atom function
	 * @param second the second atom function
     * @param hoelder
	 * @param HoelderID determines if the stochastically dependent
	 * or independent version is invoked.
	 */
	public AdditiveComposition(SymbolicFunction first, SymbolicFunction second, Hoelder hoelder){
	    super(first, second, hoelder);
	}
	
	//Methods

	/**
	 * Calculates the value of the resulting function at theta 
	 * (first entry in <code>parameters</code>), with given 
	 * <code>parameters</code>.
     * @param theta
	 * @param parameters contains the needed parameters (including
	 * theta, as first entry) to calculate the value of the 
	 * function. Entries indexed from 1 to 
	 * {@link firstparameterIDs.size()} belong to the first atom-
	 * function, following entries to the second atom-function.
	 * @return the value of the added functions, evaluated at the
	 * given parameters.
     * @throws unikl.disco.calculator.symbolic_math.ThetaOutOfBoundException
	 * @throws ServerOverloadException 
     * @throws unikl.disco.calculator.symbolic_math.ParameterMismatchException 
	 */
	@Override
	public double getValue(double theta, Map<Integer, Hoelder> parameters)
			throws ThetaOutOfBoundException, ParameterMismatchException, ServerOverloadException {
		
		/*//Checks for a mismatch in given and needed parameters
		//1. Checks for a mismatch in the number of given and needed parameters
		if((hoelder == null && parameters.size() != SetUtils.getUnion(firstparameters.keySet(), secondparameters.keySet()).size()) 
				|| (hoelder != null && parameters.size() != SetUtils.getUnion(firstparameters.keySet(), secondparameters.keySet()).size() +1)){
			throw new ParameterMismatchException("Total number of parameters does not match for atom functions (added)");
		}

		//Constructs the parameter-arrays, which serve as input for the atom-functions
		HashMap<Integer, Hoelder> given1 = new HashMap<Integer, Hoelder>();
		HashMap<Integer, Hoelder> given2 = new HashMap<Integer, Hoelder>();
	
		for(Map.Entry<Integer, Hoelder> entry : firstparameters.entrySet()){
			// WRONG  if(parameters.containsKey(entry.getKey())) given1.put(entry.getKey(), entry.getValue());
			if(parameters.containsKey(entry.getKey())) given1.put(entry.getKey(), parameters.get(entry.getKey()));
			else throw new ParameterMismatchException("Needed hoelder_id is not found in given parameters.");
		}
		for(Map.Entry<Integer, Hoelder> entry : secondparameters.entrySet()){
			//WRONG  if(parameters.containsKey(entry.getKey())) given2.put(entry.getKey(), entry.getValue());
			if(parameters.containsKey(entry.getKey())) given2.put(entry.getKey(), parameters.get(entry.getKey()));
			else throw new ParameterMismatchException("Needed hoelder_id is not found in given parameters.");
		}
		
		//Multiplies the Hölder-coefficients to theta, if needed
		double theta1 = (hoelder == null) ? theta : theta*hoelder.getPValue();
		double theta2 = (hoelder == null) ? theta : theta*hoelder.getQValue();

		return first.getValue(theta1, given1) + second.getValue(theta2, given2);*/
	    if(checkForParameterMismatch(parameters))
		throw new ParameterMismatchException("Total number of parameters does not match for atom functions (added)");
	    
	    return (getValueOfFunction(theta, parameters, 1) + getValueOfFunction(theta, parameters, 2));
	}
	
	/**
	 * Returns an infix representation of the function. If one or 
	 * both of the atom functions are vanishing, the plus sign is 
	 * omitted.
	 * @return a String representation of the function.
	 */
	@Override
	public String toString(){
	    return (hoelder == null ? (first.toString() + " + " + second.toString()) 
		    : (first.toString()+"+_dep("+hoelder.getHoelderID()+")"+second.toString()) );
	}
}
 public abstract interface SymbolicFunction extends Serializable {

	//Methods
	
	/**
	 * Returns the value of the theta-dependent function at theta 
	 * (theta must be the first of the parameters).
     * @param theta
	 * @param parameters the set of parameters, including theta and 
	 * further parameters on which the function depends.
	 * @return the value of the theta-dependent function at theta.
     * @throws unikl.disco.calculator.symbolic_math.ThetaOutOfBoundException
     * @throws unikl.disco.calculator.symbolic_math.ParameterMismatchException
	 * @throws ServerOverloadException 
	 */
	double getValue(double theta, Map<Integer, Hoelder> parameters) throws ThetaOutOfBoundException, ParameterMismatchException, ServerOverloadException;
	
	/**
	 * Returns a string representation of the function
     * @return 
	 */
	@Override
	String toString();
		
	//Getter and Setter
	
    /**
     *
     * @return
     */
    	
	double getmaxTheta();
	
    /**
     *
     * @return
     */
    Map<Integer, Hoelder> getParameters();
	
}
 public class UnitaryMinus implements SymbolicFunction {

	//Members
	SymbolicFunction atom;
	Map<Integer,Hoelder> parameters;
	
	public UnitaryMinus(SymbolicFunction atom){
		this.atom = atom;
		parameters = atom.getParameters();
	}

	@Override
	public double getValue(double theta, Map<Integer, Hoelder> parameters)
			throws ThetaOutOfBoundException, ParameterMismatchException, ServerOverloadException {
		return -atom.getValue(theta, parameters);
	}

	@Override
	public double getmaxTheta() {
		return atom.getmaxTheta();
	}

	@Override
	public Map<Integer, Hoelder> getParameters() {
		return atom.getParameters();
	}
	
	@Override
	public String toString(){
		
		String output = "-"+atom.toString();
		
		return output;
	}

}
 public class BFunction implements SymbolicFunction {
	
	private static final long serialVersionUID = -393050275685989790L;
	SymbolicFunction exponent;
	double maxtheta;
	private Map<Integer, Hoelder> parameters;
	
	//Constructor
	
    /**
     *
     * @param exponent
     */
    	
	public BFunction(SymbolicFunction exponent){
		this.exponent = exponent;
		maxtheta = exponent.getmaxTheta();
		this.parameters = exponent.getParameters();
	}
	
	/**
	 * Calculates the value of the resulting B-function at theta 
	 * (first entry in <code>parameters</code>), with given 
	 * <code>parameters</code>.
     * @param theta
	 * @param parameters contains the needed parameters (including
	 * theta, as first entry).
	 * @return the value of the B-function
     * @throws unikl.disco.calculator.symbolic_math.ThetaOutOfBoundException
	 * @throws ParameterMismatchException 
	 */
	@Override
	public double getValue(double theta, Map<Integer, Hoelder> parameters)
			throws ThetaOutOfBoundException, ServerOverloadException, ParameterMismatchException {

		//Checks for a mismatch in number of given and needed parameters
		if(parameters.size() != this.parameters.size()){
			throw new ParameterMismatchException("Number of parameters does not match for atom function (B-Function)");
		}
		
		//Checks if argument in the logarithm is non-positive (see definition of the B-function)
		if(exponent.getValue(theta, parameters) >= 0){
			throw new ServerOverloadException("Usage of non-positive argument in log(). Argument:"+Double.toString(1-Math.exp(exponent.getValue(theta, parameters))));
		}
		
		else {
			return -1/theta*Math.log(1-Math.exp(theta*exponent.getValue(theta, parameters)));
		}
	}

	/**
	 * Returns a string representation of the B-function. In the 
	 * form <code>B(f)</code>.
     * @return 
	 */
	@Override
	public String toString(){
		
		String output = "B("+exponent.toString()+")";
		
		return output;
	}

	//Getter and SetterMaperride

    /**
     *
     * @return
     */
    	public Map<Integer, Hoelder> getParameters() {
		return parameters;
	}
	
    /**
     *
     * @return
     */
    @Override
	public double getmaxTheta(){
		return maxtheta;
	}

} public class ConstantFunction implements SymbolicFunction {

	
	private static final long serialVersionUID = 1154257189928764896L;
	private final double rate;
	private final double maxTheta;
	
    /**
     *
     * @param rate
     */
    public ConstantFunction(double rate) {
	    this.rate = rate;
	    this.maxTheta = Double.POSITIVE_INFINITY;
	}
	
	@Override
	public double getValue(double theta, Map<Integer, Hoelder> parameters) throws ParameterMismatchException {
	    if(!parameters.isEmpty()) {
		throw new ParameterMismatchException("Constant function has no Hoelder parameters");
	    }
	    return rate;
	}
	
	@Override
	public String toString(){
		return Double.toString(rate);
	}
	
    /**
     *
     * @return
     */
    @Override
	public double getmaxTheta(){
		return maxTheta;
	}

    /**
     *
     * @return
     */
    @Override
	public Map<Integer, Hoelder> getParameters() {
	    return new HashMap<>(0);
	}
	
}
 public class Hoelder implements Serializable {

	//Members
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 2169450349608663397L;
	private int hoelder_id;
	private double p_value;
	private double q_value;
	
	//Constructors
	
	/**
	 * Creates a dummy Hoelder
	 * @param hoelder_id
	 */
	public Hoelder(int hoelder_id){
		this.hoelder_id = hoelder_id;
	}
	
    /**
     *
     * @param hoelder_id
     * @param p_value
     */
    public Hoelder(int hoelder_id, double p_value){
		this.hoelder_id = hoelder_id;
		this.p_value = p_value;
		this.q_value = 1/(1-1/p_value);
	}
	
    /**
     *
     * @param hoelder_id
     * @param value
     * @param p_value
     */
    public Hoelder(int hoelder_id, double value, boolean p_value){
		this.hoelder_id = hoelder_id;
		if(p_value){
			this.p_value = value;
			this.q_value = 1/(1-1/value);
		}
		else{
			this.q_value = value;
			this.p_value = 1/(1-1/value);
		}
	}

	//Methods
	
    /**
     *
     * @return
     */
    	
	@Override
	public String toString(){
		return "p-value: "+p_value+"   q-value: "+q_value;
	}
	
	//Getter and Setter
	
    /**
     *
     * @return
     */
    	
	public int getHoelderID() {
		return hoelder_id;
	}

    /**
     *
     * @return
     */
    public double getPValue() {
		return p_value;
	}

    /**
     *
     * @param p_value
     */
    public void setPValue(double p_value) {
		this.p_value = p_value;
		this.q_value = 1/(1-1/p_value);
	}

    /**
     *
     * @return
     */
    public double getQValue() {
		return q_value;
	}

    /**
     *
     * @param q_value
     */
    public void setQValue(double q_value) {
		this.q_value = q_value;
		this.p_value = 1/(1-1/q_value);
	}
	
    /**
     *
     * @return
     */
    public Hoelder copy() {
            return new Hoelder(this.hoelder_id, this.p_value);
        }
}
 public class NewParameter implements SymbolicFunction {

	//Members
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 8098072874403146679L;
	private Hoelder hoelder;
	
	//Constructors
	
	/**
	 * A new parameter always gets a fresh parameter_id from the 
	 * {@link Analysis}-Class.
     * @param hoelder
	 */
	public NewParameter(Hoelder hoelder){
		this.hoelder = hoelder;
	}
	
	//Methods 
	
	/**
	 * Just returns the value of <code>parameters[1]</code>. The
	 * first entry in <code>parameters</code> should be theta, but
	 * is however not used. The special form of the input <code>
	 * parameters</code> is just needed to serve the overall 
	 * structure of {@link SymbolicFunction}s.
     * @param theta
	 * @param parameters an array consisting of theta (first entry)
	 * and the new parameter (second entry).
	 * @return the new parameter as given.
     * @throws unikl.disco.calculator.symbolic_math.ParameterMismatchException
	 */
	@Override
	public double getValue(double theta, Map<Integer, Hoelder> parameters) throws ParameterMismatchException{
		if(parameters.size() != 1) throw new ParameterMismatchException("NewParameter has exactly one parameter.");
		return hoelder.getPValue();
	}

	
	/**
	 * Returns a string representation of the new parameter, by:<br>
	 * <code>parameter_id</code>
	 * where <code>parameter</code> is just the parameter-id as 
	 * given by the constructor.
	 * @return a String representation of the new parameter.
	 */
	@Override
	public String toString(){
		String output = Integer.toString(hoelder.getHoelderID())+"_id";
		return output;
	}
	
    /**
     *
     * @return
     */
    @Override
	public double getmaxTheta() {
		double maxtheta = Double.POSITIVE_INFINITY;
		return maxtheta;
	}

    /**
     *
     * @return
     */
    @Override
	public Map<Integer, Hoelder> getParameters() {
		HashMap<Integer, Hoelder> parameter_ids = new  HashMap<Integer, Hoelder>(0);
		parameter_ids.put(hoelder.getHoelderID(), hoelder);
		return parameter_ids;
	}

}
 public class scaledFunction implements SymbolicFunction {
	
	//Members
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -8546822282037420484L;
	private SymbolicFunction original;
	private Hoelder hoelder;
	private boolean p_scale;
	
	//Constructors
	
	/**
	 * Constructs an <code>scaledFunction</code> entity. If 
	 * <code>p_scale</code> is set <code>true</code> the 
	 * normal scaling version is constructed, as described above.
	 * If <code>p_scale</code> is set <code>false</code> the 
	 * second part of a Hoelder-coefficient is used to scale the 
	 * atom function.
	 * This constructor gets the next HoelderID of the 
	 * {@link Analysis}-Class.
	 * @param function the atom function
	 * @param p_scale wether the first or second part of a Hoelder-
	 * coefficient should be used for scaling.
	 */
	/*public scaledFunction(SymbolicFunction function, boolean p_scale){
		this.original = function;
		this.hoelder = Network.createHoelder();
		this.p_scale = p_scale;
	}*/
	
	/**
	 * Constructs an <code>scaledFunction</code> entity. If 
	 * <code>p_scale</code> is set <code>true</code> the 
	 * normal scaling version is constructed, as described above.
	 * If <code>p_scale</code> is set <code>false</code> the 
	 * second part of a Hoelder-coefficient is used to scale the 
	 * atom function.
	 * @param function the atom function
     * @param hoelder
	 * @param p_scale wether the first or second part of a Hoelder-
	 * coefficient should be used for scaling.
	 */
	public scaledFunction(SymbolicFunction function, Hoelder hoelder, boolean p_scale){
		this.original = function;
		this.hoelder = hoelder;
		this.p_scale = p_scale;
	}
	
	//Methods
	
	/**
	 * Calculates the value of the resulting function at theta 
	 * (first entry in <code>parameters</code>), with given 
	 * <code>parameters</code>. It is important to note that the 
	 * last entry in <code>parameters</code> is the parameter, 
	 * which is used for scaling theta.
     * @param theta
	 * @param parameters contains the needed parameters (including
	 * theta, as first entry). The last entry in parameters gives
	 * the value of the Hoelder-coefficient, which is used for 
	 * scaling theta.
	 * @return the value of the scaled function.
     * @throws unikl.disco.calculator.symbolic_math.ThetaOutOfBoundException
	 * @throws ServerOverloadException 
     * @throws unikl.disco.calculator.symbolic_math.ParameterMismatchException 
	 */
	@Override
	public double getValue(double theta, Map<Integer, Hoelder> parameters)
			throws ThetaOutOfBoundException, ParameterMismatchException, ServerOverloadException {
		
		//Checks if number of given and needed parameters matches
		if(parameters.size() != original.getParameters().size()+1 && !original.getParameters().containsKey(hoelder)
				|| parameters.size() != original.getParameters().size() && original.getParameters().containsKey(hoelder)){
			throw new ParameterMismatchException("Number of parameters for scaled function does not match");
		}
		
		//Constructs the parameter-array needed for calculating the scaled atom-function
		HashMap<Integer, Hoelder> givenparameters = new HashMap<Integer, Hoelder>(0);
		
		for(Map.Entry<Integer, Hoelder> entry : original.getParameters().entrySet()){
			if(parameters.containsKey(entry.getKey())) givenparameters.put(entry.getKey(), parameters.get(entry.getKey()));
			else throw new ParameterMismatchException("Needed hoelder_id is not found in given parameters.");
		}
		
		//Scales theta
		
		if(p_scale)	theta = theta*parameters.get(hoelder.getHoelderID()).getPValue();
		else theta = theta*parameters.get(hoelder.getHoelderID()).getQValue();

		return original.getValue(theta, givenparameters);
	}

	/**
	 * Gives a String representation of the scaled function by<br>
	 * <code>scaled(f(t),scale_parameter_ID)</code><br>
     * @return 
	 */
	@Override
	public String toString(){
		if(p_scale)	return "scaled("+original.toString()+","+Integer.toString(hoelder.getHoelderID())+")";
		else return "scaled("+original.toString()+","+Integer.toString(hoelder.getHoelderID())+",q)";
	}

	//Getter and Setter
	
    /**
     *
     * @return
     */
    	
	@Override
	public double getmaxTheta() {
		if(p_scale)	return original.getmaxTheta()/hoelder.getPValue();
		else return original.getmaxTheta()/hoelder.getQValue();
	}

    /**
     *
     * @return
     */
    @Override
	public Map<Integer, Hoelder> getParameters() {
		Map<Integer, Hoelder> copy = original.getParameters();
		copy.put(hoelder.getHoelderID(), hoelder);
		return copy;
	}
	
	
}
 public class Service implements Serializable {
	
	//Members
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -3149240364532210267L;
	private double thetastar;
	private SymbolicFunction rho;
	private SymbolicFunction sigma;
	private Set<Integer> Arrivaldependencies;
	private Set<Integer> Servicedependencies;
        private Network nw; // TODO: Maybe exchange this for Node/Flow later on
	//Constructor
	
	/**
	 * Creates a <code>Service</code> instance, with  <code>rho
	 * </code> and <code>sigma</code> being the 
	 * {@link ZeroFunctions}s.
     * @param nw
	 */	
	public Service(Network nw){ 
		rho = new ConstantFunction(0);
		sigma = new ConstantFunction(0);
		thetastar = Math.min(rho.getmaxTheta(), sigma.getmaxTheta());
		Arrivaldependencies = new HashSet<Integer>();
		Servicedependencies = new HashSet<Integer>();
                this.nw = nw;
	}
	
	
	/**
	 * Creates a <code>Service</code> instance with functions 
	 * <code>rho</code> and <code>sigma</code>. 
	 * <code>thetastar</code> is deduced from the two functions.
	 * @param sigma the time independent part of the MGF-bound.
 	 * @param rho the time dependent part of the MGF-bound.
     * @param nw
	 * @see SymbolicFunction
	 */
	public Service(SymbolicFunction sigma, SymbolicFunction rho, Network nw) {
		this.rho = rho;
		this.sigma = sigma;
		thetastar = Math.min(rho.getmaxTheta(), sigma.getmaxTheta());
		Arrivaldependencies = new HashSet<Integer>();
		Servicedependencies = new HashSet<Integer>();
                this.nw = nw;
	}
	
	/**
	 * Creates a <code>Service</code> instance with functions 
	 * <code>rho</code> and <code>sigma</code>.
	 * <code>thetastar</code> is deduced from the two functions.
	 * Further the service is dependent on some <code>vertex_id
	 * </code>The purpose of this constructor is to easily 
	 * associate the service as with a vertex, which results in the
	 * service being dependent on iteself.
	 * @param sigma the time independent part of the MGF-bound
	 * @param rho the time dependent part of the MGF-bound
	 * @param vertex_id the id of the vertex, with which this
	 * service is associated.
     * @param nw
	 */
	public Service(SymbolicFunction sigma, SymbolicFunction rho, int vertex_id, Network nw) {
		this.rho = rho;
		this.sigma = sigma;
		thetastar = Math.min(rho.getmaxTheta(), sigma.getmaxTheta());
		Arrivaldependencies = new HashSet<Integer>();
		Servicedependencies = new HashSet<Integer>();
		Servicedependencies.add(vertex_id);
                this.nw = nw;
	}
	
	/**
	 * Adds a stochastic dependency between this instance and some 
	 * {@link Flow}.
	 * @param flow_id the flow-id, which is stochastically dependent
	 * of the instance.
	 */
	public void addArrivalDependency(int flow_id){
		Arrivaldependencies.add(flow_id);
	}
	
	/**
	 * Adds multiple stochastically dependent {@link Flow}s to the
	 * set of stochastically dependent arrivals.
	 * @param flow_ids the set of flow-ids, which are stochastically
	 * dependent of the instance.
	 */
	public void addArrivalDependency(Set<Integer> flow_ids){
		Arrivaldependencies.addAll(flow_ids);
	}
	
	/**
	 * Adds a stochastic dependency between the instance and some 
	 * {@link Vertex}.
	 * @param vertex_id the vertex-id, which is stochastically 
	 * dependent of the instance.
	 */
	public void addServiceDependency(int vertex_id){
		Servicedependencies.add(vertex_id);
	}
	
	/**
	 * Adds multiple stochastically dependent {@link Vertex} to 
	 * the set of stochastically dependent vertices.
	 * @param vertex_ids the set of vertex-ids processes, which are 
	 * stochastically dependent of the instance.
	 */
	public void addServiceDependency(Set<Integer> vertex_ids){
		Servicedependencies.addAll(vertex_ids);
	}
	
	/**
	 * The return is the evaluation of the MGF-bound at the points 
	 * <code>sigmaparameters</code> and <code>rhoparameters</code>,
	 * within the time interval (m,n].
     * @param theta
	 * @param sigmaparameters the point at which the MGF is
	 * evaluated. It has to match the number of parameters needed 
	 * to calculate sigma. The first parameter needs to be theta.
	 * @param rhoparameters the point at which the MGF is evaluated. 
	 * It has to match the number of parameters needed to calculate 
	 * rho. The first parameter needs to be theta.
	 * @param n the end of the time interval (m,n]
	 * @param m the beginning of the time interval (m,n]
	 * @return the value of the MGF at the given point
     * @throws unikl.disco.calculator.symbolic_math.ThetaOutOfBoundException
	 * @throws ServerOverloadException 
     * @throws unikl.disco.calculator.symbolic_math.ParameterMismatchException 
	 */
	public double evaluate(double theta, HashMap<Integer, Hoelder> sigmaparameters, HashMap<Integer, Hoelder> rhoparameters, int n, int m)
			throws ThetaOutOfBoundException, ParameterMismatchException, ServerOverloadException {
		double value = Math.exp(theta*sigma.getValue(theta, sigmaparameters) + theta*rho.getValue(theta, rhoparameters)*(n-m));
		return value;
	}
	
	/**
	 * Returns the <code>Service</code>, which is the result
	 * of concatenating <code>service1</code> with <code>service2
	 * </code>. Stochastic dependencies are taken into account.
	 * In the stochastic dependent case this leads to the 
	 * introduction of a new Hoelder-coefficient.
	 * @param service1 the first flow being multiplexed
	 * @param service2 the second flow being multiplexed 
	 * @return the multiplexed arrival
	 */
	public Service concatenate(Service service1, Service service2){
		Service service;
		
		//Dependent Case
		if(!SetUtils.getIntersection(service1.getServicedependencies(),service2.getServicedependencies()).isEmpty() || !SetUtils.getIntersection(service1.getArrivaldependencies(), service2.getArrivaldependencies()).isEmpty()){
			Hoelder hoelder = nw.createHoelder();
			SymbolicFunction givensigma = new AdditiveComposition(new AdditiveComposition(service1.getSigma(),service2.getSigma(),hoelder),new BFunction(new NegativeAbsoluteDifference(service1.getRho(),service2.getRho(),hoelder)));
			SymbolicFunction givenrho = new MaximumFunction(service1.getRho(), service2.getRho(), hoelder);
			service = new Service(givensigma, givenrho, nw);
		}
		
		//Independent Case
		else{
			SymbolicFunction givensigma = new AdditiveComposition(new AdditiveComposition(service1.getSigma(),service2.getSigma()),new BFunction(new NegativeAbsoluteDifference(service1.getRho(),service2.getRho())));
			SymbolicFunction givenrho = new MaximumFunction(service1.getRho(), service2.getRho());
			service = new Service(givensigma, givenrho, nw);
		}
		
		//Keeps track of stochastic dependencies
		service.addArrivalDependency(service1.getArrivaldependencies());
		service.addArrivalDependency(service2.getArrivaldependencies());
		service.addServiceDependency(service2.getServicedependencies());
		service.addServiceDependency(service1.getServicedependencies());
		
		return service;
	}
	
	/**
	 * Returns the leftover-<code>service</code>, resulting from a 
	 * server with some <code>Service</code>, working on an 
	 * {@link Arrival}. Stochastic dependencies are taken into 
	 * account. 
	 * In the stochastic dependent case this leads to the 
	 * introduction of a new Hoelder-coefficient.
	 * @param arrival the arrival being served
	 * @param service the service of the service element
	 * @return the leftover service of the service element
	 */
	public Service leftover(Arrival arrival, Service service){
		Service leftoverservice;

		//Dependent CaseedFunctions
		if(!SetUtils.getIntersection(arrival.getServicedependencies(),service.getServicedependencies()).isEmpty() || !SetUtils.getIntersection(service.getArrivaldependencies(), arrival.getArrivaldependencies()).isEmpty()){
			Hoelder hoelder = nw.createHoelder();
			SymbolicFunction givensigma = new AdditiveComposition(arrival.getSigma(),service.getSigma(),hoelder);
			SymbolicFunction givenrho = new AdditiveComposition(arrival.getRho(),service.getRho(),hoelder);
			leftoverservice = new Service(givensigma, givenrho, nw);
			System.out.println("Dependent Case Leftover calculated");
		}
		
		//Independent Case
		else{
			SymbolicFunction givensigma = new AdditiveComposition(arrival.getSigma(),service.getSigma());
			SymbolicFunction givenrho = new AdditiveComposition(arrival.getRho(),service.getRho());
			leftoverservice = new Service(givensigma, givenrho, nw);
			System.out.println("Independent Case Leftover calculated");
		}
		
		//Keeps track of stochastic dependencies
		leftoverservice.addArrivalDependency(arrival.getArrivaldependencies());
		leftoverservice.addServiceDependency(service.getServicedependencies());
		leftoverservice.addArrivalDependency(service.getArrivaldependencies());
		leftoverservice.addServiceDependency(arrival.getServicedependencies());
		
		return leftoverservice;
	}
	
	/**
	 * Returns a String representation of the service in MGF-
	 * Notation. This means, if the MGF of a service in an
	 * interval (m,n] is bounded by: 
	 * <code>exp(t*f + t*g*(n-m))</code>
	 * the corresponding bound is expressed by:
	 * <code>(f,g)</code>
     * @return 
	 */
	@Override
	public String toString(){
		String first = sigma.toString();
		String second = rho.toString();
		String output = "("+first+","+second+")";
		return output;
	}
	
	//Getter and Setter
	
    /**
     *
     * @return
     */
    	
	public double getThetastar() {
		return thetastar;
	}

    /**
     *
     * @return
     */
    public SymbolicFunction getRho() {
		return rho;
	}

    /**
     *
     * @param rho
     */
    public void setRho(SymbolicFunction rho) {
		this.rho = rho;
		thetastar = Math.min(rho.getmaxTheta(), sigma.getmaxTheta());
	}

    /**
     *
     * @return
     */
    public SymbolicFunction getSigma() {
		return sigma;
	}

    /**
     *
     * @param sigma
     */
    public void setSigma(SymbolicFunction sigma) {
		this.sigma = sigma;
		thetastar = Math.min(rho.getmaxTheta(), sigma.getmaxTheta());
	}

    /**
     *
     * @return
     */
    public Set<Integer> getArrivaldependencies() {
		return Arrivaldependencies;
	}

    /**
     *
     * @return
     */
    public Set<Integer> getServicedependencies() {
		return Servicedependencies;
	}

} public class AnalysisException extends RuntimeException {
    public AnalysisException(Exception e) {
        super(e);
    }
    
    public AnalysisException(String message) {
        super(message);
    }
    
} public class SetUtils {
	/**
	 * Returns the set difference between the set <code>s1</code> and the set <code>s2</code>.
	 * @param s1
	 * @param s2
	 * @return the difference set
	 */
    public static <T> Set<T> getDifference(Set<T> s1, Set<T> s2) {
    	Set<T> result = new HashSet<T>(s1);
    	result.removeAll(s2);
    	return result;
    }
    
    /**
     * Returns the intersection of set <code>s1</code> and set <code>s2</code>.
     * @param s1 a set
     * @param s2 another set
     * @return the intersection set
     */
    public static <T> Set<T> getIntersection(Set<T> s1, Set<T> s2) {
		if(s1==null || s2==null)
			return new HashSet<T>();

    	Set<T> result = new HashSet<T>(s1);
    	result.retainAll(s2);
    	return result;
    }
    
    /**
     * Returns the intersection of all sets contained in the list <code>sets</code>.
     * @param sets a list of sets
     * @return the intersection of all sets
     */
    public static <T> Set<T> getIntersection(List<Set<T>> sets) {
    	Set<T> result = new HashSet<T>();    	
    	Iterator<Set<T>> iter = sets.iterator();
    	if (iter.hasNext()) {
    		result.addAll(iter.next());
        	for (; iter.hasNext(); ) {
        		result.retainAll(iter.next());
        	}    		
    	}
    	return result;
    }

    /**
     * Returns the union of set <code>s1</code> and set <code>s2</code>.
     * @param s1 a set
     * @param s2 another set
     * @return the union set
     */
    public static <T> Set<T> getUnion(Set<T> s1, Set<T> s2) {
    	Set<T> result = new HashSet<T>(s1);
   		result.addAll(s2);
    	return result;
    }
    
    /**
     * Returns the union of all sets contained in the list <code>sets</code>.
     * @param sets a list of sets
     * @return the union of all sets
     */
    public static <T> Set<T> getUnion(List<Set<T>> sets) {
    	Set<T> result = new HashSet<T>();
    	for(Set<T> set : sets) {
    		result.addAll(set);
    	}
    	return result;
    }
    
    /**
     * Creates a map containing each element of the <code>Set set</code> as key
     * and the <coded>Object value</code> as corresponding value.
     * @param set the set whose elements will be the keys of entries in the map
     * @param value the value of each of the map's entries
     * @return a map
     */
//    public static Map createMap(Set set, Object value) {
//    	Map map = new HashMap(set.size());
//    	for (Iterator iter = set.iterator(); iter.hasNext(); ) {
//    		map.put(iter.next(), value);
//    	}
//    	return map;
//    }
}

import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import unikl.disco.calculator.symbolic_math.Arrival;
import unikl.disco.calculator.symbolic_math.BadInitializationException;
import unikl.disco.calculator.symbolic_math.AdditiveComposition;
import unikl.disco.calculator.symbolic_math.SymbolicFunction;
import unikl.disco.calculator.symbolic_math.UnitaryMinus;
import unikl.disco.calculator.symbolic_math.functions.BFunction;
import unikl.disco.calculator.symbolic_math.functions.ConstantFunction;
import unikl.disco.calculator.symbolic_math.Hoelder;
import unikl.disco.calculator.symbolic_math.NewParameter;
import unikl.disco.calculator.symbolic_math.functions.scaledFunction;
import unikl.disco.calculator.symbolic_math.Service;
import unikl.disco.misc.AnalysisException;
import unikl.disco.misc.SetUtils;

    }

    /**
     * Helper function for {@link analysis()}. It takes the FoI and above
     * information to calculate end to end performance bounds. Stochastic
     * dependencies are taken into account and might increase the number of
     * Hoelder-coefficients.
     *
     * @param arrival the {@link Arrival}-description of the FoI
     * @param service the {@link Service}-description of the SoI
     * @return the bound in the {@link Arrival}-description
     * @throws BadInitializationException
     */
    //TODO:(Michael) Get Arrival representation for the delay- (backlog-, and output-)bound. 
    private Arrival calculateBound(Arrival arrival, List<Service> leftover_services, Arrival aggregated_through) {

        Arrival result;

        //The result is dependent on the wished performance-bound
        switch (getBoundtype()) {
            //TODO:(Michael) Update this to end-to-end
            case BACKLOG:
                System.out.println("Ladder Analysis for output-bound not implemented, yet.");
                result = new Arrival(nw);
                break;

            case DELAY:

                //TODO: This dependent case needs thorough testing! Not recommended to use before that.
                //the sigma and rho of the bound:
                /*SymbolicFunction sigma;
			SymbolicFunction rho;
			
			//Intermediate sigmas and rhos used to construct above
			SymbolicFunction sigma_A;
			
			SymbolicFunction rho_agg = aggregated_through.getRho();
			SymbolicFunction sigma_agg = aggregated_through.getSigma();
			
			
			//Preparations to process dependencies
			List<Set<Integer>> agg_and_lo_arrival = new ArrayList<Set<Integer>>();
			agg_and_lo_arrival.add(aggregated_through.getArrivaldependencies());		
			List<Set<Integer>> agg_and_lo_service = new ArrayList<Set<Integer>>();
			agg_and_lo_service.add(aggregated_through.getServicedependencies());
			
			List<Set<Integer>> lo_arrival = new ArrayList<Set<Integer>>();
			List<Set<Integer>> lo_service = new ArrayList<Set<Integer>>();
			List<Set<Integer>> reduced_lo_arrival = new ArrayList<Set<Integer>>();
			List<Set<Integer>> reduced_lo_service = new ArrayList<Set<Integer>>();
			
			for(Service leftover_service : leftover_services){
				agg_and_lo_arrival.add(leftover_service.getArrivaldependencies());
				agg_and_lo_service.add(leftover_service.getServicedependencies());
				
				lo_arrival.add(leftover_service.getArrivaldependencies());
				lo_service.add(leftover_service.getServicedependencies());
				reduced_lo_arrival.add(leftover_service.getArrivaldependencies());
				reduced_lo_service.add(leftover_service.getServicedependencies());
			}
			//Processing of dependencies: Hoelder parameters are introduced for each dependency encountered.
			//Splitting off the flow of interest from the calculations
			if(!SetUtils.getIntersection(arrival.getArrivaldependencies(),SetUtils.getUnion(agg_and_lo_arrival)).isEmpty() 
					|| !SetUtils.getIntersection(arrival.getServicedependencies(),SetUtils.getUnion(agg_and_lo_service)).isEmpty())
					{
				Hoelder hoelder = nw.createHoelder();
				rho = new UnitaryMinus(new scaledFunction(arrival.getRho(),hoelder,true));
				sigma_A = new scaledFunction(arrival.getSigma(),hoelder,true);
				
				rho_agg = new scaledFunction(aggregated_through.getRho(),hoelder,false);
				sigma_agg = new scaledFunction(aggregated_through.getSigma(),hoelder,false);
				for(Service leftover_service : leftover_services){
					leftover_service.setRho(new scaledFunction(leftover_service.getRho(),hoelder,false));
					leftover_service.setSigma(new scaledFunction(leftover_service.getSigma(),hoelder,false));
				}
			}
			else{
				rho = new UnitaryMinus(arrival.getRho());
				sigma_A = arrival.getSigma();
			}
			//Splitting off the aggregated through-flow from the calculations
			if(!SetUtils.getIntersection(aggregated_through.getArrivaldependencies(), SetUtils.getUnion(lo_arrival)).isEmpty()
					|| !SetUtils.getIntersection(aggregated_through.getArrivaldependencies(), SetUtils.getUnion(lo_service)).isEmpty()){
				Hoelder hoelder = nw.createHoelder();
				rho_agg = new scaledFunction(rho_agg,hoelder,true);
				sigma_agg = new scaledFunction(sigma_agg,hoelder,true);
				
				for(Service leftover_service : leftover_services){
					leftover_service.setRho(new scaledFunction(leftover_service.getRho(),hoelder,false));
					leftover_service.setSigma(new scaledFunction(leftover_service.getSigma(),hoelder,false));
				}
			}
			//Splitting off each leftover service from the calculations
			List<Service> sublist_leftover_services = leftover_services.subList(1, leftover_services.size()); 
			for(Service leftover_service : leftover_services){
				reduced_lo_arrival.remove(leftover_service.getArrivaldependencies());
				reduced_lo_service.remove(leftover_service.getServicedependencies());
				if(!SetUtils.getIntersection(leftover_service.getArrivaldependencies(), SetUtils.getUnion(reduced_lo_arrival)).isEmpty()
					||	!SetUtils.getIntersection(leftover_service.getServicedependencies(), SetUtils.getUnion(reduced_lo_service)).isEmpty()){
					Hoelder hoelder = nw.createHoelder();
					leftover_service.setRho(new scaledFunction(leftover_service.getRho(),hoelder,true));
					leftover_service.setSigma(new scaledFunction(leftover_service.getSigma(),hoelder,true));
					for(Service other_service : sublist_leftover_services){
						other_service.setRho(new scaledFunction(other_service.getRho(),hoelder,false));
						other_service.setSigma(new scaledFunction(other_service.getSigma(),hoelder,false));
					}
					sublist_leftover_services = sublist_leftover_services.subList(1,sublist_leftover_services.size());
				}
			}*/
                //INDEPENDENT CASE
                SymbolicFunction rho = new UnitaryMinus(arrival.getRho());
                SymbolicFunction sigma = arrival.getSigma();
                SymbolicFunction rho_through_total = arrival.getRho();
                if(aggregated_through != null){
                	sigma = new AdditiveComposition(arrival.getSigma(), aggregated_through.getSigma());
                	rho_through_total = new AdditiveComposition(arrival.getRho(), aggregated_through.getRho());
                }
                
                for (Service leftover_service : leftover_services) {
                    sigma = new AdditiveComposition(sigma, leftover_service.getSigma());

                    sigma = new AdditiveComposition(sigma, new BFunction(new AdditiveComposition(leftover_service.getRho(), rho_through_total)));
