Merge branch '8-modularity' into 'master'

Resolve "повысить модульность"

Closes #8

See merge request romanov73/time-series-smoothing!5
This commit is contained in:
Anton Romanov 2021-06-09 14:06:48 +00:00
commit 090b339219
47 changed files with 761 additions and 607 deletions

View File

@ -1,6 +1,12 @@
/*
* 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; package ru.ulstu;
import ru.ulstu.models.TimeSeries; import ru.ulstu.datamodel.ts.TimeSeries;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;

View File

@ -1,19 +1,10 @@
/* /*
* Copyright (c) 2020. Anton Romanov * Copyright (C) 2021 Anton Romanov - All Rights Reserved
* Licensed under the Apache License, Version 2.0 (the "License"); * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
* 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 ru.ulstu.controllers; package ru.ulstu.controller;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -21,10 +12,10 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.HttpServerErrorException;
import ru.ulstu.models.exceptions.ForecastValidateException; import ru.ulstu.datamodel.exception.ForecastValidateException;
import ru.ulstu.models.exceptions.TimeSeriesValidateException; import ru.ulstu.datamodel.exception.TimeSeriesValidateException;
import ru.ulstu.models.response.ErrorConstants; import ru.ulstu.datamodel.response.ErrorConstants;
import ru.ulstu.models.response.ResponseExtended; import ru.ulstu.datamodel.response.ResponseExtended;
@RestController @RestController
@ControllerAdvice @ControllerAdvice

View File

@ -1,12 +1,10 @@
/* /*
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
* * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*
* *
*/ */
package ru.ulstu.controllers; package ru.ulstu.controller;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -16,12 +14,12 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.configuration.ApiConfiguration; import ru.ulstu.configuration.ApiConfiguration;
import ru.ulstu.models.ForecastParams; import ru.ulstu.datamodel.ForecastParams;
import ru.ulstu.models.ModelingResult; import ru.ulstu.datamodel.ModelingResult;
import ru.ulstu.models.TimeSeries; import ru.ulstu.datamodel.exception.ModelingException;
import ru.ulstu.models.exceptions.ModelingException; import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.services.MethodParamBruteForce; import ru.ulstu.service.MethodParamBruteForce;
import ru.ulstu.services.TimeSeriesService; import ru.ulstu.service.TimeSeriesService;
@RestController @RestController
@RequestMapping(ApiConfiguration.API_1_0) @RequestMapping(ApiConfiguration.API_1_0)

View File

@ -1,4 +1,10 @@
package ru.ulstu.controllers; /*
* 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.controller;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -10,8 +16,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.configuration.ApiConfiguration; import ru.ulstu.configuration.ApiConfiguration;
import ru.ulstu.models.TimeSeries; import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.services.UtilService; import ru.ulstu.service.UtilService;
@RestController @RestController
@RequestMapping(ApiConfiguration.API_1_0) @RequestMapping(ApiConfiguration.API_1_0)

View File

@ -1,4 +1,12 @@
package ru.ulstu.models; /*
* 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.datamodel;
import ru.ulstu.datamodel.ts.TimeSeries;
public class ForecastParams { public class ForecastParams {
private TimeSeries originalTimeSeries; private TimeSeries originalTimeSeries;

View File

@ -0,0 +1,21 @@
/*
* 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.datamodel;
import ru.ulstu.datamodel.ts.TimeSeries;
public abstract class Model {
protected final TimeSeries timeSeriesModel;
protected Model(TimeSeries ts) {
timeSeriesModel = new TimeSeries("Model of", ts.getName());
}
public TimeSeries getTimeSeriesModel() {
return timeSeriesModel;
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.datamodel;
import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.method.Method;
import ru.ulstu.method.MethodParamValue;
import java.util.List;
public class ModelingResult {
private final TimeSeries timeSeries;
private final List<MethodParamValue> paramValues;
private final Score score;
private final Method method;
public ModelingResult(TimeSeries timeSeries,
List<MethodParamValue> paramValues,
Score score,
Method method) {
this.timeSeries = timeSeries;
this.paramValues = paramValues;
this.score = score;
this.method = method;
}
public TimeSeries getTimeSeries() {
return timeSeries;
}
public List<MethodParamValue> getParamValues() {
return paramValues;
}
public Score getScore() {
return score;
}
public Method getTimeSeriesMethod() {
return method;
}
}

View File

@ -1,12 +1,10 @@
/* /*
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
* * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*
* *
*/ */
package ru.ulstu.models; package ru.ulstu.datamodel;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import ru.ulstu.score.ScoreMethod; import ru.ulstu.score.ScoreMethod;

View File

