08-02-19.mw

> data:=[[1,2], [2,2], [5,6], [7,9], [8,10]];
 

[[1, 2], [2, 2], [5, 6], [7, 9], [8, 10]] (1)
 

> err := (f, p) -> abs( f(p[1]) - p[2]);
 

proc (f, p) options operator, arrow; abs(`+`(f(p[1]), `-`(p[2]))) end proc (2)
 

> dist:= h-> sum( err(h,data[i]), i=1..nops(data));
 

proc (h) options operator, arrow; sum(err(h, data[i]), i = 1 .. nops(data)) end proc (3)
 

>
 

> dist(x->x+1);
 

3 (4)
 

> dist(x->2*x+1);
 

22 (5)
 

> seq(dist(x->x+j),j=-2..8);
 

16, 11, 6, 3, 4, 9, 14, 19, 24, 29, 34 (6)
 

> seq([j,dist(x->x+j)],j=-2..8);
 

[-2, 16], [-1, 11], [0, 6], [1, 3], [2, 4], [3, 9], [4, 14], [5, 19], [6, 24], [7, 29], [8, 34] (7)
 

> plot( [seq([j,dist(x->x+j)],j=-2..8)] );
 

Plot_2d
 

> mbToDist := (m,b) -> dist(x->m*x+b);
 

proc (m, b) options operator, arrow; dist(proc (x) options operator, arrow; `+`(`*`(m, `*`(x)), b) end proc) end proc (8)
 

> mbToDist(1,1);
 

3 (9)
 

> mbToDist(1.01,1);
 

2.930000000 (10)
 

> mbToDist(1,1.02);
 

3.020000000 (11)
 

> plot3d(mbToDist(m,b),m=0..2,b=0..2,axes=boxed,style=patchcontour);
 

Plot
 

> diff(mbToDist(m,b),m);
 

