/*******************************************************************************
* Copyright 2012 the original author or authors.
*
* 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 emlab.trend;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.neo4j.annotation.NodeEntity;
import org.springframework.transaction.annotation.Transactional;
import agentspring.simulation.SimulationParameter;
import agentspring.trend.Trend;
import cern.jet.random.Distributions;
import cern.jet.random.engine.RandomEngine;
@NodeEntity
public class TriangularTrend implements Trend {
static final Logger logger = LoggerFactory.getLogger(TriangularTrend.class);
@SimulationParameter(label = "Minimum growth factor per time step")
private double min;
@SimulationParameter(label = "Maximum growth factor per time step")
private double max;
@SimulationParameter(label = "Expected growth factor per time step")
private double top;
private String previousValues;
private double start;
@Transactional
public double getValue(long time) {
int timeToCheck = (int) time;
// If previous values not existing, make it and put starting value in.
if (previousValues == null) {
// Empty
previousValues = "";
previousValues += getStart();
this.persist();
}
// Map existing
String[] vals = previousValues.split(",");
int lastFilled = vals.length - 1;
double[] values = null;
// Check what is bigger: what we already have or what we have to
// generate?
if (timeToCheck < lastFilled) {
values = new double[lastFilled + 1];
} else {
values = new double[timeToCheck + 1];
}
for (int i = 0; i <= lastFilled; i++) {
values[i] = Double.parseDouble(vals[i]);
}
// If value is not already existing
if (timeToCheck >= lastFilled) {
// Add new values
for (int i = lastFilled + 1; i <= timeToCheck; i++) {
double lastValue = 0;
// don't try for element -1...
if (i > 0) {
lastValue = values[i - 1];
}
double randomValue = Distributions.nextTriangular(RandomEngine.makeDefault());
double translatedValue = 0d;
if (randomValue < 0) {
translatedValue = top + (randomValue * (top - min));
} else {
translatedValue = top + (randomValue * (max - top));
}
double newValue = lastValue * translatedValue;
values[i] = newValue;
previousValues += "," + newValue;
}
this.persist();
}
return values[timeToCheck];
}
public double getMin() {
return min;
}
public void setMin(double min) {
this.min = min;
}
public double getMax() {
return max;
}
public void setMax(double max) {
this.max = max;
}
public double getTop() {
return top;
}
public void setTop(double top) {
this.top = top;
}
public double getStart() {
return start;
}
public void setStart(double start) {
this.start = start;
}
}