From 35fedf4fec745bf962ce9dfabed540868ac34667 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Tue, 19 Apr 2022 18:06:40 +0400 Subject: [PATCH 1/3] #3 -- add F-Transform --- .../ru/ulstu/controller/IndexController.java | 4 +- .../ru/ulstu/method/MethodParamValue.java | 8 ++ .../java/ru/ulstu/method/MethodParameter.java | 10 ++- .../AddTrendAddSeasonModel.java | 3 +- .../AddTrendNoSeasonModel.java | 3 +- .../notrendnoseason/NoTrendNoSeasonModel.java | 3 +- .../parameter/ExponentialMethodParameter.java | 3 +- .../ulstu/method/ftransform/AComponent.java | 57 ++++++++++++ .../ulstu/method/ftransform/FTransform.java | 87 +++++++++++++++++++ .../method/ftransform/FTransformModel.java | 43 +++++++++ .../parameter/NumberOfCoveredPoints.java | 29 +++++++ .../ulstu/service/MethodParamBruteForce.java | 22 +++-- .../ru/ulstu/service/TimeSeriesService.java | 4 + 13 files changed, 262 insertions(+), 14 deletions(-) create mode 100644 src/main/java/ru/ulstu/method/ftransform/AComponent.java create mode 100644 src/main/java/ru/ulstu/method/ftransform/FTransform.java create mode 100644 src/main/java/ru/ulstu/method/ftransform/FTransformModel.java create mode 100644 src/main/java/ru/ulstu/method/ftransform/parameter/NumberOfCoveredPoints.java diff --git a/src/main/java/ru/ulstu/controller/IndexController.java b/src/main/java/ru/ulstu/controller/IndexController.java index 86389b2..05814e0 100644 --- a/src/main/java/ru/ulstu/controller/IndexController.java +++ b/src/main/java/ru/ulstu/controller/IndexController.java @@ -82,11 +82,13 @@ public class IndexController { private void addChartToModel(TimeSeries timeSeries, String method, Model model) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException { int countForecastPoints = timeSeries.getLength() > 20 ? 10 : timeSeries.getLength() / 3; - TimeSeries timeSeriesModel = timeSeriesService.smoothTimeSeries(timeSeries).getTimeSeries(); + TimeSeries timeSeriesModel; ModelingResult modelingResult; if (method == null) { + timeSeriesModel = timeSeriesService.smoothTimeSeries(timeSeries).getTimeSeries(); modelingResult = timeSeriesService.getForecast(timeSeries, countForecastPoints); } else { + timeSeriesModel = timeSeriesService.smoothTimeSeries(timeSeries, method).getTimeSeries(); modelingResult = timeSeriesService.getForecast(timeSeries, method, countForecastPoints); } TimeSeries forecast = modelingResult.getTimeSeries(); diff --git a/src/main/java/ru/ulstu/method/MethodParamValue.java b/src/main/java/ru/ulstu/method/MethodParamValue.java index df61b32..f3411c2 100644 --- a/src/main/java/ru/ulstu/method/MethodParamValue.java +++ b/src/main/java/ru/ulstu/method/MethodParamValue.java @@ -16,4 +16,12 @@ public class MethodParamValue { public Number getValue() { return value; } + + public Integer getIntValue() { + return value.intValue(); + } + + public void setValue(Number value) { + this.value = value; + } } diff --git a/src/main/java/ru/ulstu/method/MethodParameter.java b/src/main/java/ru/ulstu/method/MethodParameter.java index 58d6681..23e4c6f 100644 --- a/src/main/java/ru/ulstu/method/MethodParameter.java +++ b/src/main/java/ru/ulstu/method/MethodParameter.java @@ -1,8 +1,10 @@ package ru.ulstu.method; +import ru.ulstu.datamodel.ts.TimeSeries; + import java.util.List; -public abstract class MethodParameter implements Comparable { +public abstract class MethodParameter implements Comparable { protected String name; public MethodParameter(String name) { @@ -13,10 +15,10 @@ public abstract class MethodParameter implements Comparable { return name; } - public abstract List getAvailableValues(); + public abstract List getAvailableValues(TimeSeries timeSeries); @Override - public int compareTo(Object o) { - return this.name.compareTo(((MethodParameter) o).getName()); + public int compareTo(MethodParameter o) { + return this.name.compareTo(o.getName()); } } diff --git a/src/main/java/ru/ulstu/method/exponential/addtrendaddseason/AddTrendAddSeasonModel.java b/src/main/java/ru/ulstu/method/exponential/addtrendaddseason/AddTrendAddSeasonModel.java index 1e54be4..0f2d163 100644 --- a/src/main/java/ru/ulstu/method/exponential/addtrendaddseason/AddTrendAddSeasonModel.java +++ b/src/main/java/ru/ulstu/method/exponential/addtrendaddseason/AddTrendAddSeasonModel.java @@ -1,5 +1,6 @@ package ru.ulstu.method.exponential.addtrendaddseason; +import ru.ulstu.datamodel.Model; import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.method.MethodParamValue; import ru.ulstu.method.MethodParameter; @@ -13,7 +14,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class AddTrendAddSeasonModel extends ru.ulstu.datamodel.Model { +public class AddTrendAddSeasonModel extends Model { private final ExponentialMethodParamValue alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5); private final ExponentialMethodParamValue beta = new ExponentialMethodParamValue<>(Beta.getInstance(), 0.5); private final ExponentialMethodParamValue gamma = new ExponentialMethodParamValue<>(Gamma.getInstance(), 0.5); diff --git a/src/main/java/ru/ulstu/method/exponential/addtrendnoseason/AddTrendNoSeasonModel.java b/src/main/java/ru/ulstu/method/exponential/addtrendnoseason/AddTrendNoSeasonModel.java index aaf5f32..f16cd9e 100644 --- a/src/main/java/ru/ulstu/method/exponential/addtrendnoseason/AddTrendNoSeasonModel.java +++ b/src/main/java/ru/ulstu/method/exponential/addtrendnoseason/AddTrendNoSeasonModel.java @@ -1,5 +1,6 @@ package ru.ulstu.method.exponential.addtrendnoseason; +import ru.ulstu.datamodel.Model; import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.method.MethodParamValue; import ru.ulstu.method.MethodParameter; @@ -11,7 +12,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class AddTrendNoSeasonModel extends ru.ulstu.datamodel.Model { +public class AddTrendNoSeasonModel extends Model { private final ExponentialMethodParamValue alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5); private final ExponentialMethodParamValue beta = new ExponentialMethodParamValue<>(Beta.getInstance(), 0.5); private final List smoothedComponent = new ArrayList<>(); diff --git a/src/main/java/ru/ulstu/method/exponential/notrendnoseason/NoTrendNoSeasonModel.java b/src/main/java/ru/ulstu/method/exponential/notrendnoseason/NoTrendNoSeasonModel.java index aaf0558..0bfdb2e 100644 --- a/src/main/java/ru/ulstu/method/exponential/notrendnoseason/NoTrendNoSeasonModel.java +++ b/src/main/java/ru/ulstu/method/exponential/notrendnoseason/NoTrendNoSeasonModel.java @@ -1,5 +1,6 @@ package ru.ulstu.method.exponential.notrendnoseason; +import ru.ulstu.datamodel.Model; import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.method.MethodParamValue; import ru.ulstu.method.MethodParameter; @@ -10,7 +11,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class NoTrendNoSeasonModel extends ru.ulstu.datamodel.Model { +public class NoTrendNoSeasonModel extends Model { private final ExponentialMethodParamValue alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5); private final List smoothedComponent = new ArrayList<>(); diff --git a/src/main/java/ru/ulstu/method/exponential/parameter/ExponentialMethodParameter.java b/src/main/java/ru/ulstu/method/exponential/parameter/ExponentialMethodParameter.java index 0df6150..cd18acf 100644 --- a/src/main/java/ru/ulstu/method/exponential/parameter/ExponentialMethodParameter.java +++ b/src/main/java/ru/ulstu/method/exponential/parameter/ExponentialMethodParameter.java @@ -1,6 +1,7 @@ package ru.ulstu.method.exponential.parameter; import com.fasterxml.jackson.annotation.JsonIgnore; +import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.method.MethodParameter; import java.util.ArrayList; @@ -35,7 +36,7 @@ public abstract class ExponentialMethodParameter extends MethodParameter { @Override @JsonIgnore - public List getAvailableValues() { + public List getAvailableValues(TimeSeries timeSeries) { List values = new ArrayList<>(); for (double i = minValue.doubleValue(); i <= maxValue.doubleValue(); i += optimizationStep.doubleValue()) { values.add(i); diff --git a/src/main/java/ru/ulstu/method/ftransform/AComponent.java b/src/main/java/ru/ulstu/method/ftransform/AComponent.java new file mode 100644 index 0000000..5ba4fe4 --- /dev/null +++ b/src/main/java/ru/ulstu/method/ftransform/AComponent.java @@ -0,0 +1,57 @@ +package ru.ulstu.method.ftransform; + +/** + * Треугольная функция принадлежности + */ +public class AComponent { + private int start; // левая граница треугольника + private int end; // правая граница треугольника + private int top; // вершина треугольника + + public int getStart() { + return start; + } + + public AComponent() { + } + + public AComponent(int start, int top, int end) { + this.start = start; + this.top = top; + this.end = end; + } + + public void setStart(int start) { + this.start = start; + } + + + public int getEnd() { + return end; + } + + public void setEnd(int end) { + this.end = end; + } + + public int getTop() { + return top; + } + + public void setTop(int top) { + this.top = top; + } + + public double getValueAtPoint(int pointIndex) { + if (pointIndex == this.getTop()) { + return 1; + } else if ((pointIndex >= this.getEnd()) || (pointIndex <= this.getStart())) { + return 0; + } else if (pointIndex < this.getTop()) { + return (double) (pointIndex - this.getStart()) / (this.getTop() - this.getStart()); + } else if (pointIndex > this.getTop()) { + return (double) -(pointIndex - this.getEnd()) / (this.getEnd() - this.getTop()); + } + return 0; + } +} diff --git a/src/main/java/ru/ulstu/method/ftransform/FTransform.java b/src/main/java/ru/ulstu/method/ftransform/FTransform.java new file mode 100644 index 0000000..3981e97 --- /dev/null +++ b/src/main/java/ru/ulstu/method/ftransform/FTransform.java @@ -0,0 +1,87 @@ +package ru.ulstu.method.ftransform; + +import org.springframework.stereotype.Component; +import ru.ulstu.datamodel.Model; +import ru.ulstu.datamodel.ts.TimeSeries; +import ru.ulstu.method.Method; +import ru.ulstu.method.MethodParamValue; +import ru.ulstu.method.MethodParameter; + +import java.util.List; + +@Component +public class FTransform extends Method { + + @Override + protected FTransformModel getModelOfValidTimeSeries(TimeSeries ts, + List parameters) { + FTransformModel model = new FTransformModel(ts, parameters); + List aComponents = generateAComponents(ts, model.getNumberOfCoveredPoints().getIntValue(), model.getAComponents()); + ; + TimeSeries piecewiseLinearTrend = model.getPiecewiseLinearTrend(); + TimeSeries tsModel = model.getTimeSeriesModel(); + + for (AComponent aComponent : aComponents) { + double sum1 = 0; + double sum2 = 0; + for (int j = 0; j < ts.getLength(); j++) { + double membership = aComponent.getValueAtPoint(j); + sum1 += membership * ts.getNumericValue(j); + sum2 += membership; + } + piecewiseLinearTrend.addValue(ts.getValue(aComponent.getTop()), sum1 / sum2); + tsModel.addValue(ts.getValue(aComponent.getTop()), sum1 / sum2); + } + return model; + } + + private List generateAComponents(TimeSeries ts, int numberOfCoveredPoints, List piecewiseLinearTrend) { + long deltaForTriangle = Math.round(numberOfCoveredPoints / 2.0); + int currentPoint = 0; + while (currentPoint < ts.getLength()) { + int startPoint = (currentPoint == 0) + ? 0 + : piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTop(); + AComponent bf = new AComponent(startPoint, currentPoint, currentPoint + numberOfCoveredPoints / 2); + if (bf.getStart() < 0) { + bf.setStart(0); + } + if (bf.getEnd() > ts.getLength() - 1) { + bf.setEnd(ts.getLength() - 1); + } + + if (bf.getTop() > ts.getLength() - 1) { + bf.setTop(ts.getLength() - 1); + } + + piecewiseLinearTrend.add(bf); + currentPoint += deltaForTriangle; + } + if (piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getEnd() != piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTop()) { + AComponent bf = new AComponent(piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTop(), + piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getEnd(), + piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getEnd()); + piecewiseLinearTrend.add(bf); + } + return piecewiseLinearTrend; + } + + @Override + protected TimeSeries getForecastWithValidParams(Model model, TimeSeries forecast) { + FTransformModel fTransformModel = (FTransformModel) model; + for (int t = 1; t < forecast.getLength(); t++) { + forecast.getValues().get(t).setValue(fTransformModel.getPiecewiseLinearTrend().getLastValue().getValue()); + } + return forecast; + } + + @Override + public List getAvailableParameters() { + return FTransformModel.getAvailableParameters(); + } + + @Override + public String getName() { + return "F - преобразование"; + } +} diff --git a/src/main/java/ru/ulstu/method/ftransform/FTransformModel.java b/src/main/java/ru/ulstu/method/ftransform/FTransformModel.java new file mode 100644 index 0000000..af38aaa --- /dev/null +++ b/src/main/java/ru/ulstu/method/ftransform/FTransformModel.java @@ -0,0 +1,43 @@ +package ru.ulstu.method.ftransform; + +import ru.ulstu.datamodel.Model; +import ru.ulstu.datamodel.ts.TimeSeries; +import ru.ulstu.method.MethodParamValue; +import ru.ulstu.method.MethodParameter; +import ru.ulstu.method.ftransform.parameter.NumberOfCoveredPoints; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class FTransformModel extends Model { + private final MethodParamValue numberOfCoveredPoints = new MethodParamValue(NumberOfCoveredPoints.getInstance(), 3); + private final List aComponents = new ArrayList<>(); + private final TimeSeries piecewiseLinearTrend; + + public FTransformModel(TimeSeries ts, List parameters) { + super(ts); + piecewiseLinearTrend = new TimeSeries("Piecewise linear trend of ", ts.getKey()); + for (MethodParamValue parameter : parameters) { + if (parameter.getParameter() instanceof NumberOfCoveredPoints) { + numberOfCoveredPoints.setValue(parameter.getValue()); + } + } + } + + public TimeSeries getPiecewiseLinearTrend() { + return piecewiseLinearTrend; + } + + public List getAComponents() { + return aComponents; + } + + public MethodParamValue getNumberOfCoveredPoints() { + return numberOfCoveredPoints; + } + + public static List getAvailableParameters() { + return Collections.singletonList(NumberOfCoveredPoints.getInstance()); + } +} diff --git a/src/main/java/ru/ulstu/method/ftransform/parameter/NumberOfCoveredPoints.java b/src/main/java/ru/ulstu/method/ftransform/parameter/NumberOfCoveredPoints.java new file mode 100644 index 0000000..a027b7c --- /dev/null +++ b/src/main/java/ru/ulstu/method/ftransform/parameter/NumberOfCoveredPoints.java @@ -0,0 +1,29 @@ +package ru.ulstu.method.ftransform.parameter; + +import ru.ulstu.datamodel.ts.TimeSeries; +import ru.ulstu.method.MethodParameter; + +import java.util.ArrayList; +import java.util.List; + +public class NumberOfCoveredPoints extends MethodParameter { + private final static int MIN_NUMBER_OF_COVERED_POINTS = 3; + private final static int MIN_INCREASING_STEP_OF_NUMBER_OF_COVERED_POINTS = 2; + + public NumberOfCoveredPoints() { + super("Number of covered points"); + } + + public static NumberOfCoveredPoints getInstance() { + return new NumberOfCoveredPoints(); + } + + @Override + public List getAvailableValues(TimeSeries timeSeries) { + List values = new ArrayList<>(); + for (double i = MIN_NUMBER_OF_COVERED_POINTS; i <= (timeSeries.getLength() < 10 ? 7 : timeSeries.getLength() / 3.0); i += MIN_INCREASING_STEP_OF_NUMBER_OF_COVERED_POINTS) { + values.add(i); + } + return values; + } +} diff --git a/src/main/java/ru/ulstu/service/MethodParamBruteForce.java b/src/main/java/ru/ulstu/service/MethodParamBruteForce.java index ec4a5af..348d63d 100644 --- a/src/main/java/ru/ulstu/service/MethodParamBruteForce.java +++ b/src/main/java/ru/ulstu/service/MethodParamBruteForce.java @@ -48,7 +48,7 @@ class MethodParamBruteForce { .collect(Collectors.toMap(TimeSeriesValue::getDate, TimeSeriesValue::getValue)); for (Method method : methods) { - List> availableParametersValues = getAvailableParametersValues(method.getAvailableParameters()); + List> availableParametersValues = getAvailableParametersValues(timeSeries, method.getAvailableParameters()); for (List parametersValues : availableParametersValues) { Method methodInstance = method.getClass().getDeclaredConstructor().newInstance(); if (methodInstance.canMakeForecast(reducedTimeSeries, parametersValues, countPoints)) { @@ -119,7 +119,7 @@ class MethodParamBruteForce { } */ - public ModelingResult getSmoothedTimeSeries(TimeSeries timeSeries) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + public ModelingResult getSmoothedTimeSeries(TimeSeries timeSeries, List methods) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { List> results = new ArrayList<>(); List results2 = new CopyOnWriteArrayList<>(); @@ -127,7 +127,7 @@ class MethodParamBruteForce { .collect(Collectors.toMap(TimeSeriesValue::getDate, TimeSeriesValue::getValue)); for (Method method : methods) { - List> availableParametersValues = getAvailableParametersValues(method.getAvailableParameters()); + List> availableParametersValues = getAvailableParametersValues(timeSeries, method.getAvailableParameters()); for (List parametersValues : availableParametersValues) { Method methodInstance = method.getClass().getDeclaredConstructor().newInstance(); if (methodInstance.canMakeModel(timeSeries, parametersValues)) { @@ -150,13 +150,25 @@ class MethodParamBruteForce { .orElse(null); } - private List> getAvailableParametersValues(List availableParameters) { + public ModelingResult getSmoothedTimeSeries(TimeSeries timeSeries, String methodClassName) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ModelingException { + Method method = methods.stream() + .filter(m -> m.getClass().getSimpleName().equals(methodClassName)) + .findAny() + .orElseThrow(() -> new ModelingException("Неизвестный метод прогнозирования")); + return getSmoothedTimeSeries(timeSeries, List.of(method)); + } + + public ModelingResult getSmoothedTimeSeries(TimeSeries timeSeries) throws ExecutionException, InterruptedException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + return getSmoothedTimeSeries(timeSeries, methods); + } + + private List> getAvailableParametersValues(TimeSeries timeSeries, 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()); + parameterValues.put(methodParameter, methodParameter.getAvailableValues(timeSeries)); } while (isNotAllParameterValuesUsed(parameterOffset, parameterValues)) { List resultRow = new ArrayList<>(); diff --git a/src/main/java/ru/ulstu/service/TimeSeriesService.java b/src/main/java/ru/ulstu/service/TimeSeriesService.java index 4b80bc7..525eb79 100644 --- a/src/main/java/ru/ulstu/service/TimeSeriesService.java +++ b/src/main/java/ru/ulstu/service/TimeSeriesService.java @@ -35,6 +35,10 @@ public class TimeSeriesService { return methodParamBruteForce.getSmoothedTimeSeries(timeSeries); } + public ModelingResult smoothTimeSeries(TimeSeries timeSeries, String methodClassName) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException { + return methodParamBruteForce.getSmoothedTimeSeries(timeSeries, methodClassName); + } + public List getAvailableMethods() { return methodParamBruteForce.getAvailableMethods(); } -- 2.34.1 From 3e2608376576951f9f9af32939e67f90d5c9fd08 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Tue, 19 Apr 2022 22:13:50 +0400 Subject: [PATCH 2/3] #3 -- F-Transform model of time series --- .../ru/ulstu/controller/IndexController.java | 63 +++++++++++-------- src/main/java/ru/ulstu/db/DbFileService.java | 3 +- .../ulstu/method/ftransform/FTransform.java | 4 +- src/main/resources/templates/method.html | 4 ++ 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/main/java/ru/ulstu/controller/IndexController.java b/src/main/java/ru/ulstu/controller/IndexController.java index 05814e0..4a329cc 100644 --- a/src/main/java/ru/ulstu/controller/IndexController.java +++ b/src/main/java/ru/ulstu/controller/IndexController.java @@ -55,31 +55,6 @@ public class IndexController { return "index"; } - @GetMapping("/method") - public String method(Model model) throws IOException { - model.addAttribute("sets", dbService.getSets()); - model.addAttribute("methods", timeSeriesService.getAvailableMethods()); - model.addAttribute("chartForm", new ChartForm()); - return "method"; - } - - @GetMapping("chartMethod") - public String chartMethod(@ModelAttribute ChartForm chartForm, Model model) throws IOException, ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { - model.addAttribute("sets", dbService.getSets()); - model.addAttribute("methods", timeSeriesService.getAvailableMethods()); - if (chartForm.getSet() != null && !chartForm.getSet().getKey().equals("")) { - model.addAttribute("listTimeSeries", dbService.getTimeSeriesMeta(chartForm.getSet())); - } - if (chartForm.getTimeSeriesMeta() != null - && chartForm.getTimeSeriesMeta().getKey() != null - && !chartForm.getTimeSeriesMeta().getKey().isEmpty() - && chartForm.getMethodClassName() != null - && !chartForm.getMethodClassName().equals("")) { - addChartToModel(dbService.getTimeSeries(chartForm.getSet(), chartForm.getTimeSeriesMeta().getKey()), chartForm.getMethodClassName(), model); - } - return "method"; - } - private void addChartToModel(TimeSeries timeSeries, String method, Model model) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException { int countForecastPoints = timeSeries.getLength() > 20 ? 10 : timeSeries.getLength() / 3; TimeSeries timeSeriesModel; @@ -95,7 +70,18 @@ public class IndexController { TimeSeries testForecast = modelingResult.getTestForecast(); model.addAttribute("dates", getDatesForChart(timeSeries, forecast)); model.addAttribute("timeSeries", timeSeries.getValues().stream().map(TimeSeriesValue::getValue).toArray()); - model.addAttribute("model", timeSeriesModel.getValues().stream().map(TimeSeriesValue::getValue).toArray()); + // если временной ряд был сжат моделью, то для графика нужно вставить пустые значения + TimeSeries modelWithSkips = new TimeSeries(timeSeriesModel.getKey()); + int j = 0; + for (int i = 0; i < timeSeries.getLength(); i++) { + if (timeSeries.getValue(i).getDate().equals(timeSeriesModel.getValue(j).getDate())) { + modelWithSkips.addValue(timeSeriesModel.getValue(j)); + j++; + } else { + modelWithSkips.addValue(new TimeSeriesValue((Double) null)); + } + } + model.addAttribute("model", modelWithSkips.getValues().stream().map(TimeSeriesValue::getValue).toArray()); timeSeries.getValues().remove(timeSeries.getValues().size() - 1); List forecastValues = timeSeries.getValues().stream().map(v -> (Double) null).collect(Collectors.toList()); @@ -121,4 +107,29 @@ public class IndexController { .collect(Collectors.toList()); } + + @GetMapping("/method") + public String method(Model model) throws IOException { + model.addAttribute("sets", dbService.getSets()); + model.addAttribute("methods", timeSeriesService.getAvailableMethods()); + model.addAttribute("chartForm", new ChartForm()); + return "method"; + } + + @GetMapping("chartMethod") + public String chartMethod(@ModelAttribute ChartForm chartForm, Model model) throws IOException, ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + model.addAttribute("sets", dbService.getSets()); + model.addAttribute("methods", timeSeriesService.getAvailableMethods()); + if (chartForm.getSet() != null && !chartForm.getSet().getKey().equals("")) { + model.addAttribute("listTimeSeries", dbService.getTimeSeriesMeta(chartForm.getSet())); + } + if (chartForm.getTimeSeriesMeta() != null + && chartForm.getTimeSeriesMeta().getKey() != null + && !chartForm.getTimeSeriesMeta().getKey().isEmpty() + && chartForm.getMethodClassName() != null + && !chartForm.getMethodClassName().equals("")) { + addChartToModel(dbService.getTimeSeries(chartForm.getSet(), chartForm.getTimeSeriesMeta().getKey()), chartForm.getMethodClassName(), model); + } + return "method"; + } } diff --git a/src/main/java/ru/ulstu/db/DbFileService.java b/src/main/java/ru/ulstu/db/DbFileService.java index 90a7e9d..aa322d4 100644 --- a/src/main/java/ru/ulstu/db/DbFileService.java +++ b/src/main/java/ru/ulstu/db/DbFileService.java @@ -35,6 +35,7 @@ public class DbFileService implements DbService { createDbIfNotExists(); return Arrays.stream(Objects.requireNonNull(new File(timeSeriesDbPath).listFiles(File::isDirectory))) .map(TimeSeriesSet::new) + .sorted() .collect(Collectors.toList()); } @@ -47,7 +48,7 @@ public class DbFileService implements DbService { .readValue(Paths.get(getSetPath(timeSeriesSet).getAbsolutePath(), file.getName()) .toFile(), TimeSeriesMeta.class)); } - return list; + return list.stream().sorted().collect(Collectors.toList()); } @Override diff --git a/src/main/java/ru/ulstu/method/ftransform/FTransform.java b/src/main/java/ru/ulstu/method/ftransform/FTransform.java index 3981e97..e533c9c 100644 --- a/src/main/java/ru/ulstu/method/ftransform/FTransform.java +++ b/src/main/java/ru/ulstu/method/ftransform/FTransform.java @@ -17,7 +17,7 @@ public class FTransform extends Method { List parameters) { FTransformModel model = new FTransformModel(ts, parameters); List aComponents = generateAComponents(ts, model.getNumberOfCoveredPoints().getIntValue(), model.getAComponents()); - ; + TimeSeries piecewiseLinearTrend = model.getPiecewiseLinearTrend(); TimeSeries tsModel = model.getTimeSeriesModel(); @@ -42,7 +42,7 @@ public class FTransform extends Method { int startPoint = (currentPoint == 0) ? 0 : piecewiseLinearTrend.get(piecewiseLinearTrend.size() - 1).getTop(); - AComponent bf = new AComponent(startPoint, currentPoint, currentPoint + numberOfCoveredPoints / 2); + AComponent bf = new AComponent(startPoint, currentPoint, (int) (currentPoint + Math.round(numberOfCoveredPoints / 2.0))); if (bf.getStart() < 0) { bf.setStart(0); } diff --git a/src/main/resources/templates/method.html b/src/main/resources/templates/method.html index ba39def..9ee0aa4 100644 --- a/src/main/resources/templates/method.html +++ b/src/main/resources/templates/method.html @@ -63,21 +63,25 @@ { name: [[#{messages.time_series}]], color: 'rgba(119,152,191,0.5)', + connectNulls: true, data: [[${timeSeries}]] }, { name: [[#{messages.time_series_model}]], color: 'rgba(255,200,0,0.5)', + connectNulls: true, data: [[${model}]] }, { name: [[#{messages.time_series_test_forecast}]], color: 'rgba(255,0,0,0.5)', + connectNulls: true, data: [[${testForecast}]] }, { name: [[#{messages.time_series_forecast_short}]], color: 'rgba(255,0,0,0.5)', + connectNulls: true, data: [[${forecast}]] } ]; -- 2.34.1 From c309c71b84aed5d5219332afb99263546ae5bea4 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Tue, 19 Apr 2022 22:19:49 +0400 Subject: [PATCH 3/3] #3 -- fix comparator --- src/main/java/ru/ulstu/db/model/TimeSeriesMeta.java | 7 ++++++- src/main/java/ru/ulstu/db/model/TimeSeriesSet.java | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/ulstu/db/model/TimeSeriesMeta.java b/src/main/java/ru/ulstu/db/model/TimeSeriesMeta.java index 6e92adb..05b4fda 100644 --- a/src/main/java/ru/ulstu/db/model/TimeSeriesMeta.java +++ b/src/main/java/ru/ulstu/db/model/TimeSeriesMeta.java @@ -2,7 +2,7 @@ package ru.ulstu.db.model; import ru.ulstu.datamodel.ts.TimeSeries; -public class TimeSeriesMeta { +public class TimeSeriesMeta implements Comparable { private String key; private int size; private boolean hasDateTime; @@ -31,4 +31,9 @@ public class TimeSeriesMeta { public boolean isHasDateTime() { return hasDateTime; } + + @Override + public int compareTo(TimeSeriesMeta o) { + return o != null ? key.compareTo(o.getKey()) : 0; + } } diff --git a/src/main/java/ru/ulstu/db/model/TimeSeriesSet.java b/src/main/java/ru/ulstu/db/model/TimeSeriesSet.java index 5dbbfbf..8decb21 100644 --- a/src/main/java/ru/ulstu/db/model/TimeSeriesSet.java +++ b/src/main/java/ru/ulstu/db/model/TimeSeriesSet.java @@ -2,7 +2,7 @@ package ru.ulstu.db.model; import java.io.File; -public class TimeSeriesSet { +public class TimeSeriesSet implements Comparable { private final String key; public TimeSeriesSet(File dir) { @@ -16,4 +16,9 @@ public class TimeSeriesSet { public String getKey() { return key; } + + @Override + public int compareTo(TimeSeriesSet o) { + return o != null ? key.compareTo(o.getKey()) : 0; + } } -- 2.34.1