From 65fa782b10b272fb93462621dc1b97c07f317170 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Fri, 28 May 2021 12:22:14 +0400 Subject: [PATCH] create full brutforce over parameters --- .../controllers/TimeSeriesController.java | 21 ++- .../java/ru/ulstu/models/ModelingResult.java | 22 +++- src/main/java/ru/ulstu/models/Score.java | 14 ++ src/main/java/ru/ulstu/score/ScoreMethod.java | 35 ++++- src/main/java/ru/ulstu/score/Smape.java | 33 +++++ .../ulstu/services/MethodParamBruteForce.java | 122 ++++++++++++++---- .../ru/ulstu/services/TimeSeriesService.java | 23 +--- .../ru/ulstu/tsMethods/MethodParameter.java | 30 +++++ .../ru/ulstu/tsMethods/TimeSeriesMethod.java | 27 ++-- .../tsMethods/TimeSeriesMethodParamValue.java | 27 ++++ .../exponential/AddTrendAddSeason.java | 70 +++++++--- .../exponential/AddTrendNoSeason.java | 51 ++++++-- .../exponential/NoTrendNoSeason.java | 25 ++-- .../{param => parameter}/Alpha.java | 8 +- .../{param => parameter}/Beta.java | 8 +- .../ExponentialMethodParamValue.java | 4 +- .../ExponentialMethodParameter.java} | 33 +++-- .../{param => parameter}/Gamma.java | 8 +- .../{param => parameter}/Season.java | 8 +- 19 files changed, 458 insertions(+), 111 deletions(-) create mode 100644 src/main/java/ru/ulstu/score/Smape.java create mode 100644 src/main/java/ru/ulstu/tsMethods/MethodParameter.java create mode 100644 src/main/java/ru/ulstu/tsMethods/TimeSeriesMethodParamValue.java rename src/main/java/ru/ulstu/tsMethods/exponential/{param => parameter}/Alpha.java (58%) rename src/main/java/ru/ulstu/tsMethods/exponential/{param => parameter}/Beta.java (58%) rename src/main/java/ru/ulstu/tsMethods/exponential/{param => parameter}/ExponentialMethodParamValue.java (91%) rename src/main/java/ru/ulstu/tsMethods/exponential/{param/ExponentialMethodParam.java => parameter/ExponentialMethodParameter.java} (52%) rename src/main/java/ru/ulstu/tsMethods/exponential/{param => parameter}/Gamma.java (58%) rename src/main/java/ru/ulstu/tsMethods/exponential/{param => parameter}/Season.java (65%) diff --git a/src/main/java/ru/ulstu/controllers/TimeSeriesController.java b/src/main/java/ru/ulstu/controllers/TimeSeriesController.java index 889a9ee..a8defd5 100644 --- a/src/main/java/ru/ulstu/controllers/TimeSeriesController.java +++ b/src/main/java/ru/ulstu/controllers/TimeSeriesController.java @@ -1,3 +1,11 @@ +/* + * + * * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + * + */ + package ru.ulstu.controllers; import io.swagger.annotations.ApiOperation; @@ -9,8 +17,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import ru.ulstu.configuration.ApiConfiguration; import ru.ulstu.models.ForecastParams; +import ru.ulstu.models.ModelingResult; import ru.ulstu.models.TimeSeries; import ru.ulstu.models.exceptions.ModelingException; +import ru.ulstu.services.MethodParamBruteForce; import ru.ulstu.services.TimeSeriesService; @RestController @@ -18,9 +28,12 @@ import ru.ulstu.services.TimeSeriesService; public class TimeSeriesController { private final TimeSeriesService timeSeriesService; + private final MethodParamBruteForce methodParamBruteForce; - public TimeSeriesController(TimeSeriesService timeSeriesService) { + public TimeSeriesController(TimeSeriesService timeSeriesService, + MethodParamBruteForce methodParamBruteForce) { this.timeSeriesService = timeSeriesService; + this.methodParamBruteForce = methodParamBruteForce; } @PostMapping("getForecast") @@ -29,4 +42,10 @@ public class TimeSeriesController { return new ResponseEntity<>(timeSeriesService.getForecast(forecastParams.getOriginalTimeSeries(), forecastParams.getCountForecast()), HttpStatus.OK); } + + @PostMapping("getSmoothed") + @ApiOperation("Получить сглаженный временной ряд") + public ResponseEntity getSmoothedTimeSeries(@RequestBody TimeSeries timeSeries) throws ModelingException { + return new ResponseEntity<>(methodParamBruteForce.getSmoothedTimeSeries(timeSeries), HttpStatus.OK); + } } diff --git a/src/main/java/ru/ulstu/models/ModelingResult.java b/src/main/java/ru/ulstu/models/ModelingResult.java index 7bd33a8..0b7de01 100644 --- a/src/main/java/ru/ulstu/models/ModelingResult.java +++ b/src/main/java/ru/ulstu/models/ModelingResult.java @@ -1,6 +1,15 @@ +/* + * + * * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + * + */ + package ru.ulstu.models; -import ru.ulstu.tsMethods.exponential.param.TimeSeriesMethodParamValue; +import ru.ulstu.tsMethods.TimeSeriesMethod; +import ru.ulstu.tsMethods.TimeSeriesMethodParamValue; import java.util.List; @@ -8,11 +17,16 @@ public class ModelingResult { private final TimeSeries timeSeries; private final List paramValues; private final Score score; + private final TimeSeriesMethod timeSeriesMethod; - public ModelingResult(TimeSeries timeSeries, List paramValues, Score score) { + public ModelingResult(TimeSeries timeSeries, + List paramValues, + Score score, + TimeSeriesMethod timeSeriesMethod) { this.timeSeries = timeSeries; this.paramValues = paramValues; this.score = score; + this.timeSeriesMethod = timeSeriesMethod; } public TimeSeries getTimeSeries() { @@ -26,4 +40,8 @@ public class ModelingResult { public Score getScore() { return score; } + + public TimeSeriesMethod getTimeSeriesMethod() { + return timeSeriesMethod; + } } diff --git a/src/main/java/ru/ulstu/models/Score.java b/src/main/java/ru/ulstu/models/Score.java index c48645b..2c95769 100644 --- a/src/main/java/ru/ulstu/models/Score.java +++ b/src/main/java/ru/ulstu/models/Score.java @@ -1,5 +1,14 @@ +/* + * + * * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + * + */ + package ru.ulstu.models; +import com.fasterxml.jackson.annotation.JsonIgnore; import ru.ulstu.score.ScoreMethod; public class Score { @@ -18,4 +27,9 @@ public class Score { public Number getValue() { return value; } + + @JsonIgnore + public Double getDoubleValue() { + return value.doubleValue(); + } } diff --git a/src/main/java/ru/ulstu/score/ScoreMethod.java b/src/main/java/ru/ulstu/score/ScoreMethod.java index b3d1aad..69301d3 100644 --- a/src/main/java/ru/ulstu/score/ScoreMethod.java +++ b/src/main/java/ru/ulstu/score/ScoreMethod.java @@ -1,7 +1,40 @@ +/* + * + * * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + * + */ + package ru.ulstu.score; +import ru.ulstu.models.Score; import ru.ulstu.models.TimeSeries; +import ru.ulstu.models.TimeSeriesValue; +import ru.ulstu.models.exceptions.ModelingException; public abstract class ScoreMethod { - public abstract Number evaluate(TimeSeries originalTimeSeries, TimeSeries modelTimeSeries); + private final String name; + + public ScoreMethod(String name) { + this.name = name; + } + + public Score getScore(TimeSeries original, TimeSeries model) throws ModelingException { + return new Score(this, evaluate(original, model)); + } + + public abstract Number evaluate(TimeSeries original, TimeSeries model) throws ModelingException; + + public String getName() { + return name; + } + + protected TimeSeriesValue getValueOnSameDate(TimeSeriesValue timeSeriesValueToFind, TimeSeries timeSeries) throws ModelingException { + return timeSeries.getValues() + .stream() + .filter(v -> v.getDate().equals(timeSeriesValueToFind.getDate())) + .findAny() + .orElseThrow(() -> new ModelingException("Значение модельного ряда не найдено в оригинальном ряде: " + timeSeriesValueToFind.getDate())); + } } diff --git a/src/main/java/ru/ulstu/score/Smape.java b/src/main/java/ru/ulstu/score/Smape.java new file mode 100644 index 0000000..cf8eb24 --- /dev/null +++ b/src/main/java/ru/ulstu/score/Smape.java @@ -0,0 +1,33 @@ +/* + * + * * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + * + */ + +package ru.ulstu.score; + +import ru.ulstu.models.TimeSeries; +import ru.ulstu.models.TimeSeriesValue; +import ru.ulstu.models.exceptions.ModelingException; + +import static java.lang.Math.abs; + +public class Smape extends ScoreMethod { + public Smape() { + super("Smape"); + } + + @Override + public Number evaluate(TimeSeries original, TimeSeries model) throws ModelingException { + double sum = 0; + for (TimeSeriesValue modelValue : model.getValues()) { + double actualValue = getValueOnSameDate(modelValue, original).getValue(); + sum += abs(modelValue.getValue() - actualValue) + / ((abs(actualValue) + abs(modelValue.getValue())) / 2); + } + sum = Math.round(sum * 100) / 100; + return sum * 100 / model.getLength(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/ulstu/services/MethodParamBruteForce.java b/src/main/java/ru/ulstu/services/MethodParamBruteForce.java index 30692dd..d9a6406 100644 --- a/src/main/java/ru/ulstu/services/MethodParamBruteForce.java +++ b/src/main/java/ru/ulstu/services/MethodParamBruteForce.java @@ -1,60 +1,138 @@ +/* + * + * * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + * + */ + package ru.ulstu.services; import org.springframework.stereotype.Service; import ru.ulstu.models.ModelingResult; import ru.ulstu.models.TimeSeries; +import ru.ulstu.models.exceptions.ModelingException; +import ru.ulstu.score.ScoreMethod; +import ru.ulstu.score.Smape; +import ru.ulstu.tsMethods.MethodParameter; import ru.ulstu.tsMethods.TimeSeriesMethod; -import ru.ulstu.tsMethods.exponential.param.TimeSeriesMethodParam; -import ru.ulstu.tsMethods.exponential.param.TimeSeriesMethodParamValue; +import ru.ulstu.tsMethods.TimeSeriesMethodParamValue; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; @Service public class MethodParamBruteForce { + private final int DEFAULT_THREAD_COUNT = 10; private final List methods; - private ExecutorService executors = Executors.newFixedThreadPool(10); + private final ScoreMethod scoreMethod = new Smape(); + private final ExecutorService executors = Executors.newFixedThreadPool(DEFAULT_THREAD_COUNT); public MethodParamBruteForce(List methods) { this.methods = methods; } public TimeSeries getForecast(TimeSeries timeSeries) { - + throw new RuntimeException("Not implemented"); } public TimeSeries getForecastWithOptimalLength(TimeSeries timeSeries) { - + throw new RuntimeException("Not implemented"); } - public TimeSeries getSmoothedTimeSeries(TimeSeries timeSeries) { - List> results = new ArrayList<>(); + public ModelingResult getSmoothedTimeSeries(TimeSeries timeSeries) throws ModelingException { + //List> results = new ArrayList<>(); + List results2 = new CopyOnWriteArrayList<>(); for (TimeSeriesMethod method : methods) { - List availableParams = method.getAvailableParams(); - Map> paramsAvailableValues = new HashMap<>(); - for (TimeSeriesMethodParam param : availableParams) { - paramsAvailableValues.put(param, param.getAvailableValues()); + List> availableParametersValues = getAvailableParametersValues(method.getAvailableParameters()); + for (List parametersValues : availableParametersValues) { + /*results.add(executors.submit(() -> { + TimeSeries model = method.createFor(timeSeries) + .setAvailableParameters(parametersValues) + .getModel(); + return new ModelingResult(model, parametersValues, scoreMethod.getScore(timeSeries, model)); + }));*/ + + TimeSeries model = method.createFor(timeSeries) + .setAvailableParameters(parametersValues) + .getModel(); + results2.add(new ModelingResult(model, + parametersValues, + scoreMethod.getScore(timeSeries, model), + method)); } - List paramValues = new ArrayList<>(); - results.add(executors.submit(() -> { - return new ModelingResult(method.getModel(), - method.createFor(timeSeries) - .setAvailableParams(paramValues) - .getModel()); - })); } - TimeSeries result = null; try { - result = results.get(0).get(); + /*results.forEach(modelingResultFuture -> { + try { + modelingResultFuture.get(); + } catch (Exception e) { + e.printStackTrace(); + } + }); + for (Future futureModelingResult: results) { + results2.add(futureModelingResult.get()); + }*/ + return results2.stream() + .min(Comparator.comparing(modelingResult -> modelingResult.getScore().getDoubleValue())) + .orElse(null); } catch (Exception e) { e.printStackTrace(); } + return null; + } + private List> getAvailableParametersValues(List availableParameters) { + List> result = new ArrayList<>(); + Map parameterOffset = new TreeMap<>(); + Map> parameterValues = new TreeMap<>(); + for (MethodParameter methodParameter : availableParameters) { + parameterOffset.put(methodParameter, 0); + parameterValues.put(methodParameter, methodParameter.getAvailableValues()); + } + while (!isAllValuesUsed(parameterOffset, parameterValues)) { + List resultRow = new ArrayList<>(); + for (MethodParameter methodParameter : parameterOffset.keySet()) { + resultRow.add(new TimeSeriesMethodParamValue(methodParameter, + parameterValues.get(methodParameter).get(parameterOffset.get(methodParameter)))); + } + incrementOffset(parameterOffset, parameterValues); + result.add(resultRow); + } return result; } + + private void incrementOffset(Map parameterOffset, + Map> parameterValues) { + List parameters = new ArrayList<>(parameterOffset.keySet()); + int i = 0; + while (i < parameters.size() && !isAllValuesUsed(parameterOffset, parameterValues)) { + if (parameterOffset.get(parameters.get(i)) == parameterValues.get(parameters.get(i)).size() - 1) { + parameterOffset.put(parameters.get(i), 0); + i++; + //continue; + } + if (parameterOffset.get(parameters.get(i)) < parameterValues.get(parameters.get(i)).size()) { + parameterOffset.put(parameters.get(i), parameterOffset.get(parameters.get(i)) + 1); + return; + } + i++; + } + } + + private boolean isAllValuesUsed(Map parameterOffset, + Map> parameterValues) { + for (MethodParameter methodParameter : parameterOffset.keySet()) { + if (parameterOffset.get(methodParameter) != parameterValues.get(methodParameter).size() - 1) { + return false; + } + } + return true; + } } diff --git a/src/main/java/ru/ulstu/services/TimeSeriesService.java b/src/main/java/ru/ulstu/services/TimeSeriesService.java index 06134b6..5c34d3e 100644 --- a/src/main/java/ru/ulstu/services/TimeSeriesService.java +++ b/src/main/java/ru/ulstu/services/TimeSeriesService.java @@ -16,11 +16,8 @@ import ru.ulstu.models.exceptions.ModelingException; import ru.ulstu.tsMethods.TimeSeriesMethod; import ru.ulstu.tsMethods.exponential.AddTrendAddSeason; import ru.ulstu.tsMethods.exponential.NoTrendNoSeason; -import ru.ulstu.tsMethods.exponential.param.Alpha; -import ru.ulstu.tsMethods.exponential.param.Beta; -import ru.ulstu.tsMethods.exponential.param.ExponentialMethodParamValue; -import ru.ulstu.tsMethods.exponential.param.Gamma; -import ru.ulstu.tsMethods.exponential.param.Season; +import ru.ulstu.tsMethods.exponential.parameter.Alpha; +import ru.ulstu.tsMethods.exponential.parameter.ExponentialMethodParamValue; @Service @@ -29,24 +26,16 @@ public class TimeSeriesService { public TimeSeries getForecast(TimeSeries timeSeries, int countPoints) throws ModelingException { TimeSeriesMethod method; - method = new NoTrendNoSeason(timeSeries, new ExponentialMethodParamValue<>(new Alpha(), 0.8)); - method = new AddTrendAddSeason(timeSeries, - new ExponentialMethodParamValue<>(new Alpha(), 0.5), - new ExponentialMethodParamValue<>(new Beta(), 0.5), - new ExponentialMethodParamValue<>(new Gamma(), 0.5), - new ExponentialMethodParamValue<>(new Season(), 17)); + method = new NoTrendNoSeason().createFor(timeSeries).setAlpha(new ExponentialMethodParamValue<>(new Alpha(), 0.8)); + method = new AddTrendAddSeason().createFor(timeSeries); return method.getForecast(countPoints); } public TimeSeries smoothTimeSeries(TimeSeries timeSeries) throws ModelingException { //NoTrendNoSeason nn = new NoTrendNoSeason(timeSeries, ExponentialMethodParams.of(ExponentialParamName.ALPHA, 0.8)); TimeSeriesMethod method; - method = new NoTrendNoSeason(timeSeries, new ExponentialMethodParamValue<>(new Alpha(), 0.8)); - method = new AddTrendAddSeason(timeSeries, - new ExponentialMethodParamValue<>(new Alpha(), 0.5), - new ExponentialMethodParamValue<>(new Beta(), 0.5), - new ExponentialMethodParamValue<>(new Gamma(), 0.5), - new ExponentialMethodParamValue<>(new Season(), 17)); + method = new NoTrendNoSeason().createFor(timeSeries); + method = new AddTrendAddSeason().createFor(timeSeries); return method.getModel(); } } diff --git a/src/main/java/ru/ulstu/tsMethods/MethodParameter.java b/src/main/java/ru/ulstu/tsMethods/MethodParameter.java new file mode 100644 index 0000000..874637f --- /dev/null +++ b/src/main/java/ru/ulstu/tsMethods/MethodParameter.java @@ -0,0 +1,30 @@ +/* + * + * * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + * + */ + +package ru.ulstu.tsMethods; + +import java.util.List; + +public abstract class MethodParameter implements Comparable { + protected String name; + + public MethodParameter(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public abstract List getAvailableValues(); + + @Override + public int compareTo(Object o) { + return this.name.compareTo(((MethodParameter) o).getName()); + } +} diff --git a/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethod.java b/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethod.java index 2b69512..7a38b6e 100644 --- a/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethod.java +++ b/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethod.java @@ -1,22 +1,31 @@ +/* + * + * * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + * + */ + package ru.ulstu.tsMethods; +import com.fasterxml.jackson.annotation.JsonIgnore; import ru.ulstu.TimeSeriesUtils; import ru.ulstu.models.TimeSeries; import ru.ulstu.models.TimeSeriesValue; import ru.ulstu.models.exceptions.ForecastValidateException; import ru.ulstu.models.exceptions.ModelingException; import ru.ulstu.models.exceptions.TimeSeriesValidateException; -import ru.ulstu.tsMethods.exponential.param.TimeSeriesMethodParam; -import ru.ulstu.tsMethods.exponential.param.TimeSeriesMethodParamValue; import java.time.temporal.ChronoUnit; import java.util.List; /** - * Наиболее общая логика моделировани и прогнозирования временных рядов + * Наиболее общая логика моделировании и прогнозирования временных рядов */ public abstract class TimeSeriesMethod { + @JsonIgnore protected TimeSeries originalTimeSeries; + @JsonIgnore private TimeSeries model; public abstract TimeSeriesMethod createFor(TimeSeries originalTimeSeries); @@ -113,13 +122,15 @@ public abstract class TimeSeriesMethod { } public TimeSeries getModel() throws ModelingException { - if (model == null) { - makeModel(); - } + //TODO: what if always run? + //if (model == null) { + makeModel(); + //} return model; } - public abstract List getAvailableParams(); + @JsonIgnore + public abstract List getAvailableParameters(); - public abstract TimeSeriesMethod setAvailableParams(List params); + public abstract TimeSeriesMethod setAvailableParameters(List parameters); } diff --git a/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethodParamValue.java b/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethodParamValue.java new file mode 100644 index 0000000..f5c9e76 --- /dev/null +++ b/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethodParamValue.java @@ -0,0 +1,27 @@ +/* + * + * * Copyright (C) 2021 Anton Romanov - All Rights Reserved + * * You may use, distribute and modify this code, please write to: romanov73@gmail.com. + * + * + */ + +package ru.ulstu.tsMethods; + +public class TimeSeriesMethodParamValue { + protected MethodParameter parameter; + protected Number value; + + public TimeSeriesMethodParamValue(MethodParameter parameter, Number value) { + this.parameter = parameter; + this.value = value; + } + + public MethodParameter getParameter() { + return parameter; + } + + public Number getValue() { + return value; + } +} diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendAddSeason.java b/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendAddSeason.java index 474cc8a..6d8752f 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendAddSeason.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendAddSeason.java @@ -11,35 +11,51 @@ package ru.ulstu.tsMethods.exponential; import ru.ulstu.models.TimeSeries; import ru.ulstu.models.exceptions.ModelingException; import ru.ulstu.models.exceptions.TimeSeriesValidateException; +import ru.ulstu.tsMethods.MethodParameter; import ru.ulstu.tsMethods.TimeSeriesMethod; -import ru.ulstu.tsMethods.exponential.param.Alpha; -import ru.ulstu.tsMethods.exponential.param.Beta; -import ru.ulstu.tsMethods.exponential.param.ExponentialMethodParamValue; -import ru.ulstu.tsMethods.exponential.param.Gamma; -import ru.ulstu.tsMethods.exponential.param.Season; +import ru.ulstu.tsMethods.TimeSeriesMethodParamValue; +import ru.ulstu.tsMethods.exponential.parameter.Alpha; +import ru.ulstu.tsMethods.exponential.parameter.Beta; +import ru.ulstu.tsMethods.exponential.parameter.ExponentialMethodParamValue; +import ru.ulstu.tsMethods.exponential.parameter.Gamma; +import ru.ulstu.tsMethods.exponential.parameter.Season; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class AddTrendAddSeason extends TimeSeriesMethod { - private final ExponentialMethodParamValue alpha; - private final ExponentialMethodParamValue beta; - private final ExponentialMethodParamValue gamma; - private final ExponentialMethodParamValue season; + private ExponentialMethodParamValue alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5); + private ExponentialMethodParamValue beta = new ExponentialMethodParamValue<>(Beta.getInstance(), 0.5); + private ExponentialMethodParamValue gamma = new ExponentialMethodParamValue<>(Gamma.getInstance(), 0.5); + private ExponentialMethodParamValue season = new ExponentialMethodParamValue<>(Season.getInstance(), 12); private final List sComponent = new ArrayList<>(); private final List tComponent = new ArrayList<>(); private final List iComponent = new ArrayList<>(); - public AddTrendAddSeason(TimeSeries timeSeries, - ExponentialMethodParamValue alpha, - ExponentialMethodParamValue beta, - ExponentialMethodParamValue gamma, - ExponentialMethodParamValue season) throws ModelingException { - super(timeSeries); + public AddTrendAddSeason createFor(TimeSeries timeSeries) { + this.originalTimeSeries = timeSeries; + return this; + } + + public AddTrendAddSeason setAlpha(ExponentialMethodParamValue alpha) { this.alpha = alpha; + return this; + } + + public AddTrendAddSeason setBeta(ExponentialMethodParamValue beta) { this.beta = beta; + return this; + } + + public AddTrendAddSeason setGamma(ExponentialMethodParamValue gamma) { this.gamma = gamma; + return this; + } + + public AddTrendAddSeason setSeason(ExponentialMethodParamValue season) { this.season = season; + return this; } @Override @@ -100,4 +116,28 @@ public class AddTrendAddSeason extends TimeSeriesMethod { } return forecast; } + + @Override + public List getAvailableParameters() { + return Arrays.asList(alpha.getParam(), beta.getParam(), gamma.getParam(), season.getParam()); + } + + @Override + public TimeSeriesMethod setAvailableParameters(List parameters) { + for (TimeSeriesMethodParamValue parameter : parameters) { + if (parameter.getParameter() instanceof Alpha) { + alpha.setValue(parameter.getValue()); + } + if (parameter.getParameter() instanceof Beta) { + beta.setValue(parameter.getValue()); + } + if (parameter.getParameter() instanceof Gamma) { + gamma.setValue(parameter.getValue()); + } + if (parameter.getParameter() instanceof Season) { + season.setValue(parameter.getValue()); + } + } + return this; + } } diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendNoSeason.java b/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendNoSeason.java index 3f7aa24..84856fe 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendNoSeason.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendNoSeason.java @@ -8,32 +8,43 @@ package ru.ulstu.tsMethods.exponential; +import org.springframework.stereotype.Component; import ru.ulstu.models.TimeSeries; -import ru.ulstu.models.exceptions.ModelingException; +import ru.ulstu.tsMethods.MethodParameter; import ru.ulstu.tsMethods.TimeSeriesMethod; -import ru.ulstu.tsMethods.exponential.param.Alpha; -import ru.ulstu.tsMethods.exponential.param.Beta; -import ru.ulstu.tsMethods.exponential.param.ExponentialMethodParamValue; +import ru.ulstu.tsMethods.TimeSeriesMethodParamValue; +import ru.ulstu.tsMethods.exponential.parameter.Alpha; +import ru.ulstu.tsMethods.exponential.parameter.Beta; +import ru.ulstu.tsMethods.exponential.parameter.ExponentialMethodParamValue; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +@Component public class AddTrendNoSeason extends TimeSeriesMethod { - private final ExponentialMethodParamValue alpha; - private final ExponentialMethodParamValue beta; + private ExponentialMethodParamValue alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5); + private ExponentialMethodParamValue beta = new ExponentialMethodParamValue<>(Beta.getInstance(), 0.5); private final List sComponent = new ArrayList<>(); private final List tComponent = new ArrayList<>(); - public AddTrendNoSeason(TimeSeries timeSeries, - ExponentialMethodParamValue alpha, - ExponentialMethodParamValue beta) throws ModelingException { - super(timeSeries); + public AddTrendNoSeason createFor(TimeSeries timeSeries) { + this.originalTimeSeries = timeSeries; + return this; + } + + public AddTrendNoSeason setAlpha(ExponentialMethodParamValue alpha) { this.alpha = alpha; + return this; + } + + public AddTrendNoSeason setBeta(ExponentialMethodParamValue beta) { this.beta = beta; + return this; } @Override - protected TimeSeries getModelOfValidTimeSeries() throws ModelingException { + protected TimeSeries getModelOfValidTimeSeries() { sComponent.clear(); tComponent.clear(); sComponent.add(originalTimeSeries.getFirstValue().getValue()); @@ -61,4 +72,22 @@ public class AddTrendNoSeason extends TimeSeriesMethod { } return forecast; } + + @Override + public List getAvailableParameters() { + return Arrays.asList(alpha.getParam(), beta.getParam()); + } + + @Override + public TimeSeriesMethod setAvailableParameters(List parameters) { + for (TimeSeriesMethodParamValue parameter : parameters) { + if (parameter.getParameter() instanceof Alpha) { + alpha.setValue(parameter.getValue()); + } + if (parameter.getParameter() instanceof Beta) { + beta.setValue(parameter.getValue()); + } + } + return this; + } } diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/NoTrendNoSeason.java b/src/main/java/ru/ulstu/tsMethods/exponential/NoTrendNoSeason.java index 01130d8..79262ae 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/NoTrendNoSeason.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/NoTrendNoSeason.java @@ -8,21 +8,20 @@ package ru.ulstu.tsMethods.exponential; -import org.springframework.stereotype.Component; import ru.ulstu.models.TimeSeries; -import ru.ulstu.models.exceptions.ModelingException; +import ru.ulstu.tsMethods.MethodParameter; import ru.ulstu.tsMethods.TimeSeriesMethod; -import ru.ulstu.tsMethods.exponential.param.Alpha; -import ru.ulstu.tsMethods.exponential.param.ExponentialMethodParam; -import ru.ulstu.tsMethods.exponential.param.ExponentialMethodParamValue; +import ru.ulstu.tsMethods.TimeSeriesMethodParamValue; +import ru.ulstu.tsMethods.exponential.parameter.Alpha; +import ru.ulstu.tsMethods.exponential.parameter.ExponentialMethodParamValue; import java.util.ArrayList; import java.util.Collections; import java.util.List; -@Component + public class NoTrendNoSeason extends TimeSeriesMethod { - private ExponentialMethodParamValue alpha; + private ExponentialMethodParamValue alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5); private final List sComponent = new ArrayList<>(); public NoTrendNoSeason createFor(TimeSeries timeSeries) { @@ -36,7 +35,7 @@ public class NoTrendNoSeason extends TimeSeriesMethod { } @Override - protected TimeSeries getModelOfValidTimeSeries() throws ModelingException { + protected TimeSeries getModelOfValidTimeSeries() { sComponent.clear(); sComponent.add(originalTimeSeries.getFirstValue().getValue()); TimeSeries model = new TimeSeries("Model of " + originalTimeSeries.getName()); @@ -60,15 +59,15 @@ public class NoTrendNoSeason extends TimeSeriesMethod { } @Override - public List getAvailableParams() { + public List getAvailableParameters() { return Collections.singletonList(alpha.getParam()); } @Override - public TimeSeriesMethod setAvailableParams(List params) { - for (ExponentialMethodParamValue param : params) { - if (param.getParam() instanceof Alpha) { - alpha.setValue(param.getValue()); + public TimeSeriesMethod setAvailableParameters(List parameters) { + for (TimeSeriesMethodParamValue parameter : parameters) { + if (parameter.getParameter() instanceof Alpha) { + alpha.setValue(parameter.getValue()); } } return this; diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/param/Alpha.java b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/Alpha.java similarity index 58% rename from src/main/java/ru/ulstu/tsMethods/exponential/param/Alpha.java rename to src/main/java/ru/ulstu/tsMethods/exponential/parameter/Alpha.java index df5d431..1e6b442 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/param/Alpha.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/Alpha.java @@ -6,10 +6,14 @@ * */ -package ru.ulstu.tsMethods.exponential.param; +package ru.ulstu.tsMethods.exponential.parameter; -public class Alpha extends ExponentialMethodParam { +public class Alpha extends ExponentialMethodParameter { public Alpha() { super("ALPHA", 0, 1, DEFAULT_OPTIMIZATION_STEP); } + + public static Alpha getInstance() { + return new Alpha(); + } } diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/param/Beta.java b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/Beta.java similarity index 58% rename from src/main/java/ru/ulstu/tsMethods/exponential/param/Beta.java rename to src/main/java/ru/ulstu/tsMethods/exponential/parameter/Beta.java index 8509593..7ea9ead 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/param/Beta.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/Beta.java @@ -6,10 +6,14 @@ * */ -package ru.ulstu.tsMethods.exponential.param; +package ru.ulstu.tsMethods.exponential.parameter; -public class Beta extends ExponentialMethodParam { +public class Beta extends ExponentialMethodParameter { public Beta() { super("BETA", 0, 1, DEFAULT_OPTIMIZATION_STEP); } + + public static Beta getInstance() { + return new Beta(); + } } diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/param/ExponentialMethodParamValue.java b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/ExponentialMethodParamValue.java similarity index 91% rename from src/main/java/ru/ulstu/tsMethods/exponential/param/ExponentialMethodParamValue.java rename to src/main/java/ru/ulstu/tsMethods/exponential/parameter/ExponentialMethodParamValue.java index fe83a21..813a5ad 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/param/ExponentialMethodParamValue.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/ExponentialMethodParamValue.java @@ -6,9 +6,9 @@ * */ -package ru.ulstu.tsMethods.exponential.param; +package ru.ulstu.tsMethods.exponential.parameter; -public class ExponentialMethodParamValue { +public class ExponentialMethodParamValue { private final T param; private Number value; diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/param/ExponentialMethodParam.java b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/ExponentialMethodParameter.java similarity index 52% rename from src/main/java/ru/ulstu/tsMethods/exponential/param/ExponentialMethodParam.java rename to src/main/java/ru/ulstu/tsMethods/exponential/parameter/ExponentialMethodParameter.java index 696d93a..e9a68b0 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/param/ExponentialMethodParam.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/ExponentialMethodParameter.java @@ -6,26 +6,27 @@ * */ -package ru.ulstu.tsMethods.exponential.param; +package ru.ulstu.tsMethods.exponential.parameter; -public abstract class ExponentialMethodParam { - public static final Float DEFAULT_OPTIMIZATION_STEP = 0.01f; - private final String key; +import com.fasterxml.jackson.annotation.JsonIgnore; +import ru.ulstu.tsMethods.MethodParameter; + +import java.util.ArrayList; +import java.util.List; + +public abstract class ExponentialMethodParameter extends MethodParameter { + public static final Float DEFAULT_OPTIMIZATION_STEP = 0.1f; private final Number minValue; private final Number maxValue; private final Number optimizationStep; - public ExponentialMethodParam(String key, Number minValue, Number maxValue, Number optimizationStep) { - this.key = key; + public ExponentialMethodParameter(String name, Number minValue, Number maxValue, Number optimizationStep) { + super(name); this.minValue = minValue; this.maxValue = maxValue; this.optimizationStep = optimizationStep; } - public String getKey() { - return key; - } - public Number getMinValue() { return minValue; } @@ -38,10 +39,20 @@ public abstract class ExponentialMethodParam { return optimizationStep; } + @Override + @JsonIgnore + public List getAvailableValues() { + List values = new ArrayList<>(); + for (double i = minValue.doubleValue(); i <= maxValue.doubleValue(); i += optimizationStep.doubleValue()) { + values.add(i); + } + return values; + } + @Override public String toString() { return "TimeSeriesMethodParam{" + - "key='" + key + '\'' + + "name='" + name + '\'' + ", minValue=" + minValue + ", maxValue=" + maxValue + ", delta=" + optimizationStep + diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/param/Gamma.java b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/Gamma.java similarity index 58% rename from src/main/java/ru/ulstu/tsMethods/exponential/param/Gamma.java rename to src/main/java/ru/ulstu/tsMethods/exponential/parameter/Gamma.java index b739290..e319fc1 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/param/Gamma.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/Gamma.java @@ -6,10 +6,14 @@ * */ -package ru.ulstu.tsMethods.exponential.param; +package ru.ulstu.tsMethods.exponential.parameter; -public class Gamma extends ExponentialMethodParam { +public class Gamma extends ExponentialMethodParameter { public Gamma() { super("Gamma", 0, 1, DEFAULT_OPTIMIZATION_STEP); } + + public static Gamma getInstance() { + return new Gamma(); + } } diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/param/Season.java b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/Season.java similarity index 65% rename from src/main/java/ru/ulstu/tsMethods/exponential/param/Season.java rename to src/main/java/ru/ulstu/tsMethods/exponential/parameter/Season.java index 3f39d40..505b82a 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/param/Season.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/parameter/Season.java @@ -6,12 +6,16 @@ * */ -package ru.ulstu.tsMethods.exponential.param; +package ru.ulstu.tsMethods.exponential.parameter; -public class Season extends ExponentialMethodParam { +public class Season extends ExponentialMethodParameter { private final static int DEFAULT_SEASON_OPTIMIZATION_STEP = 1; public Season() { super("Сезонность", 0, 12, DEFAULT_SEASON_OPTIMIZATION_STEP); } + + public static Season getInstance() { + return new Season(); + } }