TuringBot and 2D-3D Animation: Jumping Jack

By Giovanni Di Maria, creator of EDM Electronics Design Master

A person’s movements can be represented using mathematical formulas. With the help of TuringBot it is possible to translate into numbers all the movements that this person makes. If the movements are simple, the formulas will also be simple. Conversely, complex movements can be described by longer and more complex formulas and equations. Thanks to the ability to find mathematical formulas for any type of action, robotic systems, simulations, 3D prototyping, video games and much more can be implemented.

Turning real life into numbers and formulas

To describe the movement of a person (or an animal, plant or object) on the computer, it is necessary to follow different phases and mathematically represent the set of actions that he performs. Some steps are quite complicated. This article is dedicated to the numerical representation of the movements of a man performing the “Jumping Jack” physical exercise. The steps to follow are as follows:

  • video capture;
  • cutting the video and keeping only the useful frames;
  • identification of the parts of the body in motion;
  • determination of the coordinates of the various segments;
  • symbolic regression and curve fitting of data;
  • application of the formulas and creation of a 3D model;
  • creation of final animation and comparison with the original video.

Video capture and frame selection

For this step, you need to create a video of the person in motion. It need not be very long. 3 or 4 seconds is enough, even at 15 FPS. The important thing is to acquire the sequence of useful frames, in which the athlete moves for a complete period, ie from when the human body assumes a certain position to when it returns to the same position.

You probably need to use a variety of software. When creating the video, the important thing is that the athlete is well lit and visible and, above all, the camera angle must not change. You need to trim the video to take only the useful sequence. For this example, the video consists of 29 frames. The various elements, therefore, are represented by as many positions in the two-dimensional spatial domain.

Identification of the moving parts of the body

The aim of our work is to simulate on the computer the movement of a graphic object composed simply of some segments. In fact, we are interested in the mathematical aspect of the problem and not the graphic one. The digital athlete must be created using some segments that represent the arms, legs, etc. Below we can see the athlete together with his virtual “avatar”, made up of many segments which, subsequently, will be mathematically processed. For convenience, the forearm and hand have been treated as a single segment, since the video shows them both with a single line.

The virtual athlete is composed of the following elements:

  • a circle “H” for the head, that is a circle with position X, Y and radius R;
  • by two segments “Arm1” and “Arm2” for the arms;
  • by two segments “Forearm1” and “Forearm2” for the forearms;
  • from the “Body” segment for the body;
  • by two segments “Thigh1” and “Thigh2” for the thighs;
  • by two segments “Leg1” and “Leg2” for the legs;
  • by two segments “Foot1” and “Foot2” for the feet.

Determination of the coordinates of the various segments

The determination of all the coordinates of the points of the subject is the most important and tiring phase of the whole operation. A good result depends on the precision with which the point values were taken. For each frame you need:

  • determine the X and Y coordinate of the start of a segment;
  • determine the end X and Y coordinate of the same segment.

The head is drawn with a circle, so its center (and its position) is represented by a single point, with X and Y coordinates. To evaluate the position of each point we can use any graphics program, for example ImageJ that , in real time, it shows the position of the mouse (in pixels) on the status bar and has many excellent automated selection functions that simplify a lot of work. We use this information to obtain the coordinates of the various segments.

It is a bit of a long job, where maximum precision and a lot of patience are required. At the end of the calculations it is possible to insert the results in a spreadsheet. Remember that these coordinates are relative. To transform them into absolute coordinates it is sufficient to subtract a fixed value.

With all this data available it is possible, for example, to draw the displacement graphs of some elements of the body, to discover the presence of any anomalies. For example, the following graph shows the trend of the position in the X axis and in the Y axis, during the entire movement of all the frames.

And now, TuringBot in action

All these coordinates must be transformed into mathematical formulas, even if the simplest and safest way would be to insert them into an array and process the movements within a loop. But the adoption of equations and formulas makes the operation much more elegant and faster, as well as allowing the writing of a shorter and more compact source code, with less memory consumption. It is understood that if the athlete’s movements change, the formulas must also follow the same changes. It is therefore the right time to try to represent the trends of human movements with mathematical formulas. The various nodes of the human body are represented by many points, of which it is necessary to memorize the two coordinates X and Y. It is therefore necessary to generate a considerable amount of mathematical formulas that allow to obtain a small arithmetic miracle. Some points are in common, so they use the same formulas.