@ -0,0 +1,13 @@
/*
* 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.datamodel.exception;
public class ForecastValidateException extends ModelingException {
public ForecastValidateException(String message) {
super(message);
}
}

View File

@ -0,0 +1,13 @@
/*
* 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.datamodel.exception;
public class ModelingException extends Exception {
public ModelingException(String message) {
super(message);
}
}

View File

@ -0,0 +1,13 @@
/*
* 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.datamodel.exception;
public class TimeSeriesValidateException extends ModelingException {
public TimeSeriesValidateException(String message) {
super(message);
}
}

View File

@ -1,4 +1,10 @@
package ru.ulstu.models.response; /*
* 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.datamodel.response;
class ControllerResponse<D, E> { class ControllerResponse<D, E> {
private final D data; private final D data;

View File

@ -1,4 +1,10 @@
package ru.ulstu.models.response; /*
* 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.datamodel.response;
class ControllerResponseError<D> { class ControllerResponseError<D> {
private final ErrorConstants description; private final ErrorConstants description;

View File

@ -1,4 +1,10 @@
package ru.ulstu.models.response; /*
* 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.datamodel.response;
public enum ErrorConstants { public enum ErrorConstants {
UNKNOWN(0, "Unknown error"), UNKNOWN(0, "Unknown error"),

View File

@ -1,4 +1,10 @@
package ru.ulstu.models.response; /*
* 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.datamodel.response;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;

View File

@ -1,4 +1,10 @@
package ru.ulstu.models.response; /*
* 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.datamodel.response;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;

View File

@ -1,4 +1,10 @@
package ru.ulstu.models; /*
* 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.datamodel.ts;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
@ -14,6 +20,10 @@ public class TimeSeries {
this.name = name; this.name = name;
} }
public TimeSeries(String prefix, String suffix) {
this.name = String.format("%s %s", prefix, suffix);
}
@JsonCreator @JsonCreator
public TimeSeries(@JsonProperty(value = "values") List<TimeSeriesValue> values, @JsonProperty(value = "name") String name) { public TimeSeries(@JsonProperty(value = "values") List<TimeSeriesValue> values, @JsonProperty(value = "name") String name) {
this.values = values; this.values = values;
@ -78,6 +88,13 @@ public class TimeSeries {
throw new RuntimeException("Индекс выходит за границы временного ряда"); throw new RuntimeException("Индекс выходит за границы временного ряда");
} }
public TimeSeriesValue getValue(int t) {
if ((values.size() > t) && (t >= 0)) {
return values.get(t);
}
throw new RuntimeException("Индекс выходит за границы временного ряда");
}
@Override @Override
public String toString() { public String toString() {
return "TimeSeries{" + return "TimeSeries{" +

View File

@ -1,4 +1,10 @@
package ru.ulstu.models; /*
* 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.datamodel.ts;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;

View File

@ -1,20 +1,19 @@
/* /*
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
* * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*
* *
*/ */
package ru.ulstu.tsMethods; package ru.ulstu.method;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import ru.ulstu.TimeSeriesUtils; import ru.ulstu.TimeSeriesUtils;
import ru.ulstu.models.TimeSeries; import ru.ulstu.datamodel.Model;
import ru.ulstu.models.TimeSeriesValue; import ru.ulstu.datamodel.exception.ForecastValidateException;
import ru.ulstu.models.exceptions.ForecastValidateException; import ru.ulstu.datamodel.exception.ModelingException;
import ru.ulstu.models.exceptions.ModelingException; import ru.ulstu.datamodel.exception.TimeSeriesValidateException;
import ru.ulstu.models.exceptions.TimeSeriesValidateException; import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.datamodel.ts.TimeSeriesValue;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.List; import java.util.List;
@ -22,69 +21,51 @@ import java.util.List;
/** /**
* Наиболее общая логика моделировании и прогнозирования временных рядов * Наиболее общая логика моделировании и прогнозирования временных рядов
*/ */
public abstract class TimeSeriesMethod { public abstract class Method {
@JsonIgnore
protected TimeSeries originalTimeSeries;
@JsonIgnore
private TimeSeries model;
public abstract TimeSeriesMethod createFor(TimeSeries originalTimeSeries);
@JsonIgnore @JsonIgnore
public abstract List<MethodParameter> getAvailableParameters(); public abstract List<MethodParameter> getAvailableParameters();
public abstract TimeSeriesMethod setAvailableParameters(List<TimeSeriesMethodParamValue> parameters);
/**
* Возвращает модельное представление временного ряда: для тех же точек времени что и в параметре timeSeries
* строится модель. Количество точек может быть изменено: сокращено при сжатии ряда, увеличено при интерполяции.
* Метод является шаблонным, выполняет операции валидации исходного ряда и потом его моделирование
*
* @throws ModelingException генерируется, если есть проблемы моделирования при задании параметров
*/
protected void makeModel() throws ModelingException {
validateTimeSeries();
model = getModelOfValidTimeSeries();
}
/** /**
* Возвращает модельное представление валидного временного ряда: для тех же точек времени что и в параметре timeSeries * Возвращает модельное представление валидного временного ряда: для тех же точек времени что и в параметре timeSeries
* строится модель. Количество точек может быть изменено: сокращено при сжатии ряда, увеличено при интерполяции. * строится модель. Количество точек может быть изменено: сокращено при сжатии ряда, увеличено при интерполяции.
* *
* @return модельное представление временного ряда * @return модель временного ряда
*/ */
protected abstract TimeSeries getModelOfValidTimeSeries() throws ModelingException; protected abstract Model getModelOfValidTimeSeries(TimeSeries timeSeries,
List<MethodParamValue> parameters) throws ModelingException;
/**
* Возвращает модельное представление временного ряда: для тех же точек времени что и в параметре timeSeries
* строится модель. Количество точек может быть изменено: сокращено при сжатии ряда, увеличено при интерполяции.
* Метод является шаблонным, выполняет операции валидации исходного ряда и потом его моделирование
* <p>
* return модельное представление временного ряда
*
* @throws ModelingException генерируется, если есть проблемы моделирования при задании параметров
*/
public Model getModel(TimeSeries timeSeries, List<MethodParamValue> parameters) throws ModelingException {
validateTimeSeries(timeSeries);
validateAdditionalParams(timeSeries, parameters);
return getModelOfValidTimeSeries(timeSeries, parameters);
}
/** /**
* Выполняет построение прогноза временного ряда. Даты спрогнозированных точек будут сгенерированы по модельным точкам. * Выполняет построение прогноза временного ряда. Даты спрогнозированных точек будут сгенерированы по модельным точкам.
* *
* @param countPoints количество точек для прогнозирования * @param model модель временного ряда, включающая все нужные компоненты
* @param forecast заготовка временного ряда для прогноза с датами и нужным количеством точек для прогнозирования
* @return прогноз временного ряда * @return прогноз временного ряда
*/ */
public TimeSeries getForecastWithValidParams(int countPoints) throws ModelingException { protected abstract TimeSeries getForecastWithValidParams(Model model, TimeSeries forecast) throws ModelingException;
TimeSeries forecast = generateEmptyForecastPoints(originalTimeSeries, countPoints);
getModel();
forecast.getFirstValue().setValue(originalTimeSeries.getLastValue().getValue());
forecast = makeForecast(forecast);
return forecast;
}
/** public boolean canMakeForecast(TimeSeries timeSeries, int countPoints) {
* Выполняет построение прогноза для уже сгенерированных будущих точек временного ряда. try {
* validateTimeSeries(timeSeries);
* @param forecast Заготовка прогноза временного ряда с пустыми значениями validateForecastParams(countPoints);
* @return временной ряд прогноза } catch (ModelingException ex) {
*/ return false;
protected abstract TimeSeries makeForecast(TimeSeries forecast) throws ModelingException;
protected TimeSeries generateEmptyForecastPoints(TimeSeries modelTimeSeries, int countPointForecast) {
long diffMilliseconds = TimeSeriesUtils.getTimeDifferenceInMilliseconds(originalTimeSeries);
TimeSeries forecast = new TimeSeries("Forecast of " + originalTimeSeries.getName());
forecast.addValue(new TimeSeriesValue(modelTimeSeries.getLastValue().getDate()));
for (int i = 1; i < countPointForecast + 1; i++) {
forecast.addValue(new TimeSeriesValue(forecast.getValues().get(i - 1).getDate().plus(diffMilliseconds, ChronoUnit.MILLIS)));
} }
return forecast; return true;
} }
/** /**
@ -94,9 +75,24 @@ public abstract class TimeSeriesMethod {
* @param countPoints количество точек для прогнозирования * @param countPoints количество точек для прогнозирования
* @return прогноз временного ряда * @return прогноз временного ряда
*/ */
public TimeSeries getForecast(int countPoints) throws ModelingException { public TimeSeries getForecast(TimeSeries timeSeries,
List<MethodParamValue> parameters,
int countPoints) throws ModelingException {
validateForecastParams(countPoints); validateForecastParams(countPoints);
return getForecastWithValidParams(countPoints); Model model = getModel(timeSeries, parameters);
TimeSeries forecast = generateEmptyForecastPoints(model.getTimeSeriesModel(), countPoints);
forecast.getFirstValue().setValue(model.getTimeSeriesModel().getLastValue().getValue());
return getForecastWithValidParams(model, forecast);
}
protected TimeSeries generateEmptyForecastPoints(TimeSeries model, int countPointForecast) {
long diffMilliseconds = TimeSeriesUtils.getTimeDifferenceInMilliseconds(model);
TimeSeries forecast = new TimeSeries("Forecast of " + model.getName());
forecast.addValue(new TimeSeriesValue(model.getLastValue().getDate()));
for (int i = 1; i < countPointForecast + 1; i++) {
forecast.addValue(new TimeSeriesValue(forecast.getValues().get(i - 1).getDate().plus(diffMilliseconds, ChronoUnit.MILLIS)));
}
return forecast;
} }
private void validateForecastParams(int countPoints) throws ForecastValidateException { private void validateForecastParams(int countPoints) throws ForecastValidateException {
@ -105,41 +101,22 @@ public abstract class TimeSeriesMethod {
} }
} }
protected void validateTimeSeries() throws ModelingException { protected void validateTimeSeries(TimeSeries timeSeries) throws ModelingException {
if (originalTimeSeries == null || originalTimeSeries.isEmpty()) { if (timeSeries == null || timeSeries.isEmpty()) {
throw new TimeSeriesValidateException("Временной ряд должен быть не пустым"); throw new TimeSeriesValidateException("Временной ряд должен быть не пустым");
} }
if (originalTimeSeries.getLength() < 2) { if (timeSeries.getLength() < 2) {
throw new TimeSeriesValidateException("Временной ряд должен содержать хотя бы 2 точки"); throw new TimeSeriesValidateException("Временной ряд должен содержать хотя бы 2 точки");
} }
if (originalTimeSeries.getValues().stream().anyMatch(val -> val == null || val.getValue() == null)) { if (timeSeries.getValues().stream().anyMatch(val -> val == null || val.getValue() == null)) {
throw new TimeSeriesValidateException("Временной ряд содержит пустые значения"); throw new TimeSeriesValidateException("Временной ряд содержит пустые значения");
} }
if (originalTimeSeries.getValues().stream().anyMatch(val -> val.getDate() == null)) { if (timeSeries.getValues().stream().anyMatch(val -> val.getDate() == null)) {
throw new TimeSeriesValidateException("Временной ряд должен иметь отметки времени"); throw new TimeSeriesValidateException("Временной ряд должен иметь отметки времени");
} }
validateAdditionalParams();
} }
protected void validateAdditionalParams() throws ModelingException { protected void validateAdditionalParams(TimeSeries timeSeries, List<MethodParamValue> parameters) throws ModelingException {
} }
public TimeSeries getModel() throws ModelingException {
//TODO: what if always run?
//if (model == null) {
makeModel();
//}
return model;
}
public boolean canMakeForecast(int countPoints) {
try {
validateTimeSeries();
validateForecastParams(countPoints);
} catch (ModelingException ex) {
return false;
}
return true;
}
} }

