FunctionArrayReduce
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © RicardoSantos

//@version=5

// @description A limited method to reduce a array using a mathematical formula.
library(title="FunctionArrayReduce")

import RicardoSantos/StringEvaluation/4 as stre
import RicardoSantos/DebugConsole/2 as console
[__T, __C] = console.init(20)

// @function Method to reduce a array using a mathematical formula.
// @param formula string, the mathematical formula, accepts some default name codes (index, output, previous, current, integer index of arguments array).
// @param samples float array, the data to process.
// @param arguments float array, the extra arguments of the formula.
// @param initial_value float, default=0, a initial base value for the process.
// @returns float.
// Notes:
//      ** if initial value is specified as "na" it will default to the first element of samples.
//      ** expression needs to have atleast one operation.
export float_ (string formula, float[] samples, float[] arguments, float initial_value=0.0) => //{
	int _size_f = str.length(formula)
	int _size_s = array.size(samples)
	int _size_a = array.size(arguments)
	//
	switch
	    (_size_f < 1) => runtime.error('FunctionArrayReduce -> float_(): "formula" is empty.')
	    (_size_s < 1) => runtime.error('FunctionArrayReduce -> float_(): "samples" has the wrong size.')
	//
	// index the keywords for the evaluation.
	string _shape = formula
	_shape := str.replace_all(_shape, 'index', str.tostring(_size_a + 0, '#'))
	_shape := str.replace_all(_shape, 'output', str.tostring(_size_a + 1, '#'))
	_shape := str.replace_all(_shape, 'previous', str.tostring(_size_a + 2, '#'))
	_shape := str.replace_all(_shape, 'current', str.tostring(_size_a + 3, '#'))
	// TODO: extra keywords?
	//
	float _output = na(initial_value) ? array.get(samples, 0) : initial_value
	// evaluate first element?
	if _size_s > 1
    	for _i = 1 to _size_s - 1
	        float _previous = array.get(samples, _i - 1)
	        float _current = array.get(samples, _i)
	        _output := stre.eval(_shape, array.concat(array.copy(arguments), array.from(_i, _output, _previous, _current)))
    _output
//{ usage:
console.queue_one(__C, str.format('last index: {0}', float_('output - output + current', array.from(0.0, 1, 2, 3, 4), array.new_float(0))))
console.queue_one(__C, str.format('sum of multiplication of value by index: {0}', float_('output + previous * index', array.from(0.0, 1, 2, 3, 4), array.new_float(0), 1)))
console.queue_one(__C, str.format('using arguments: {0}', float_('output + previous * 0 - 1', array.from(0.0, 1, 2, 3, 4), array.new_float(3, 3.3))))
console.queue_one(__C, str.format('sum of squares: {0}', float_('output + current ^ 0', array.from(0.0, 1, 2, 3, 4), array.new_float(1, 2))))
console.queue_one(__C, str.format('sum of positive direction of change: {0}', float_('output + current >= previous', array.from(0.0, 1, 2, 3, 4), array.new_float(1, 2))))
console.queue_one(__C, str.format('strenght of direction: {0}', float_('output + (current >= previous) - (current <= previous)', array.from(0.0, 1, 3, 2, 3), array.new_float(1, 2))))
//{ remarks
//      ** if initial value is specified as "na" it will default to the first element of samples.
//      ** expression needs to have atleast one operation.
//}}}



console.update(__T, __C)