For each coordinate of each point it is necessary to create a text file for TuringBot, containing two columns. The data is, of course, taken from the giant spreadsheet. We show below the example for the X coordinate of the head, but the other files follow the same rule.

x y
1 190
2 190
3 190
4 189
5 189
6 188
7 188
8 187
9 186
10 186
11 185
12 184
13 184
14 184
15 184
16 185
17 185
18 186
19 186
20 187
21 188
22 188
23 188
24 189
25 190
26 190
27 191
28 192
29 192

The TuringBot setting is as follows:

  • Search metric: RMS error;
  • Train / test split: No cross validation;
  • Test sample: Chosen randomly;
  • Integer constants only: Disabled;
  • Bound search mode: Deactivated;
  • Maximum formula complexity: 60;
  • Allowed functions: + * / sin cos exp log sqrt abs floor ceil round

For some systems, care must be taken with trigonometric functions. They work in radians in TuringBot, while for other graphics software they may work in degrees, complicating the conversion process. In our specific case, the following conversion functions were created in OpenSCAD:

function cos_deg (x) = cos (x * 180 / 3.1415);
function sin_deg (x) = sin (x * 180 / 3.1415);

A relatively low search time is sufficient for each formula, let’s say 5-10 minutes or less is more than enough. It is very interesting to observe TuringBot during the research. Its formulas are getting closer and closer to the final goal, as can be seen in the screen below.

Below there are all the formulas that describe the positions of all the coordinates of the segments that make up the virtual athlete.