View File

@ -0,0 +1,25 @@
/*
* 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.method;
public class MethodParamValue {
protected MethodParameter parameter;
protected Number value;
public MethodParamValue(MethodParameter parameter, Number value) {
this.parameter = parameter;
this.value = value;
}
public MethodParameter getParameter() {
return parameter;
}
public Number getValue() {
return value;
}
}

View File

@ -1,12 +1,10 @@
/* /*
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
* * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*
* *
*/ */
package ru.ulstu.tsMethods; package ru.ulstu.method;
import java.util.List; import java.util.List;

View File

@ -0,0 +1,97 @@
/*
* 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.method.exponential.addtrendaddseason;
import org.springframework.stereotype.Component;
import ru.ulstu.datamodel.Model;
import ru.ulstu.datamodel.exception.ModelingException;
import ru.ulstu.datamodel.exception.TimeSeriesValidateException;
import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.method.Method;
import ru.ulstu.method.MethodParamValue;
import ru.ulstu.method.MethodParameter;
import ru.ulstu.method.exponential.parameter.Season;
import java.util.List;
@Component
public class AddTrendAddSeason extends Method {
@Override
protected Model getModelOfValidTimeSeries(TimeSeries ts, List<MethodParamValue> parameters) {
AddTrendAddSeasonModel model = new AddTrendAddSeasonModel(ts, parameters);
List<Double> sComponent = model.getSmoothedComponent();
List<Double> tComponent = model.getTrendComponent();
List<Double> iComponent = model.getSeasonComponent();
sComponent.add(ts.getFirstValue().getValue());
TimeSeries tsModel = model.getTimeSeriesModel();
iComponent.add(1.0);
tComponent.add(0.0);
tsModel.addValue(ts.getFirstValue());
//выполняется проход модели по сглаживанию
for (int t = 1; t < model.getSeason().getValue().intValue(); t++) {
sComponent.add(model.getAlpha().getDoubleValue() * ts.getNumericValue(t)
+ (1 - model.getAlpha().getDoubleValue())
* (sComponent.get(t - 1) + tComponent.get(t - 1)));
tComponent.add(model.getBeta().getDoubleValue()
* (sComponent.get(t) - sComponent.get(t - 1))
+ (1 - model.getBeta().getDoubleValue()) * tComponent.get(t - 1));
iComponent.add(model.getGamma().getDoubleValue() * ts.getNumericValue(t) / sComponent.get(sComponent.size() - 1)
+ (1 - model.getGamma().getDoubleValue()) * iComponent.get(0));
tsModel.addValue(ts.getValues().get(t), sComponent.get(sComponent.size() - 1));
}
for (int t = model.getSeason().getIntValue(); t < ts.getValues().size(); t++) {
sComponent.add(model.getAlpha().getDoubleValue() * ts.getNumericValue(t)
/ iComponent.get(t - model.getSeason().getIntValue())
+ (1 - model.getAlpha().getDoubleValue())
* (sComponent.get(t - 1) + tComponent.get(t - 1)));
tComponent.add(model.getBeta().getDoubleValue()
* (sComponent.get(t) - sComponent.get(t - 1))
+ (1 - model.getBeta().getDoubleValue()) * tComponent.get(t - 1));
iComponent.add(model.getGamma().getDoubleValue() * ts.getNumericValue(t) / sComponent.get(sComponent.size() - 1)
+ (1 - model.getGamma().getDoubleValue()) * iComponent.get(t - model.getSeason().getIntValue()));
tsModel.addValue(ts.getValue(t), sComponent.get(sComponent.size() - 1));
}
return model;
}
@Override
protected void validateAdditionalParams(TimeSeries ts, List<MethodParamValue> parameters) throws ModelingException {
for (MethodParamValue parameter : parameters) {
if (parameter.getParameter() instanceof Season) {
if (ts.getLength() < parameter.getValue().intValue()) {
throw new TimeSeriesValidateException("Период больше чем длина ряда");
}
}
}
}
@Override
protected TimeSeries getForecastWithValidParams(Model model, TimeSeries forecast) {
AddTrendAddSeasonModel currentModel = (AddTrendAddSeasonModel) model;
List<Double> sComponent = currentModel.getSmoothedComponent();
List<Double> tComponent = currentModel.getTrendComponent();
List<Double> iComponent = currentModel.getSeasonComponent();
for (int t = 1; t < forecast.getLength(); t++) {
iComponent.add(currentModel.getGamma().getDoubleValue() * forecast.getNumericValue(t - 1) / sComponent.get(sComponent.size() - 1)
+ (1 - currentModel.getGamma().getDoubleValue()) * iComponent.get(t + model.getTimeSeriesModel().getLength() - currentModel.getSeason().getIntValue()));
forecast.getValues().get(t).setValue((sComponent.get(sComponent.size() - 1) + tComponent.get(tComponent.size() - 1) * t)
* iComponent.get(t + model.getTimeSeriesModel().getLength() - currentModel.getSeason().getIntValue()));
}
return forecast;
}
@Override
public List<MethodParameter> getAvailableParameters() {
return AddTrendAddSeasonModel.getAvailableParameters();
}
}

View File

@ -0,0 +1,80 @@
/*
* 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.method.exponential.addtrendaddseason;
import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.method.MethodParamValue;
import ru.ulstu.method.MethodParameter;
import ru.ulstu.method.exponential.parameter.Alpha;
import ru.ulstu.method.exponential.parameter.Beta;
import ru.ulstu.method.exponential.parameter.ExponentialMethodParamValue;
import ru.ulstu.method.exponential.parameter.Gamma;
import ru.ulstu.method.exponential.parameter.Season;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AddTrendAddSeasonModel extends ru.ulstu.datamodel.Model {
private final ExponentialMethodParamValue<Alpha> alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5);
private final ExponentialMethodParamValue<Beta> beta = new ExponentialMethodParamValue<>(Beta.getInstance(), 0.5);
private final ExponentialMethodParamValue<Gamma> gamma = new ExponentialMethodParamValue<>(Gamma.getInstance(), 0.5);
private final ExponentialMethodParamValue<Season> season = new ExponentialMethodParamValue<>(Season.getInstance(), 12);
private final List<Double> smoothedComponent = new ArrayList<>();
private final List<Double> trendComponent = new ArrayList<>();
private final List<Double> seasonComponent = new ArrayList<>();
public AddTrendAddSeasonModel(TimeSeries ts, List<MethodParamValue> parameters) {
super(ts);
for (MethodParamValue 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());
}
}
}
public List<Double> getSmoothedComponent() {
return smoothedComponent;
}
public List<Double> getTrendComponent() {
return trendComponent;
}
public List<Double> getSeasonComponent() {
return seasonComponent;
}
public ExponentialMethodParamValue<Alpha> getAlpha() {
return alpha;
}
public ExponentialMethodParamValue<Beta> getBeta() {
return beta;
}
public ExponentialMethodParamValue<Gamma> getGamma() {
return gamma;
}
public ExponentialMethodParamValue<Season> getSeason() {
return season;
}
public static List<MethodParameter> getAvailableParameters() {
return Arrays.asList(Alpha.getInstance(), Beta.getInstance(), Gamma.getInstance(), Season.getInstance());
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.method.exponential.addtrendnoseason;
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 AddTrendNoSeason extends Method {
@Override
protected Model getModelOfValidTimeSeries(TimeSeries ts, List<MethodParamValue> parameters) {
AddTrendNoSeasonModel model = new AddTrendNoSeasonModel(ts, parameters);
List<Double> sComponent = model.getSmoothedComponent();
List<Double> tComponent = model.getTrendComponent();
sComponent.add(ts.getFirstValue().getValue());
TimeSeries tsModel = model.getTimeSeriesModel();
sComponent.add(ts.getFirstValue().getValue());
tComponent.add(ts.getValue(1).getValue() - ts.getValue(0).getValue());
tsModel.addValue(ts.getFirstValue());
//выполняется проход модели по сглаживанию
for (int t = 1; t < ts.getValues().size(); t++) {
sComponent.add(model.getAlpha().getDoubleValue() * ts.getNumericValue(t)
+ (1 - model.getAlpha().getDoubleValue())
* (sComponent.get(t - 1) - tComponent.get(t - 1)));
tComponent.add(model.getBeta().getDoubleValue()
* (sComponent.get(t) - sComponent.get(t - 1))
+ (1 - model.getBeta().getDoubleValue()) * tComponent.get(t - 1));
tsModel.addValue(ts.getValues().get(t), sComponent.get(sComponent.size() - 1));
}
return model;
}
@Override
protected TimeSeries getForecastWithValidParams(Model model, TimeSeries forecast) {
AddTrendNoSeasonModel currentModel = (AddTrendNoSeasonModel) model;
List<Double> sComponent = currentModel.getSmoothedComponent();
List<Double> tComponent = currentModel.getTrendComponent();
for (int t = 1; t < forecast.getLength(); t++) {
forecast.getValues().get(t).setValue(sComponent.get(sComponent.size() - 1) + tComponent.get(tComponent.size() - 1) * t);
}
return forecast;
}
@Override
public List<MethodParameter> getAvailableParameters() {
return AddTrendNoSeasonModel.getAvailableParameters();
}
}

View File

@ -0,0 +1,57 @@
/*
* 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.method.exponential.addtrendnoseason;
import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.method.MethodParamValue;
import ru.ulstu.method.MethodParameter;
import ru.ulstu.method.exponential.parameter.Alpha;
import ru.ulstu.method.exponential.parameter.Beta;
import ru.ulstu.method.exponential.parameter.ExponentialMethodParamValue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AddTrendNoSeasonModel extends ru.ulstu.datamodel.Model {
private final ExponentialMethodParamValue<Alpha> alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5);
private final ExponentialMethodParamValue<Beta> beta = new ExponentialMethodParamValue<>(Beta.getInstance(), 0.5);
private final List<Double> smoothedComponent = new ArrayList<>();
private final List<Double> trendComponent = new ArrayList<>();
public AddTrendNoSeasonModel(TimeSeries ts, List<MethodParamValue> parameters) {
super(ts);
for (MethodParamValue parameter : parameters) {
if (parameter.getParameter() instanceof Alpha) {
alpha.setValue(parameter.getValue());
}
if (parameter.getParameter() instanceof Beta) {
beta.setValue(parameter.getValue());
}
}
}
public List<Double> getSmoothedComponent() {
return smoothedComponent;
}
public List<Double> getTrendComponent() {
return trendComponent;
}
public ExponentialMethodParamValue<Alpha> getAlpha() {
return alpha;
}
public ExponentialMethodParamValue<Beta> getBeta() {
return beta;
}
public static List<MethodParameter> getAvailableParameters() {
return Arrays.asList(Alpha.getInstance(), Beta.getInstance());
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.method.exponential.notrendnoseason;
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 NoTrendNoSeason extends Method {
@Override
protected NoTrendNoSeasonModel getModelOfValidTimeSeries(TimeSeries ts,
List<MethodParamValue> parameters) {
NoTrendNoSeasonModel model = new NoTrendNoSeasonModel(ts, parameters);
List<Double> sComponent = model.getSmoothedComponent();
sComponent.add(ts.getFirstValue().getValue());
TimeSeries tsModel = model.getTimeSeriesModel();
tsModel.addValue(ts.getFirstValue());
//выполняется проход модели по сглаживанию
for (int t = 1; t < ts.getValues().size(); t++) {
sComponent.add(sComponent.get(t - 1)
+ model.getAlpha().getDoubleValue()
* (ts.getNumericValue(t) - sComponent.get(t - 1)));
tsModel.addValue(ts.getValue(t), sComponent.get(sComponent.size() - 1));
}
return model;
}
@Override
protected TimeSeries getForecastWithValidParams(Model model, TimeSeries forecast) {
for (int t = 1; t < forecast.getLength(); t++) {
forecast.getValues().get(t).setValue(forecast.getValues().get(t - 1).getValue());
}
return forecast;
}
@Override
public List<MethodParameter> getAvailableParameters() {
return NoTrendNoSeasonModel.getAvailableParameters();
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.method.exponential.notrendnoseason;
import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.method.MethodParamValue;
import ru.ulstu.method.MethodParameter;
import ru.ulstu.method.exponential.parameter.Alpha;
import ru.ulstu.method.exponential.parameter.ExponentialMethodParamValue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class NoTrendNoSeasonModel extends ru.ulstu.datamodel.Model {
private final ExponentialMethodParamValue<Alpha> alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5);
private final List<Double> smoothedComponent = new ArrayList<>();
public NoTrendNoSeasonModel(TimeSeries ts, List<MethodParamValue> parameters) {
super(ts);
for (MethodParamValue parameter : parameters) {
if (parameter.getParameter() instanceof Alpha) {
alpha.setValue(parameter.getValue());
}
}
}
public List<Double> getSmoothedComponent() {
return smoothedComponent;
}
public ExponentialMethodParamValue<Alpha> getAlpha() {
return alpha;
}
public static List<MethodParameter> getAvailableParameters() {
return Collections.singletonList(Alpha.getInstance());
}
}

View File

@ -4,7 +4,7 @@
* *
*/ */
package ru.ulstu.tsMethods.exponential.parameter; package ru.ulstu.method.exponential.parameter;
public class Alpha extends ExponentialMethodParameter { public class Alpha extends ExponentialMethodParameter {
public Alpha() { public Alpha() {

View File

@ -4,7 +4,7 @@
* *
*/ */
package ru.ulstu.tsMethods.exponential.parameter; package ru.ulstu.method.exponential.parameter;
public class Beta extends ExponentialMethodParameter { public class Beta extends ExponentialMethodParameter {
public Beta() { public Beta() {

View File

@ -1,12 +1,10 @@
/* /*
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
* * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*
* *
*/ */
package ru.ulstu.tsMethods.exponential.parameter; package ru.ulstu.method.exponential.parameter;
public class ExponentialMethodParamValue<T extends ExponentialMethodParameter> { public class ExponentialMethodParamValue<T extends ExponentialMethodParameter> {
private final T param; private final T param;

View File

@ -4,10 +4,10 @@
* *
*/ */
package ru.ulstu.tsMethods.exponential.parameter; package ru.ulstu.method.exponential.parameter;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import ru.ulstu.tsMethods.MethodParameter; import ru.ulstu.method.MethodParameter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -4,7 +4,7 @@
* *
*/ */
package ru.ulstu.tsMethods.exponential.parameter; package ru.ulstu.method.exponential.parameter;
public class Gamma extends ExponentialMethodParameter { public class Gamma extends ExponentialMethodParameter {
public Gamma() { public Gamma() {

View File

@ -4,7 +4,7 @@
* *
*/ */
package ru.ulstu.tsMethods.exponential.parameter; package ru.ulstu.method.exponential.parameter;
public class Season extends ExponentialMethodParameter { public class Season extends ExponentialMethodParameter {
private final static int DEFAULT_SEASON_OPTIMIZATION_STEP = 1; private final static int DEFAULT_SEASON_OPTIMIZATION_STEP = 1;

View File

@ -1,47 +0,0 @@
/*
*
* * 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.TimeSeriesMethod;
import ru.ulstu.tsMethods.TimeSeriesMethodParamValue;
import java.util.List;
public class ModelingResult {
private final TimeSeries timeSeries;
private final List<TimeSeriesMethodParamValue> paramValues;
private final Score score;
private final TimeSeriesMethod timeSeriesMethod;
public ModelingResult(TimeSeries timeSeries,
List<TimeSeriesMethodParamValue> paramValues,
Score score,
TimeSeriesMethod timeSeriesMethod) {
this.timeSeries = timeSeries;
this.paramValues = paramValues;
this.score = score;
this.timeSeriesMethod = timeSeriesMethod;
}
public TimeSeries getTimeSeries() {
return timeSeries;
}
public List<TimeSeriesMethodParamValue> getParamValues() {
return paramValues;
}
public Score getScore() {
return score;
}
public TimeSeriesMethod getTimeSeriesMethod() {
return timeSeriesMethod;
}
}

View File

@ -1,7 +0,0 @@
package ru.ulstu.models.exceptions;
public class ForecastValidateException extends ModelingException {
public ForecastValidateException(String message) {
super(message);
}
}

View File

@ -1,7 +0,0 @@
package ru.ulstu.models.exceptions;
public class ModelingException extends Exception {
public ModelingException(String message) {
super(message);
}
}

View File

@ -1,7 +0,0 @@
package ru.ulstu.models.exceptions;
public class TimeSeriesValidateException extends ModelingException {
public TimeSeriesValidateException(String message) {
super(message);
}
}

View File

@ -4,7 +4,7 @@
* *
*/ */
package ru.ulstu.pages; package ru.ulstu.page;
import org.primefaces.model.chart.AxisType; import org.primefaces.model.chart.AxisType;
import org.primefaces.model.chart.DateAxis; import org.primefaces.model.chart.DateAxis;
@ -14,11 +14,11 @@ import org.primefaces.model.chart.LineChartSeries;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import ru.ulstu.models.TimeSeries; import ru.ulstu.datamodel.exception.ModelingException;
import ru.ulstu.models.TimeSeriesValue; import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.models.exceptions.ModelingException; import ru.ulstu.datamodel.ts.TimeSeriesValue;
import ru.ulstu.services.TimeSeriesService; import ru.ulstu.service.TimeSeriesService;
import ru.ulstu.services.UtilService; import ru.ulstu.service.UtilService;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped; import javax.faces.view.ViewScoped;

View File

@ -1,17 +1,15 @@
/* /*
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
* * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*
* *
*/ */
package ru.ulstu.score; package ru.ulstu.score;
import ru.ulstu.models.Score; import ru.ulstu.datamodel.Score;
import ru.ulstu.models.TimeSeries; import ru.ulstu.datamodel.exception.ModelingException;
import ru.ulstu.models.TimeSeriesValue; import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.models.exceptions.ModelingException; import ru.ulstu.datamodel.ts.TimeSeriesValue;
public abstract class ScoreMethod { public abstract class ScoreMethod {
private final String name; private final String name;

View File

@ -1,16 +1,14 @@
/* /*
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved
* * Copyright (C) 2021 Anton Romanov - All Rights Reserved * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
* * You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*
* *
*/ */
package ru.ulstu.score; package ru.ulstu.score;
import ru.ulstu.models.TimeSeries; import ru.ulstu.datamodel.exception.ModelingException;
import ru.ulstu.models.TimeSeriesValue; import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.models.exceptions.ModelingException; import ru.ulstu.datamodel.ts.TimeSeriesValue;
import static java.lang.Math.abs; import static java.lang.Math.abs;

View File

@ -4,17 +4,18 @@
* *
*/ */
package ru.ulstu.services; package ru.ulstu.service;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.ulstu.models.ModelingResult; import ru.ulstu.datamodel.Model;
import ru.ulstu.models.TimeSeries; import ru.ulstu.datamodel.ModelingResult;
import ru.ulstu.models.exceptions.ModelingException; import ru.ulstu.datamodel.exception.ModelingException;
import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.method.Method;
import ru.ulstu.method.MethodParamValue;
import ru.ulstu.method.MethodParameter;
import ru.ulstu.score.ScoreMethod; import ru.ulstu.score.ScoreMethod;
import ru.ulstu.score.Smape; import ru.ulstu.score.Smape;
import ru.ulstu.tsMethods.MethodParameter;
import ru.ulstu.tsMethods.TimeSeriesMethod;
import ru.ulstu.tsMethods.TimeSeriesMethodParamValue;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
@ -29,11 +30,11 @@ import java.util.concurrent.Future;
@Service @Service
public class MethodParamBruteForce { public class MethodParamBruteForce {
private final int DEFAULT_THREAD_COUNT = 50; private final int DEFAULT_THREAD_COUNT = 50;
private final List<TimeSeriesMethod> methods; private final List<Method> methods;
private final ScoreMethod scoreMethod = new Smape(); private final ScoreMethod scoreMethod = new Smape();
private final ExecutorService executors = Executors.newFixedThreadPool(DEFAULT_THREAD_COUNT); private final ExecutorService executors = Executors.newFixedThreadPool(DEFAULT_THREAD_COUNT);
public MethodParamBruteForce(List<TimeSeriesMethod> methods) { public MethodParamBruteForce(List<Method> methods) {
this.methods = methods; this.methods = methods;
} }
@ -49,15 +50,21 @@ public class MethodParamBruteForce {
List<Future<ModelingResult>> results = new ArrayList<>(); List<Future<ModelingResult>> results = new ArrayList<>();
List<ModelingResult> results2 = new CopyOnWriteArrayList<>(); List<ModelingResult> results2 = new CopyOnWriteArrayList<>();
try { try {
for (TimeSeriesMethod method : methods) { for (Method method : methods) {
List<List<TimeSeriesMethodParamValue>> availableParametersValues = getAvailableParametersValues(method.getAvailableParameters()); List<List<MethodParamValue>> availableParametersValues = getAvailableParametersValues(method.getAvailableParameters());
for (List<TimeSeriesMethodParamValue> parametersValues : availableParametersValues) { for (List<MethodParamValue> parametersValues : availableParametersValues) {
results.add(executors.submit(() -> { results.add(executors.submit(() -> {
TimeSeriesMethod methodInstance = method.getClass().getDeclaredConstructor().newInstance(); Method methodInstance = method.getClass().getDeclaredConstructor().newInstance();
TimeSeries model = methodInstance.createFor(timeSeries) try {
.setAvailableParameters(parametersValues) Model model = methodInstance.getModel(timeSeries, parametersValues);
.getModel(); return new ModelingResult(model.getTimeSeriesModel(),
return new ModelingResult(model, parametersValues, scoreMethod.getScore(timeSeries, model), methodInstance); parametersValues,
scoreMethod.getScore(timeSeries, model.getTimeSeriesModel()),
methodInstance);
} catch (ModelingException ex) {
ex.printStackTrace();
return null;
}
})); }));
} }
} }
@ -79,8 +86,8 @@ public class MethodParamBruteForce {
} }
} }
private List<List<TimeSeriesMethodParamValue>> getAvailableParametersValues(List<MethodParameter> availableParameters) { private List<List<MethodParamValue>> getAvailableParametersValues(List<MethodParameter> availableParameters) {
List<List<TimeSeriesMethodParamValue>> result = new ArrayList<>(); List<List<MethodParamValue>> result = new ArrayList<>();
Map<MethodParameter, Integer> parameterOffset = new TreeMap<>(); Map<MethodParameter, Integer> parameterOffset = new TreeMap<>();
Map<MethodParameter, List<Number>> parameterValues = new TreeMap<>(); Map<MethodParameter, List<Number>> parameterValues = new TreeMap<>();
for (MethodParameter methodParameter : availableParameters) { for (MethodParameter methodParameter : availableParameters) {
@ -88,9 +95,9 @@ public class MethodParamBruteForce {
parameterValues.put(methodParameter, methodParameter.getAvailableValues()); parameterValues.put(methodParameter, methodParameter.getAvailableValues());
} }
while (!isAllValuesUsed(parameterOffset, parameterValues)) { while (!isAllValuesUsed(parameterOffset, parameterValues)) {
List<TimeSeriesMethodParamValue> resultRow = new ArrayList<>(); List<MethodParamValue> resultRow = new ArrayList<>();
for (MethodParameter methodParameter : parameterOffset.keySet()) { for (MethodParameter methodParameter : parameterOffset.keySet()) {
resultRow.add(new TimeSeriesMethodParamValue(methodParameter, resultRow.add(new MethodParamValue(methodParameter,
parameterValues.get(methodParameter).get(parameterOffset.get(methodParameter)))); parameterValues.get(methodParameter).get(parameterOffset.get(methodParameter))));
} }
incrementOffset(parameterOffset, parameterValues); incrementOffset(parameterOffset, parameterValues);

View File

@ -4,18 +4,17 @@
* *
*/ */
package ru.ulstu.services; package ru.ulstu.service;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.ulstu.models.TimeSeries; import ru.ulstu.datamodel.exception.ModelingException;
import ru.ulstu.models.exceptions.ModelingException; import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.tsMethods.TimeSeriesMethod; import ru.ulstu.method.Method;
import ru.ulstu.tsMethods.exponential.AddTrendAddSeason; import ru.ulstu.method.exponential.addtrendaddseason.AddTrendAddSeason;
import ru.ulstu.tsMethods.exponential.NoTrendNoSeason;
import ru.ulstu.tsMethods.exponential.parameter.Alpha; import java.util.Collections;
import ru.ulstu.tsMethods.exponential.parameter.ExponentialMethodParamValue;
@Service @Service
@ -28,10 +27,9 @@ public class TimeSeriesService {
} }
public TimeSeries getForecast(TimeSeries timeSeries, int countPoints) throws ModelingException { public TimeSeries getForecast(TimeSeries timeSeries, int countPoints) throws ModelingException {
TimeSeriesMethod method; Method method;
method = new NoTrendNoSeason().createFor(timeSeries).setAlpha(new ExponentialMethodParamValue<>(new Alpha(), 0.8)); method = new AddTrendAddSeason();
method = new AddTrendAddSeason().createFor(timeSeries); return method.getForecast(timeSeries, Collections.emptyList(), countPoints);
return method.getForecast(countPoints);
} }
public TimeSeries smoothTimeSeries(TimeSeries timeSeries) throws ModelingException { public TimeSeries smoothTimeSeries(TimeSeries timeSeries) throws ModelingException {

View File

@ -1,11 +1,17 @@
package ru.ulstu.services; /*
* 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.service;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.ulstu.TimeSeriesUtils; import ru.ulstu.TimeSeriesUtils;
import ru.ulstu.models.TimeSeries; import ru.ulstu.datamodel.ts.TimeSeries;
import ru.ulstu.models.TimeSeriesValue; import ru.ulstu.datamodel.ts.TimeSeriesValue;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Arrays; import java.util.Arrays;

View File

@ -1,27 +0,0 @@
/*
*
* * 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;
}
}

View File

@ -1,144 +0,0 @@
/*
* 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.exponential;
import org.springframework.stereotype.Component;
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.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;
@Component
public class AddTrendAddSeason extends TimeSeriesMethod {
private ExponentialMethodParamValue<Alpha> alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5);
private ExponentialMethodParamValue<Beta> beta = new ExponentialMethodParamValue<>(Beta.getInstance(), 0.5);
private ExponentialMethodParamValue<Gamma> gamma = new ExponentialMethodParamValue<>(Gamma.getInstance(), 0.5);
private ExponentialMethodParamValue<Season> season = new ExponentialMethodParamValue<>(Season.getInstance(), 12);
private final List<Double> sComponent = new ArrayList<>();
private final List<Double> tComponent = new ArrayList<>();
private final List<Double> iComponent = new ArrayList<>();
public AddTrendAddSeason createFor(TimeSeries timeSeries) {
this.originalTimeSeries = timeSeries;
return this;
}
public AddTrendAddSeason setAlpha(ExponentialMethodParamValue<Alpha> alpha) {
this.alpha = alpha;
return this;
}
public AddTrendAddSeason setBeta(ExponentialMethodParamValue<Beta> beta) {
this.beta = beta;
return this;
}
public AddTrendAddSeason setGamma(ExponentialMethodParamValue<Gamma> gamma) {
this.gamma = gamma;
return this;
}
public AddTrendAddSeason setSeason(ExponentialMethodParamValue<Season> season) {
this.season = season;
return this;
}
@Override
protected TimeSeries getModelOfValidTimeSeries() throws ModelingException {
sComponent.clear();
tComponent.clear();
iComponent.clear();
iComponent.add(1.0);
sComponent.add(originalTimeSeries.getFirstValue().getValue());
tComponent.add(0.0);
TimeSeries model = new TimeSeries("Model of " + originalTimeSeries.getName());
model.addValue(originalTimeSeries.getFirstValue());
//выполняется проход модели по сглаживанию
for (int t = 1; t < season.getValue().intValue(); t++) {
sComponent.add(alpha.getDoubleValue() * originalTimeSeries.getNumericValue(t)
+ (1 - alpha.getDoubleValue())
* (sComponent.get(t - 1) + tComponent.get(t - 1)));
tComponent.add(beta.getDoubleValue()
* (sComponent.get(t) - sComponent.get(t - 1))
+ (1 - beta.getDoubleValue()) * tComponent.get(t - 1));
iComponent.add(gamma.getDoubleValue() * originalTimeSeries.getNumericValue(t) / sComponent.get(sComponent.size() - 1)
+ (1 - gamma.getDoubleValue()) * iComponent.get(0));
model.addValue(originalTimeSeries.getValues().get(t), sComponent.get(sComponent.size() - 1));
}
for (int t = season.getIntValue();
t < originalTimeSeries.getValues().size(); t++) {
sComponent.add(alpha.getDoubleValue() * originalTimeSeries.getNumericValue(t)
/ iComponent.get(t - season.getIntValue())
+ (1 - alpha.getDoubleValue())
* (sComponent.get(t - 1) + tComponent.get(t - 1)));
tComponent.add(beta.getDoubleValue()
* (sComponent.get(t) - sComponent.get(t - 1))
+ (1 - beta.getDoubleValue()) * tComponent.get(t - 1));
iComponent.add(gamma.getDoubleValue() * originalTimeSeries.getNumericValue(t) / sComponent.get(sComponent.size() - 1)
+ (1 - gamma.getDoubleValue()) * iComponent.get(t - season.getIntValue()));
model.addValue(originalTimeSeries.getValues().get(t), sComponent.get(sComponent.size() - 1));
}
return model;
}
@Override
protected void validateAdditionalParams() throws ModelingException {
if (originalTimeSeries.getLength() < season.getIntValue()) {
throw new TimeSeriesValidateException("Период больше чем длина ряда");
}
}
@Override
protected TimeSeries makeForecast(TimeSeries forecast) throws ModelingException {
TimeSeries model = getModel();
for (int t = 1; t < forecast.getLength(); t++) {
iComponent.add(gamma.getDoubleValue() * forecast.getNumericValue(t - 1) / sComponent.get(sComponent.size() - 1)
+ (1 - gamma.getDoubleValue()) * iComponent.get(t + model.getLength() - season.getIntValue()));
forecast.getValues().get(t).setValue((sComponent.get(sComponent.size() - 1) + tComponent.get(tComponent.size() - 1) * t)
* iComponent.get(t + model.getLength() - season.getIntValue()));
}
return forecast;
}
@Override
public List<MethodParameter> getAvailableParameters() {
return Arrays.asList(alpha.getParam(), beta.getParam(), gamma.getParam(), season.getParam());
}
@Override
public TimeSeriesMethod setAvailableParameters(List<TimeSeriesMethodParamValue> 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;
}
}

View File

@ -1,93 +0,0 @@
/*
*
* * 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.exponential;
import org.springframework.stereotype.Component;
import ru.ulstu.models.TimeSeries;
import ru.ulstu.tsMethods.MethodParameter;
import ru.ulstu.tsMethods.TimeSeriesMethod;
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 ExponentialMethodParamValue<Alpha> alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5);
private ExponentialMethodParamValue<Beta> beta = new ExponentialMethodParamValue<>(Beta.getInstance(), 0.5);
private final List<Double> sComponent = new ArrayList<>();
private final List<Double> tComponent = new ArrayList<>();
public AddTrendNoSeason createFor(TimeSeries timeSeries) {
this.originalTimeSeries = timeSeries;
return this;
}
public AddTrendNoSeason setAlpha(ExponentialMethodParamValue<Alpha> alpha) {
this.alpha = alpha;
return this;
}
public AddTrendNoSeason setBeta(ExponentialMethodParamValue<Beta> beta) {
this.beta = beta;
return this;
}
@Override
protected TimeSeries getModelOfValidTimeSeries() {
sComponent.clear();
tComponent.clear();
sComponent.add(originalTimeSeries.getFirstValue().getValue());
tComponent.add(originalTimeSeries.getValues().get(1).getValue() - originalTimeSeries.getValues().get(0).getValue());
TimeSeries model = new TimeSeries("Model of " + originalTimeSeries.getName());
model.addValue(originalTimeSeries.getFirstValue());
//выполняется проход модели по сглаживанию
for (int t = 1; t < originalTimeSeries.getValues().size(); t++) {
sComponent.add(alpha.getDoubleValue() * originalTimeSeries.getNumericValue(t)
+ (1 - alpha.getDoubleValue())
* (sComponent.get(t - 1) - tComponent.get(t - 1)));
tComponent.add(beta.getDoubleValue()
* (sComponent.get(t) - sComponent.get(t - 1))
+ (1 - beta.getDoubleValue()) * tComponent.get(t - 1));
model.addValue(originalTimeSeries.getValues().get(t), sComponent.get(sComponent.size() - 1));
}
return model;
}
@Override
protected TimeSeries makeForecast(TimeSeries forecast) {
for (int t = 1; t < forecast.getLength(); t++) {
forecast.getValues().get(t).setValue(sComponent.get(sComponent.size() - 1) + tComponent.get(tComponent.size() - 1) * t);
}
return forecast;
}
@Override
public List<MethodParameter> getAvailableParameters() {
return Arrays.asList(alpha.getParam(), beta.getParam());
}
@Override
public TimeSeriesMethod setAvailableParameters(List<TimeSeriesMethodParamValue> 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;
}
}

View File

@ -1,74 +0,0 @@
/*
* 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.exponential;
import org.springframework.stereotype.Component;
import ru.ulstu.models.TimeSeries;
import ru.ulstu.tsMethods.MethodParameter;
import ru.ulstu.tsMethods.TimeSeriesMethod;
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> alpha = new ExponentialMethodParamValue<>(Alpha.getInstance(), 0.5);
private final List<Double> sComponent = new ArrayList<>();
public NoTrendNoSeason createFor(TimeSeries timeSeries) {
this.originalTimeSeries = timeSeries;
return this;
}
public NoTrendNoSeason setAlpha(ExponentialMethodParamValue<Alpha> alpha) {
this.alpha = alpha;
return this;
}
@Override
protected TimeSeries getModelOfValidTimeSeries() {
sComponent.clear();
sComponent.add(originalTimeSeries.getFirstValue().getValue());
TimeSeries model = new TimeSeries("Model of " + originalTimeSeries.getName());
model.addValue(originalTimeSeries.getFirstValue());
//выполняется проход модели по сглаживанию
for (int t = 1; t < originalTimeSeries.getValues().size(); t++) {
sComponent.add(sComponent.get(t - 1)
+ alpha.getDoubleValue()
* (originalTimeSeries.getNumericValue(t) - sComponent.get(t - 1)));
model.addValue(originalTimeSeries.getValues().get(t), sComponent.get(sComponent.size() - 1));
}
return model;
}
@Override
protected TimeSeries makeForecast(TimeSeries forecast) {
for (int t = 1; t < forecast.getLength(); t++) {
forecast.getValues().get(t).setValue(forecast.getValues().get(t - 1).getValue());
}
return forecast;
}
@Override
public List<MethodParameter> getAvailableParameters() {
return Collections.singletonList(alpha.getParam());
}
@Override
public TimeSeriesMethod setAvailableParameters(List<TimeSeriesMethodParamValue> parameters) {
for (TimeSeriesMethodParamValue parameter : parameters) {
if (parameter.getParameter() instanceof Alpha) {
alpha.setValue(parameter.getValue());
}
}
return this;
}
}