Closed victorel-petrovich closed 2 months ago
if you look at the source code you will see that we always use 4 consecutive values of a sequence, we use the last value to calculate the error, we predict the 4th value and since we have the original 4th value we can calculate the difference by subtracting the prediction from the last value. this could be applied in consecutive layers with more values of a sequence, the implementation is only one layer, but the same could be done recursively the more elements of the series we have. It works on practically any data sequence that does not involve prime numbers from OEIS.org. you can try it with hundreds of sequences from this website. for example https://oeis.org/A001318
Algorithm just use last 4 consecutive inputs of a sequence . I recommend use the code published https://github.com/pedroelbanquero/geometric-extrapolation/blob/main/Probnet.hs
Thanks for replying, but it's still not clear at all. I'm not familiar with Haskell... So I just want to understand the idea of the algorithm.
I had understood how to get the predicted 21.125, as 13*(13/8).
Also how to get the entire list of predicted values:
[4.0,4.5,8.333333333333334,12.8,21.125]
And how to get the list of errors as true-predicted
:
[-1.0,0.5,-0.3333333333333339,0.1999999999999993]
But what is not clear is how do you get next value for error: -0.1333333333333331
?
It seems to be -0.3333333333333339+0.1999999999999993
, but why would you add them ?
Trying to get it in same way as 21.125 was obtained, it fails: 0.199*(0.199/-0.33)= -0.12 , not -0.13333
Is it explained somewhere else? even in another language; I can translate.
I also looked at https://github.com/pedroelbanquero/geometric-extrapolation?tab=readme-ov-file#conclusion and the numbers there at the end:
round $ ((3*1.66)-5) + (5*1.6) = 8
appear to be wrong: d2=5/3=1.6666 not 1.6 and d1=3/2=1.5 not 1.666
More importantly, why is the formula:
fnos (m,n,d1,d2) = round ( ( ( n * d1 ) - m ) + ( m * d2 ) )
?
prediction= m * d2
, ok;
error= true-prediction
true=prediction+error = prediction + (true-prediction)
So should not error be m-(n*d1)
as opposed to ( n * d1 ) - m
?
The idea of the algorithm is simple, we predict each next element of the sequence and compare it with the original series, generating a sequence of errors, then we predict what the next error would be, then we predict the next element of the series and subtract the error we have made from the prediction.
You're right, the formula example is wrong. Because example is 1,2,3,5,8,13 , i made wrong copy paste when i put as a math formula
https://hackage.haskell.org/package/Probnet
.... 5/3 = 1.666 8/5 = 1.6 13/8 = 1.625 ....
Algo works fine i just made a bad math explanation sorry I will correct it as soon as possible
then we predict what the next error would be
how exactly? because the numbers in your 2 examples don't work out.
On the example that you have just corrected:
round $ ((3*1.5)-5) + (5*1.66) = 8
eq (1)
(3*1.5)-5) + (5*1.66)=-0.5+8.333 = 7.833
, so round(7.833)= 8, you get the right value, but it seems to be an accident:
3*1.5-5
= old prediction - old true =4.5 -5 = -0.5
, so error = true-prediction = 0.5
So to get true value, starting from prediction, you need to do:
prediction -(prediction-true) = prediction + (true-prediction) = prediction + error
But in eq(1) above, you have contradiction:
(old prediction - old true)+new prediction
-- which means you have: prediction - error
yes , as the same way, you have the sequence of errors [-1.0,0.5,-0.3333333333333339,0.1999999999999993]
5 - 4.5 = 0.5 8 - 8.3333 = -0.333333 13 -12.8.... = 0.1999999
as we extrapolate the values with the function [4.0,4.5,8.333333333333334,12.8,21.125] we do the same with the errors
ghci> predict1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993]
-0.1333333333333331
the result on this case fibbonacci sequence
ghci> - 0.1333 + 21.125
20.9917
ghci> round it
21
in the example of math function one part of the formula is the error and other the extrapolation as you comment before
error + extrapolation
error = ( n d1 ) - m ) extrapolation = ( m d2 )
anyway the best, is use the haskell code, I'm not really good on math , and i do that some years ago from a dream I had
to use the code just type in console after install haskell
ghci Probnet.hs
this will load the haskell script , and you can play with the functions . haskell functions have more cases to solve another things like cyclic patterns, anyway algo is not finished , just take in consideration 1 layer , and not have implemented yet frequency variation of the dataset , just pseudo cyclic patterns with same frequency for example 12345,12345,12345 but not 12345,123456,1234567 .... this is pending yet . i do the algorithm from logic's and after i was trying to explain in math terms , but I'm not really good on math ..... if you are, i can share my ideas to you or we can develop more over the repo . i really appreciate your interest , you are the first interested on that HAHA .
Thanks for the example correction , i corrected also on Wikipedia page https://en.wikipedia.org/wiki/Extrapolation
is not an accident, you can apply that to many many sequence just test that on haskell and you can check , really crazy data sequences until infinite with no error of prediction let me show some
ghci> probnet 3 [2, 10, 24, 44, 70, 102, 140, 184, 234, 290, 352, 420, 494] [2,10,24,44,70,102,140,184,234,290,352,420,494,574,660,752]
ghci> probnet 3 [6, 30, 72, 132, 210, 306, 420, 552, 702] [6,30,72,132,210,306,420,552,702,870,1056,1260]
thousands of sequences , incremental sequences for the algo now because is a simple version polynomials with different degree can be solved with the same function
algo can be improved a lot yet, taking care of frequencies, and incremental and decrement , changes and combine , and also adding probability issues of the dataset , and recursion layer for error prediction, for example some sequence are not correct, but have another layer of errors, for example [0,1,0,1,0,1] this happens with many sequences also that not solve correctly but can be improved to solve with another layer of errors, i think is some kind of principle of AI for maths, another way to solve math functions , with no model, well the model is just the input data
also can be used as notation of functions keeping the main points of sequence , many sequence starts with same numbers but in some point converges to another sequence, sometimes seems algo not works for a sequence but when you get the sample data more in the "future" of the dataset, at this "moment" / "index" , sequence will be solved until infinite with 100 % accuracy .
in reality i was trying to encode information as the functions who generate the information instead of encode the observable data, but i found that , i imagine information as a some point of a data sequence in the future and idea was try to encode the beginning points of a sequence and the moments to arrive to this future of information . this was the motivation, but as i said I'm just amateur on this things and no many academic knowledge , please share your discoverers if you find something more
Thanks for your replies. I did not doubt that your program works. But just could not understand the explanations / numbers.
Yes, I find the whole idea interesting. Maybe later we can discuss future improvments for the algorithm.
But for now, let's finish correcting the explanation you have written for the shorter example. I think now I know what is going on:
For the example with extrapolating the value after 13, (21.125), you have produced the new error = -0.1333, by calling predict1 function on the sequence of (true) errors [-1.0,0.5,-0.3333333333333339,0.1999999999999993]
But for the example for extrapolating value after 5, (8.33), to get the new error= -0.5, you did not use predict1 on errors [-1.0,0.5]
but instead you have implicitely written error= (3*1.5-5)
.
Which is misleading.
Can you please test at your command line:
ghci> predict1 [-1.0 , 0.5 ]
I can't because function need at least 4 consecutive points , reason because example with just 1,2,3,5 was not good example and example with haskell is until 13 of fibo sequence by this reason. i need to review the code to know how i solve that because works anyway, let me review
ghci> probnet 7 [1,2,3,5]
[1,2,3,5,8,13,21,34,55,89,144]
my apologies to be a disaster guy , let me a moment
My understanding is this:
the algorithm should extrapolate the sequence of (true) errors [-1.0 , 0.5 ]
using same idea as it extrapolated from [1 2 3 5]
: 5*(5/3) = 8.333
Thus, extrapolation for errors is : 0.5*(0.5/-1) = -0.25
.
And this works: round (8.333 + -0.25 ) = 8
= true value
But if I use same ideas for extrapolation beyond [-1.0,0.5,-0.3333333333333339,0.1999999999999993]
, then get new error = 0.2*(0.2/-0.3333) = -0.12
.
This is different from -0.133333 you wrote earlier, but works:
round (21.125 + -0.12 ) = round (21.005) = 21
= true value
-- | Generate new prediction with error prediction
probnet :: (Integral b, RealFrac a) => Int -> [a] -> [b]
probnet layers dat
| layers > 1 = probnet (layers - 1) $ map (\x-> fromIntegral (round x)) out
| otherwise = fmap round out
where
out = dat ++ [(predict1 dat + prerr dat)]
-- | This is the next prediction for the difference between each
-- original element and its prediction based on previous elements
prerr :: RealFrac a => [a] -> a
prerr dat
| last err == 0 = 0
| otherwise = predict1 $ drop 2 err
where
err = zipWith subtract pred dat -- differences between elements and its predictions
pred = fmap predict1 $ inits dat -- 2 first inits have 0 and 1 elements, will be dropped
This is what is doing exactly the haskell code, is right is not the good explanation in math form
ghci> prerr [1,2,3,5]
-0.25
ghci> predict
predict predict1
ghci> predict1 [1,2,3,5]
8.333333333333334
ghci> it - 0.25
8.083333333333334
prerr for [1,2,3,5] is -0.25 you are right
and I guess if you check prerr [1,2,3,5, 8, 13]
you will get about -0.12
ghci> prerr [1,2,3,5,8,13] -0.1333333333333331
no in this case i get -0.1333333333333331
maybe by number of decimals ?
predict1 :: RealFrac a => [a] -> a
predict1 dat
-- | l1 == (eleml+1) = (ratio1 (dat) (eleml+1)) * last dat
| otherwise = (ratio1 dat eleml) * last dat
where
Just eleml = elemIndex ned dat
ned = nearnum (last $ dat) (init dat)
l1 = length dat
l = last $ init dat
lastper = last dat
nearnum :: RealFrac a => a -> [a] -> a
nearnum n = minimumBy nearer
where
nearer x y = compare (abs (x - n)) (abs (y - n))
nearnum compare if is LT or GT
I got that -0.12 as explained in 2nd paragraph in https://github.com/pedroelbanquero/geometric-extrapolation/issues/1#issuecomment-2278952452
but now I guess that since we have a sequence of 4 (not just 2) values (of errors), [-1.0,0.5,-0.3333333333333339,0.1999999999999993]
, the algo will apply recursively, just like in case of 4 values [ 1,2,3,5], and so it will attempt to improve on the -0.12 extrapolation.
I'll check on paper and let you know.
Cool man , thanks so much, we will make corrections on Wikipedia, was wrong some years HAHAHA,
feel free to pull request your modifications on README and i will merge
I tested my guess above (that the algo does to the sequence of errors same thing as for initial sequence, recursively),doesn't work:
Below, 0.(3) means 0.33333...
1 2 3 5 8 13
4 4.5 8.(3) 12.8 21.125
-------------------------------------------------------------------
-1 0.5 -0.(3) 0.2
-0.25 0.(2) -0.12
-------------------------------------------------------------------
-0.08(3) -0.0(2)
-0.0059(259)
-0.0059(259) + -0.12 + 21.125 = -0.1(259) + 21.125 = 20.999074
For extrapolated error, gives ~ -0.1259, not -0.13333 . So you code must be doing something different to predict / extrapolate the error values. Maybe another hint is that in Readme, you mentioned that you would not apply this algorithm to values that alternate in sign; the errors here do.
Guess #2: on Readme, https://github.com/pedroelbanquero/geometric-extrapolation?tab=readme-ov-file#sequences-with-quasi-cyclic-pattern , you say " the ratio used for prediction will be the one of the element whose value is closest to the last element." -- perhaps in the algo you apply this idea to any sequence ?
If so, then the closest to 0.2 is 0.5, and the closest to -0.333 is -1, so we get:
1 2 3 5 8 13
4 4.5 8.(3) 12.8 21.125
-------------------------------------------------------------------
-1 0.5 -0.(3) 0.2
-0.25 0.1(6) -0.1(3)
-------------------------------------------------------------------
-0.08(3) 0.0(3)
-0.01(3)
-0.01(3) + -0.1(3) + 21.125 =~ -0.146666 + 21.125 = 20.97833
The predicted error is -0.146666, still not -0.13333. hmm
Guess #3: your algo does not predict next error in exactly same way as predicting next value in sequence. Namely, it produces first extrapolation for error, and stops here, without trying to improve it recursively (by computing more past extrapolations and then again computing errors ) the way I describe above in guess # 2
To test this, please run the following:
ghci> probnet 1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993]
ghci> probnet 1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993] [-1,0,0,0,0]
this not works by the rounds i think
ghci> probnet 1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993] [-1,0,0,0,0] ghci> predict1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993] -0.1333333333333331 ghci> prerr [-1.0,0.5,-0.3333333333333339,0.1999999999999993] -1.3333333333332434e-2
take in consideration de nearest function , who get the LT or GT
If you want, we can get to the bottom of this if you change a bit the program so that it doesn't round at the end , then run that probnet 1 [ [-1, 0.5, -1/3, 0.2 ]
or , even better, add in the program some print statements to print all the important lists: the values, the predicted (extrapolated) values, the errors the predictions for errors the errors from last predictions again
So that we get something similar to the "tables" in my replies above.
let me prepare the debug
ghci> probnet 1 [-1, 0.5, -1/3, 0.2 ] [-1.0,0.5,-0.3333333333333333,0.2,-0.1466666666666667] ghci> probnet 1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993] [-1.0,0.5,-0.3333333333333339,0.1999999999999993,-0.14666666666666556]
predict1 :: RealFrac a => [a] -> a predict1 dat -- | l1 == (eleml+1) = (ratio1 (dat) (eleml+1)) * last dat | otherwise = (ratio1 dat eleml) * last dat where Just eleml = elemIndex ned dat ned = nearnum (last $ dat) (init dat) l1 = length dat l = last $ init dat lastper = last dat nearnum :: RealFrac a => a -> [a] -> a nearnum n = minimumBy nearer where nearer x y = compare (abs (x - n)) (abs (y - n))
let me debug also this function, and nearest function
ghci> ratio1 [1,2,3,5,8,13,21] 2 1.6666666666666667 ghci> ratio1 [1,2,3,5,8,13,21] 3 1.6 ghci> ratio1 [1,2,3,5,8,13,21] 4 1.625 ghci> ratio1 [1,2,3,5,8,13,21] 5 1.6153846153846154
Guess #2: on Readme, https://github.com/pedroelbanquero/geometric-extrapolation?tab=readme-ov-file#sequences-with-quasi-cyclic-pattern , you say " the ratio used for prediction will be the one of the element whose value is closest to the last element." -- perhaps in the algo you apply this idea to any sequence ?
If so, then the closest to 0.2 is 0.5, and the closest to -0.333 is -1, so we get:
1 2 3 5 8 13 4 4.5 8.(3) 12.8 21.125 ------------------------------------------------------------------- -1 0.5 -0.(3) 0.2 -0.25 0.1(6) -0.1(3) ------------------------------------------------------------------- -0.08(3) 0.0(3) -0.01(3) -0.01(3) + -0.1(3) + 21.125 =~ -0.146666 + 21.125 = 20.97833
The predicted error is -0.146666, still not -0.13333. hmm
ghci> probnet 1 [-1, 0.5, -1/3, 0.2 ] [-1.0,0.5,-0.3333333333333333,0.2,-0.1466666666666667] ghci> probnet 1 [-1.0,0.5,-0.3333333333333339,0.1999999999999993] [-1.0,0.5,-0.3333333333333339,0.1999999999999993,-0.14666666666666556]
predict1 not add the error, probnet function add the error
Hi, thank you , yes your computation with probnet 1 confirmed that guess #3 is probably correct
If I'm right, then it makes sense not to recursively "improve" on the predicted error as that would make the algo less efficient.
take in consideration de nearest function , who get the LT or GT
I don't understand what you meant about that (I find Haskell very hard to read if you don't know the lang)
Just explai
Hi, thank you , yes your computation with probnet 1 confirmed that guess #3 is probably correct
If I'm right, then it makes sense not to recursively "improve" on the predicted error as that would make the algo less efficient.
take in consideration de nearest function , who get the LT or GT
I don't understand what you meant about that (I find Haskell very hard to read if you don't know the lang)
Just explaining what does compare function inside nearest function
ghci> compare 5 8 LT ghci> compare 8 5 GT
tell me when you have better math explanation please, to upload readme and wikipedia
I'm really glad you made an effort to understand the algorithm, thank you very much, I really appreciate it.
tell me when you have better math explanation please, to upload readme and wikipedia
I'll help improve Readme, but let's run one more check to confirm my guess #3:
Please run the following without any rounding, and I will do on paper/python based on my understanding:
seq = [ 1, 3, 5, 7, 9, 11 ]
probnet 1 seq
prerr seq
drop 2 (inits seq)
preds = fmap predict1 it
errs = zipWith subtract preds (drop 2 seq)
predict1 errs
probnet 1 errs
ghci> seq = [ 1, 3, 5, 7, 9, 11 ]
ghci> probnet 1 seq
[1.0,3.0,5.0,7.0,9.0,11.0,13.03628117913832]
ghci> prerr seq
-0.4081632653061252
ghci> drop 2 (inits seq)
[[1,3],[1,3,5],[1,3,5,7],[1,3,5,7,9],[1,3,5,7,9,11]]
ghci> preds = fmap predict1 it
ghci> errs = zipWith subtract preds (drop 2 seq)
ghci> predict1 errs
-0.4081632653061252
ghci> probnet 1 errs
[-4.0,-1.333333333333334,-0.7999999999999989,-0.571428571428573,-0.43167346938775947]
ghci>
OK, It's confirmed, to find prediction of error, your alg stops after finding first prediction for errors
>>> seq = [ 1, 3, 5, 7, 9, 11 ]
>>> seq
[1, 3, 5, 7, 9, 11]
>>> preds= [seq[i]**2/seq[i-1] for i in range(1,len(seq))]
>>> preds
[9.0, 8.333333333333334, 9.8, 11.571428571428571, 13.444444444444445]
>>> errs=[seq[i+2]-preds[i] for i in range(len(preds)-1)]
>>> errs
[-4.0, -1.333333333333334, -0.8000000000000007, -0.5714285714285712]
>>> prederrs= [errs[i]**2/errs[i-1] for i in range(1,len(errs))]
>>> prederrs
[-0.44444444444444486, -0.48000000000000065, -0.4081632653061217]
>>> errserrs=[errs[i+2]-prederrs[i] for i in range(len(prederrs)-1)]
>>> errserrs
[-0.35555555555555585, -0.09142857142857053]
>>> prederrserrs= [errserrs[i]**2/errserrs[i-1] for i in range(1,len(errserrs))]
>>> prederrserrs
[-0.02351020408163217]
>>> prederrserrs[-1]+prederrs[-1]
-0.43167346938775386
>>> next1=preds[-1]+prederrs[-1]
>>> next1
13.036281179138323
>>> next2=preds[-1]+prederrs[-1]+prederrserrs[-1]
>>> next2
13.012770975056691
do yo have final math formula ? math explanation ?
The only thing I have is the following pics with some formulas on scratch papers. V0 is the value to be predicted, V1 with line on top means initial predictions; e1, e2 are the errors.
Your method reminded me of "predictor-corrector" method in solving differential equations that I learned about in graduate school (see wikipedia). However, your approach is still very different from that, as you construct the sequence of errors and predict that. Which might be original. Bravo!
One potential issue I can think about for now is that that sequence of errors can have positive and negative and 0 values even if the sequence of values to predict has only positive values. So algorithm has to deal with the special case when one of the error values is very close to 0. Because otherwise, if you have to divide by such value, you can get big numerical error.
One way to deal with it is: when the algo needs to divide by a error value that is too close to 0 , and only in such cases, it can switch to predict the next error using not ratios but differences method.
For my part, I will try to improve some things in the future, such as the change in frequency of a data set, the curves, more error prediction layers with more than 4 points. Also, what you say about values close to 0 or 0. Thank you very much for your attention and effort to understand it, it makes me very happy that someone is interested.
Thank you for your review, I am very grateful. I really appreciate the effort you took to review it. Feel free to use what you need or improve what you see fit.
In next fragment:
how did you get the -0.1333333333333331 ? I could not obtain it by either adding or multiplying something to the last error in that sequence.
Thank you