Head
y01=round((2.6318+(0.0554792*((0.624893-cos(5.98948*x))*x)))*cos(0.22113*x)+187.659);
y02=131.133+round((22.2134-cos(-0.236286+1.0202*x))*cos((-0.0920179)*(((-6.27235+cos(1.1767+x))/x)+200.387*x))-cos(0.665542+0.98184*x)+(-0.312138*x)+4.11456);
Arm 1
y03=145.872-((-0.162146)*3.12725*round(cos(0.869371-round(5.96336*x))*(0.362323*x+1.77951)-(cos(-2.63665+round(-0.806851*x))/0.61255)+x));
y04=191.306+((round(cos(0.100135*(-8.17967-1.70143*round(cos(x))+x))*(1.27238*x-cos(-1.86063+x))-(cos(389.994*(x+1.88321)+0.0989649)/0.0417673))+x)/(-1.2269));
y05=round((-22.0364+ceil(-0.00500284*ceil(x)*x))*(-1.65113-cos(19.3301*(x-0.0605927))))+((30.7797/(0.161422+x))+(68.1958-cos(51.0009*x))-cos(x));
y06=exp(3.04946+cos(2.45808*(-0.0870771*x)+0.138404)+1.14937)+(98.0591+round(sin(round(0.980629*x)))+((6.65119-cos(exp(0.0876617*x)))*cos(0.695886*(2.86001+x))));
Forearm 1
y07=y05;
y08=y06;
y09=(82.9424-5.26613*cos(0.586505*x))*(cos((-0.373595)*(x+exp(round(0.702127*x)-(0.498511+round(0.81141*x)))+1.08672))+1.09296)-cos(x+1.33121);
y10=24.2181-floor((6.34302+(-0.112064*x))*round(cos(0.553976+x)))+abs(12.7211+x-((0.650495*x-11.0444)*round(3.27817*((cos((-0.730758)*(0.273942+x))/0.755489)+(x-12.8353)))));
Body 1
y11=2.89195*cos(1.94668*0.118136*floor(0.631336-(0.929462*x+cos(exp(0.91244*x))))+(0.00305925/cos(x)))+186.109;
y12=round(168.264-(ceil(23.9806*cos((-2.32409+(-0.00596887+x))/0.00939977))+1.57128*cos(-1.18468*x))-(cos(x)+(1.91115*(cos(7.08496*(-0.288919+x))+0.109288*x))));
y13=round(185.474-0.0754086*x)+round(cos((-0.991109+0.0450943*x)*(0.928695*x+log(x))));
y14=302.57-round(0.656922*x)-(3.72319*cos(0.92024*(0.811155+x))+round((0.357329-x*cos(0.448989*(5.09698+x)))*(-0.0148642*x+((-0.214389*cos(61*x)*(4.88954-x)-25.1065)/x))));
Thigh 1
y15=(3.73138+((-2.81755)/x)-1.5051*sin(round(0.797607*x+0.247816)+3.30139))*(-0.514093+cos(0.205523*(cos(round((-4.32537)*(x+((-1.0676)/x))))+x)))+164.175;
y16=round(291.396-((0.865647*x+13.9971)*cos(x+568-0.562408*x)))-3.78295*cos(0.889973*(1.67606+x))-((-68.1261)/(1.44242*cos(x-0.362494*x)+x));
y17=18.9883*cos(-12.8305*floor(-2.33066+x))+(0.0747105*(7.00189-(0.0741629/cos(x))+x)*cos(509.575*x))+(148.027+round(cos(x+0.658366))+(-0.209201*round(x)));
y18=390.962+(round((-0.602733)*(cos(0.747127*x-0.621592)+0.177481)*(-13.466-cos(round((-0.957067)/cos(x)))+cos(x*x)+x))+27.0249*cos(0.457091*(-0.671057+(2.28055-x))));
Leg 1
y19=y17;
y20=y18;
y21=((4.54964+(-0.104918*x)+0.86746)*cos(0.908546*x+2.08515)+22.7637)*cos(-0.111712*cos(0.935385*x)+6.70845*0.0314056*1*x)+(155.963-(x/3.08672));
y22=(13.6737-round((x-1.93818)*(0.289077+cos(-0.619872+x))))*(-0.0369057+round(3.95993/(x+1.89954)))+478.649+round(cos(0.116577*(-3.69209*x))*round(0.549631*(2.80209+x)));
Foot 1
y23=y21;
y24=y22;
y25=139.272+round(41.4532+(5.65241*cos(1.93845+0.927451*x)+(-0.313033*x)))*cos(0.233247*(cos(0.93121*(0.497331+x))+(1.53881-x)));
y26=round(0.608219/x)+(round(531.435-exp(sin((-0.579902)*(-1.04537+x))-round(cos((-0.437731)*(-1.0422+x)))))-1.74977*round(-0.0192443*x));
Arm 2
y27=215.61+(round(-6.43715+((0.0859084*x-cos(0.942479-x))*cos(x-1.00562)))*cos((0.294155+(-0.00453909*cos(x)))*(4.12657+x))+round(16.3707/(1.00701+0.237835*x)));
y28=11.6855*cos(0.807271*x-x)+round((cos((-0.423063)*(x-0.93908))/(0.0525671+(-0.000435858*x)))-log(x)*cos(0.888721*(2.08408+x)))+178.346;
y29=268.152-cos(x)-round(cos(13.3713*x))-round((2.85905+(cos(x/0.00529412)+(30.6583/x)))*(cos((-0.503562)*(3.04348+x))/(-0.441047+0.0116418*x)));
y30=round(190.29-((0.274471*(x-1.03236)-cos(x)+4.1627)*cos(0.498517*(x+3.46653))))+((77.1759+8.48446*cos(-0.610676*x))*cos(-0.201617*x));
Forearm 2
y31=y29;
y32=y30;
y33=round(-0.249366*x)+291.228+(-12.6244*cos((-0.820511)*(-0.186609+x)))-(round(78.0757*cos((-0.404411)*((2.17112/(x+0.071869))+x-0.610615)))-ceil(4.08193*cos((-1.17325)*(x-0.515673))));
y34=abs(164.762+(224*cos(0.198515*x)-15.9158*cos((-0.738632)*(1.55249+x)))-8.63263*cos(-1.01382*x*cos(0.211738*x)+0.224974))-3.18017+6.85659*cos(x);
Thigh 2
y35=0.172415+round(210.278+1.65102*round(cos(5.80056*(0.885518+x)))+(-0.0412545*x+cos(6.98431*x)))+floor(((-0.0356155)/sin(x-18.9299))+0.158463);
y36=round(round(3.61529*cos(round(0.194003*x))+(307.838-3.51777*cos((-0.897347)*(1.61609+x)))-0.729957*x)-cos(0.471091*(5.10132+0.942463*x))*round(21.5251+0.421583*round(x)));
y37=221.338-19.8608*cos(0.208955*x)+3.4534*cos(0.449626*(cos(2.00243*x*cos(x))+(-1.68947+x)));
y38=(0.247935/(-0.632871+x-3.60529))+(395.163+((28.4837+cos(exp(x+0.642375)))*cos(0.430087*(x-0.908733)))-ceil(-0.0921263*x))-round(2.63053*cos(0.886319*(2.07703+x)));
Leg 2
y39=y37;
y40=y38;
y41=221.068-round(cos((-0.229646)*(1.00585-x))*(0.512421*x+(17.4901+((3.61754-3.39247*cos(round(0.966905*x)))*cos(-0.599782*x-(-970.82-x))))));
y42=round(((7.16092*cos(x)+2.62982)/x)+ceil(11.2742*cos(0.46229*round(2.61198-1.01162*x))))+round(1.6828*cos(23.8215*(0.0290402+x)))+481.601;
Foot 2
y43=y41;
y44=y42;
y45=233.767+((-30.4935+cos(1.96625*x))*cos((-0.253376)*(2.19983-(0.927354*x-2.38703*cos(0.421426*x-1.58061)))));
y46=530.782+((cos(0.663909*x)+cos(2.00314*x)+2.30646)*cos(0.509108*(3-x))+round(cos(0.471645-x)));