`+`(abs(1, `+`(m, b, `-`(2))), `*`(2, `*`(abs(1, `+`(`*`(2, `*`(m)), b, `-`(2))))), `*`(5, `*`(abs(1, `+`(`*`(5, `*`(m)), b, `-`(6))))), `*`(7, `*`(abs(1, `+`(`*`(7, `*`(m)), b, `-`(9))))), `*`(8, `*`...
`+`(abs(1, `+`(m, b, `-`(2))), `*`(2, `*`(abs(1, `+`(`*`(2, `*`(m)), b, `-`(2))))), `*`(5, `*`(abs(1, `+`(`*`(5, `*`(m)), b, `-`(6))))), `*`(7, `*`(abs(1, `+`(`*`(7, `*`(m)), b, `-`(9))))), `*`(8, `*`...
(12)
 

> diff(mbToDist(m,b),b);
 

`+`(abs(1, `+`(m, b, `-`(2))), abs(1, `+`(`*`(2, `*`(m)), b, `-`(2))), abs(1, `+`(`*`(5, `*`(m)), b, `-`(6))), abs(1, `+`(`*`(7, `*`(m)), b, `-`(9))), abs(1, `+`(`*`(8, `*`(m)), b, `-`(10)))) (13)
 

>
 

Oh, ick! abs value isn't differentiable.   

Try something else. 

> err2 := (f, p) -> ( f(p[1]) - p[2])^2;
 

proc (f, p) options operator, arrow; `*`(`^`(`+`(f(p[1]), `-`(p[2])), 2)) end proc (14)
 

> dist2:= h-> sum( err2(h,data[i]), i=1..nops(data));
 

proc (h) options operator, arrow; sum(err2(h, data[i]), i = 1 .. nops(data)) end proc (15)
 

> mbToDist2 := (m,b) -> dist2(x->m*x+b);
 

proc (m, b) options operator, arrow; dist2(proc (x) options operator, arrow; `+`(`*`(m, `*`(x)), b) end proc) end proc (16)
 

> plot3d(mbToDist2(m,b),m=0..2,b=0..2,axes=boxed,style=patchcontour);
 

Plot
 

> diff(mbToDist2(m,b),m);
 

`+`(`*`(286, `*`(m)), `*`(46, `*`(b)), `-`(358)) (17)
 

> diff(mbToDist2(m,b),b);
 

`+`(`*`(46, `*`(m)), `*`(10, `*`(b)), `-`(58)) (18)
 

> solve({diff(mbToDist2(m,b),m)=0,diff(mbToDist2(m,b),b)=0}, {m,b});
 

{m = `/`(38, 31), b = `/`(5, 31)} (19)
 

> with(plots):
 

> display( [ plot(data,style=point, color=red),
          plot(38*x/31 + 5/31,x=0..10,color=blue)]);
 

Plot_2d
 

> CurveFitting[LeastSquares](data,x);
 

`+`(`*`(`/`(38, 31), `*`(x)), `/`(5, 31)) (20)
 

>
 

Let's try to find a close cubic instead. 

 

> cubdis:=(a,b,c,d) -> dist2(x->a*x^3+b*x^2+c*x+d);
 

proc (a, b, c, d) options operator, arrow; dist2(proc (x) options operator, arrow; `+`(`*`(a, `*`(`^`(x, 3))), `*`(b, `*`(`^`(x, 2))), `*`(c, `*`(x)), d) end proc) end proc (21)
 

> cubdis(1,2,3,4);
 

677797 (22)
 

> cubdis(0,0,38/31,5/31);
 

`/`(28, 31) (23)
 

>
 

Find the best values for a,b,c,d that fit a cubic. 

 

>
 

> diff(cubdis(a,b,c,d),a);
 

`+`(`-`(17950), `*`(790966, `*`(a)), `*`(1978, `*`(d)), `*`(105466, `*`(b)), `*`(14278, `*`(c))) (24)
 

>
 

Just to make it more explicit what we are doing (this isn't necessary), we're going to write out EXACTLY what the function we are minimizing is, so that you can see it is quadratic and so has a unique minimum. 

First, dist2data is the distance from the function h to our 5 points (ie, the sum of the squares of the vertical distance h(x)-y at these 5 points). 

> dist2data:= unapply(sum( (h(data[i][1])-data[i][2])^2, i=1..nops(data)),h);
 

proc (h) options operator, arrow; `+`(`*`(`^`(`+`(h(1), `-`(2)), 2)), `*`(`^`(`+`(h(2), `-`(2)), 2)), `*`(`^`(`+`(h(5), `-`(6)), 2)), `*`(`^`(`+`(h(7), `-`(9)), 2)), `*`(`^`(`+`(h(8), `-`(10)), 2))) e... (25)
 

We want to find a good cubic, so let's give the generic cubic a name 

> mycubic:=x->a*x^3+b*x^2+c*x+d;
 

proc (x) options operator, arrow; `+`(`*`(a, `*`(`^`(x, 3))), `*`(b, `*`(`^`(x, 2))), `*`(c, `*`(x)), d) end proc (26)
 

Here is the "distance" between the generic cubic and our 5 points.  Note that it depends on a,b,c, and d. 

> thedist:=dist2data(mycubic);
 

`+`(`*`(`^`(`+`(a, b, c, d, `-`(2)), 2)), `*`(`^`(`+`(`*`(8, `*`(a)), `*`(4, `*`(b)), `*`(2, `*`(c)), d, `-`(2)), 2)), `*`(`^`(`+`(`*`(125, `*`(a)), `*`(25, `*`(b)), `*`(5, `*`(c)), d, `-`(6)), 2)), `...
`+`(`*`(`^`(`+`(a, b, c, d, `-`(2)), 2)), `*`(`^`(`+`(`*`(8, `*`(a)), `*`(4, `*`(b)), `*`(2, `*`(c)), d, `-`(2)), 2)), `*`(`^`(`+`(`*`(125, `*`(a)), `*`(25, `*`(b)), `*`(5, `*`(c)), d, `-`(6)), 2)), `...
(27)
 

Each of the 4 partials is linear in the 4 variables. 

> diff(thedist,a);
 

`+`(`-`(17950), `*`(790966, `*`(a)), `*`(1978, `*`(d)), `*`(105466, `*`(b)), `*`(14278, `*`(c))) (28)
 

> ans:=solve( {diff(thedist,a)=0, diff(thedist,b)=0, diff(thedist,c)=0, diff(thedist,d)=0}, {a,b,c,d});
 

{a = -`/`(32, 733), b = `/`(1453, 2199), c = -`/`(1186, 733), d = `/`(6554, 2199)} (29)
 

So that I don't have to retype, I'm going to use assign. 

> assign(ans);
 

now a, b, c, and d refer to those specific values. 

> mycubic(x);
 

`+`(`-`(`*`(`/`(32, 733), `*`(`^`(x, 3)))), `*`(`/`(1453, 2199), `*`(`^`(x, 2))), `-`(`*`(`/`(1186, 733), `*`(x))), `/`(6554, 2199)) (30)
 

> thedist(mycubic);
 

`/`(6, 733) (31)
 

> display([plot(mycubic(x),x=0..10),plot(data,style=point,color=blue)]);
 

Plot_2d
 

If I want to use a as a variable again, I need to unassign it: 

> a,b,c,d;
 

-`/`(32, 733), `/`(1453, 2199), -`/`(1186, 733), `/`(6554, 2199) (32)
 

> unassign('a','b','c','d');
 

> a,b,c,d;
 

a, b, c, d (33)
 

>