using StructureHelperCommon.Infrastructures.Exceptions; using StructureHelperCommon.Infrastructures.Interfaces; using StructureHelperCommon.Models; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace StructureHelperCommon.Models.Calculators { public class FindParameterCalculator : IFindParameterCalculator { private double start, end; private Predicate predicate; private FindParameterResult result; private double precision; private int maxIterationCount; private double current; private double step; private int iterationNum; public string Name { get; set; } public IFindParameterCalculatorInputData InputData { get; set; } public IAccuracy Accuracy { get; set; } public IResult Result => result; public Action ActionToOutputResults { get; set; } public IShiftTraceLogger? TraceLogger { get; set; } public Guid Id => throw new NotImplementedException(); public FindParameterCalculator() { InputData = new FindParameterCalculatorInputData(); Accuracy = new Accuracy() { IterationAccuracy = 0.001d, MaxIterationCount = 1000 }; } public FindParameterCalculator(IShiftTraceLogger? traceLogger) : this() { TraceLogger = traceLogger; } public void Run() { result = new(); try { start = InputData.StartValue; end = InputData.EndValue; predicate = InputData.Predicate; FindMinimumValue(); } catch (Exception ex) { result.IsValid = false; result.Description += ex; } } public object Clone() { throw new NotImplementedException(); } private void FindMinimumValue() { TraceLogger?.AddMessage($"Calculating parameter by iterations is started,\nrequired precision {Accuracy.IterationAccuracy}"); if (predicate(end) == false) { TraceLogger?.AddMessage($"Predicate for end value must be true", TraceLogStatuses.Error); throw new StructureHelperException(ErrorStrings.DataIsInCorrect + ": predicate for end value must be true"); } precision = Accuracy.IterationAccuracy; maxIterationCount = Accuracy.MaxIterationCount; current = start; step = (end - start) / 2d; iterationNum = 0; while (step > precision) { ProcessIteration(); } TraceLogger?.AddMessage($"Parameter value Cur={current} was found,\nCalculation has finished succefully"); result.Parameter = current; result.Description = "Parameter was found succefully"; result.IsValid = true; ActionToOutputResults?.Invoke(result); } private void ProcessIteration() { TraceLogger?.AddMessage($"Iteration number {iterationNum} is started", TraceLogStatuses.Debug); if (predicate(current) == true) { TraceLogger?.AddMessage($"Predicate value in {current} is true", TraceLogStatuses.Debug, 50); end = current; } else { TraceLogger?.AddMessage($"Predicate value in {current} is false", TraceLogStatuses.Debug, 50); start = current; } current = (start + end) / 2d; TraceLogger?.AddMessage($"New current value Cur=({start}+{end})/2={current}", TraceLogStatuses.Debug); step = (end - start) / 2d; TraceLogger?.AddMessage($"New step S={current}", TraceLogStatuses.Debug, 50); iterationNum++; result.IsValid = false; result.IterationNumber = iterationNum; result.CurrentAccuracy = step; ActionToOutputResults?.Invoke(result); if (iterationNum > maxIterationCount) { TraceLogger?.AddMessage($"Recuired precision was not achieved, current step {step}, required precision {precision}", TraceLogStatuses.Error); result.Description = "Parameter was not found succefully: \n"; throw new StructureHelperException(ErrorStrings.DataIsInCorrect + ": violation of iteration count"); } } } }