Implementation of the model

After the creation of the formulas by TuringBot, it is finally possible to implement the athlete’s mathematical model. The figure below shows the use of OpenSCAD with the created equations.

The following short list shows all software used in the project. Obviously, the user can use other software, according to their needs.

  • video recorder of a smartphone or camera;
  • Avidemux;
  • ImageMagick (convert.exe);
  • ImageJ;
  • Calc (LibreOffice);
  • and of course… TuringBot.

It is very interesting to observe the animation of the real and virtual subject at the same time.

Conclusions

By symbolic regression it is possible to convert any fact and action into a mathematical formula. These techniques are used in movies, video games, and 2D and 3D simulations. Behind a very short film, even lasting just one second, there is a lot of effort and dozens of hours of work. The adoption of mathematical formulas for the description of the points, in 2D and 3D space, gives a great touch of elegance to the project. Depending on the software used, it may be necessary to “overturn” the coordinates of the subject. The whole procedure described was very exciting and fun, even if very tiring. And the satisfaction was immense when, after all the calculations made and the implementation of the code, the digital figure acquired a life of its own and started jumping. Let us remember once again, the athlete’s movement is not produced by coordinates stored in an array, but is created using mathematical formulas. All this massive processing would not have been possible without the use of TuringBot. This is math!

The representation of the board in a Chess Engine with TuringBot

By Giovanni Di Maria, creator of EDM Electronics Design Master

A Chess Engine is a computer program that receives a move as input and returns a counter move as an answer. Here we will not delve into the theory that underlies the functioning of Chess Engines, but we will focus our attention on the representation of the chessboard relative to the initial position of a game, deepening a mathematical method to get there, using the TuringBot program.

The starting position

For those who are familiar with the game of chess, they know that the pieces are placed on the board in a very particular way, as evidenced by the figure below.

From left to right there are:

  • rook;
  • the knight;
  • the bishop;
  • Queen;
  • the king;
  • the bishop;
  • the knight;
  • rook.

The black pieces are arranged in a similar way: the Queens are on the squares of their color: the white Queen on the white square and the black Queen on the black square.

How to represent the chessboard in memory

There are many methods for representing a chessboard in memory. We focus our attention on reproducing the starting position using an 8×8 matrix. The basic idea is this, then the programmer can vary the method according to his needs. This in-memory representation is necessary because the program must know the game situation, especially at the start of the game. A possible solution, extremely clear and simple, perhaps banal, consists in memorizing the initials of the chess pieces in the matrix, distinguishing them between white and black with upper and lower case. This solution immediately provides a clear reading of the source code.

void reset_chessboard()
{
    int x, y;
    // -------Empty chessboard---------
    for (x = 1; x <= 8; x++)
        for (y = 1; y <= 8; y++)
            chessboard[x][y] = '-';
    // ----Pawns-------
    for (x = 1; x <= 8; x++)
    {
        chessboard[x][2] = 'P';
        chessboard[x][7] = 'p';
    }
    // ------knight------
    chessboard[2][1] = 'N';
    chessboard[7][1] = 'N';
    chessboard[2][8] = 'n';
    chessboard[7][8] = 'n';
    // ------Bishop--------
    chessboard[3][1] = 'B';
    chessboard[6][1] = 'B';
    chessboard[3][8] = 'b';
    chessboard[6][8] = 'b';
    // ----Rook---------
    chessboard[1][1] = 'R';
    chessboard[8][1] = 'R';
    chessboard[1][8] = 'r';
    chessboard[8][8] = 'r';
    // -----Queen-----
    chessboard[4][1] = 'Q';
    chessboard[4][8] = 'q';
    // -----King-------
    chessboard[5][1] = 'K';
    chessboard[5][8] = 'k';
    return;
}

The mathematical approach with TuringBot

A very elegant solution is to perform the processing and storage of the initial characters of the pieces through two simple nested cycles, within which a formula, found by TuringBot, calculates the ASCII code to be inserted in each cell of the matrix. The basic idea follows the diagrams illustrated below.

As can be seen in the matrix on the right (completely equivalent to the one on the left), in each element of the square matrix there is an ASCII numeric code that corresponds to the character that distinguishes each piece. The empty box is represented by a space (ASCII code 32). Recall that each box of a matrix is identified by two values, one of row and one of column. These values can be saved in a text file, consisting of 64 lines and 3 columns. It will be the TuringBot Input file.

1 1 82
1 2 78
1 3 66
1 4 81
1 5 75
1 6 66
1 7 78
1 8 82
2 1 80
2 2 80
2 3 80
2 4 80
2 5 80
2 6 80
2 7 80
2 8 80
3 1 32
3 2 32
3 3 32
3 4 32
3 5 32
3 6 32
3 7 32
3 8 32
4 1 32
4 2 32
4 3 32
4 4 32
4 5 32
4 6 32
4 7 32
4 8 32
5 1 32
5 2 32
5 3 32
5 4 32
5 5 32
5 6 32
5 7 32
5 8 32
6 1 32
6 2 32
6 3 32
6 4 32
6 5 32
6 6 32
6 7 32
6 8 32
7 1 112
7 2 112
7 3 112
7 4 112
7 5 112
7 6 112
7 7 112
7 8 112
8 1 114
8 2 110
8 3 98
8 4 113
8 5 107
8 6 98
8 7 110
8 8 114

Processing and research with TuringBot

After opening the input file in TuringBot, you can configure some search parameters to better optimize this operation. Some functions, in fact, are not necessary. In our case, the following search parameters have been entered:

  • Basic functions
    • Addition
    • Multiplication
    • Division
  • Trigonometric functions
    • cos (x)
  • Other functions
    • floor (x)

Of course you can try other functions. The search procedure is quite long as the final formula is very complex. The screenshot below shows some initial setup steps. After setting the values, you can start the search by pressing the appropriate button.

The research begins and the program begins to generate many formulas, with a solution ever closer to the final goal. A continuously updated window shows the formulas found, in order of length and error. Normally the longer formulas provide the best results.

Each formula is also characterized, of course, by a graph that should follow the trend of the original data. A perfect formula always lies above all input points.

Final results

The search field is extremely vast and a final result is not always perfect, with a difference of zero. In this case, luck wanted the system to find an excellent formula that perfectly described the initial arrangement of the pieces on the board. The search took about 4 hours, using 4 Threads. This timing obviously depends on the computer used and the number of processes used for the operation. Below are the different formulas found by TuringBot:

ComplexityErrorFunction
133.174763
529.543437.5+col1*col1
727.7461col1*(-4.42857+col1)+57.4285
818.437837.8919*sin(col1)+55.6912
917.1364128.854-(-5.76178*col1*(col1-8.20656))
1015.35447.64726*col1*sin(col1)+57.17
1213.783731.3877+(5.355*(7.2754*sin(col1)+col1))
1311.813732+(62*greater(sin(col1),0.555342))
1410.60117.09756*abs(col1+10.0746*sin(col1))
157.121(13.9153/cos(floor(0.732407*col1)))+58.555
173.8758232+(greater(sin(col1),0.415717)*(5.18918*col1+38.6487))
183.5793abs(30.9689-(-6.10071*sin(1.05488*col1)*(7.47296+col1)))
203.1130131.4802+pow(11.7402*(col1+5.71344),cos(1.04974*col1-1.56687))
273.0281231.4787+pow((11.6058+(0.68396/(col2*col2)))*(col1+5.71681),cos(1.04968*col1-1.56654))
282.4801731.4839+pow((11.6357-cos(4.18524*col2))*(col1+5.69307),cos(1.04935*col1-1.56473))
302.4222531.4835+pow((11.6154-cos(4.26395*(-0.110504+col2)))*(col1+5.69428),cos(1.04932*col1-1.56459))
332.3570632-((38.2449+((cos(col1)+4.90525)*(col1-cos((-2.01944)*(0.23205+col2)))))*floor(cos(-58.3057-col1)))
352.299232.0001-((38.2972+((1.28923*cos(col1)+4.83299)*(col1-cos(2.02027*(0.230258+col2)))))*floor(cos(-58.3057-col1)))
382.0259332.0005-(floor(cos(col1+1.83754))*(5.12705*(8.04121-((0.818858-cos(-34.9995*col1))*(cos(2.09691*col2)+0.6415))+col1)))
401.7558932.0028-(floor(cos(col1+1.78588))*(5.18838*(8.15112-((0.78022-cos(34.8496*col1+0.883278))*(cos(2.09681*col2)+0.945564))+col1)))
411.5233232-(floor(cos(col1+1.78119))*(4.96845*(8.04125-floor((0.939273-cos(34.9916*col1))*(cos(-2.0859*col2)+0.624216))+col1)))
431.1131232-(floor(cos(col1+1.8017))*(5.12004*(cos(col1)+7.83221-((0.78464-cos(-34.9183*col1))*(cos(2.09684*col2)+0.591668))+col1)))
450.76065232.0002-(floor(cos(col1+1.73726))*(5.12047*(cos(col1)+7.831-((0.783564-cos(34.9177*col1))*(cos((-2.00884)*(col2+0.259462))+0.612137))+col1)))
480.728869floor(32-(floor(cos(col1+1.73299))*(5.12841*(col1+7.95556-((0.779654-cos(34.9151*col1))*(cos(1.97953*(col2+0.346471))+0.636367))+cos(col1)))))
530.41344832.0002-(floor(cos(col1+1.81624))*(5.11899*(col1+7.82369-((0.754511-cos(-34.913*col1))*(cos((-2.01269)*(col2+(0.0352432/cos(col2))+0.268925))+0.648806))+cos(col1))))
550.1266632.0005-(floor(cos(col1+1.78631))*(5.12029*(cos(col1)+7.8269-((0.771208-cos(34.9154*col1))*(cos((-1.98154)*(col2+0.178865*cos(-5.37724+col2)+0.351792))+0.63671))+col1)))
570.058082832-(floor(cos(col1+1.81682))*(5.11347*(col1+7.83564-((0.769821-cos(-34.9072*col1))*(cos((-1.98027)*(col2+0.180734*cos(-5.38204+col2)+0.35485))+0.644024))+1.07536*cos(col1))))
580floor(32-(floor(cos(col1+1.73299))*(5.12816*(col1+7.89449-((0.770326-cos(34.9151*col1))*(cos(1.97953*(col2+0.181536*cos(-5.37362+col2)+0.35012))+0.636367))+cos(col1)))))

The final formula, therefore, which perfectly calculates the ASCII code of the piece on a box, given an “x” and “y” position, is the following:

floor(32-(floor(cos(x+1.73299))*(5.12816*(x+7.89449-((0.770326-cos(34.9151*x))*(cos(1.97953*(y+0.181536*cos(-5.37362+y)+0.35012))+0.636367))+cos(x)))))

The formula can be implemented in all programming languages. The following example was created for the PARI / GP program:

{
   for(x=1,8,
      for(y=1,8,
         z=floor(32-(floor(cos(x+1.73299))*(5.12816*(x+7.89449-((0.770326-cos(34.9151*x))*(cos(1.97953*(y+0.181536*cos(-5.37362+y)+0.35012))+0.636367))+cos(x)))))            ;
         print(x,"    ",y,"      ",z);
      );
   );
}

The execution of the simple listing, which contemplates the long but powerful mathematical formula, generates the following list of values, perfectly corresponding with the previous one.

1 1 82
1 2 78
1 3 66
1 4 81
1 5 75
1 6 66
1 7 78
1 8 82
2 1 80
2 2 80
2 3 80
2 4 80
2 5 80
2 6 80
2 7 80
2 8 80
3 1 32
3 2 32
3 3 32
3 4 32
3 5 32
3 6 32
3 7 32
3 8 32
4 1 32
4 2 32
4 3 32
4 4 32
4 5 32
4 6 32
4 7 32
4 8 32
5 1 32
5 2 32
5 3 32
5 4 32
5 5 32
5 6 32
5 7 32
5 8 32
6 1 32
6 2 32
6 3 32
6 4 32
6 5 32
6 6 32
6 7 32
6 8 32
7 1 112
7 2 112
7 3 112
7 4 112
7 5 112
7 6 112
7 7 112
7 8 112
8 1 114
8 2 110
8 3 98
8 4 113
8 5 107
8 6 98
8 7 110
8 8 114

When the curve fits perfectly to the points of the input data, with a zero error, it means that the final formula has been found!