import graph3;
import math;  // for the leastsquares routine

Billboard.targetsize = true;  // Perspective should not affect the labels.
currentprojection = perspective(60 * (5, 2, 3));

file duncan = input("linearregression.dat");

string headers = duncan;

real[][] independentvars;
real[] dependentvars;

while (!eof(duncan)) {
 string line = duncan;
 string[] entries = split(line);
 if (entries.length < 5) continue;
 string type = entries[1];
 real income = (real)(entries[2]);
 real education = (real)(entries[3]);
 real prestige = (real)(entries[4]);

 // include 1.0 for the residue
 independentvars.push(new real[] {income, education, 1.0});
 dependentvars.push(prestige);
}

real[] coeffs = leastsquares(independentvars, dependentvars, warn=false);
if (coeffs.length == 0) {
 abort("Unable to find regression: independent variables are "
       + "linearly dependent.");
}

real f(pair xy) {
 return coeffs[0] * xy.x  // income
   + coeffs[1] * xy.y  // education
   + coeffs[2];        // residue
}

real xmin = infinity, xmax = -infinity, ymin = infinity, ymax = -infinity;
for (real[] row : independentvars) {
 if (row[0] < xmin) xmin = row[0];
 if (row[0] > xmax) xmax = row[0];
 if (row[1] < ymin) ymin = row[1];
 if (row[1] > ymax) ymax = row[1];
}

// Draw the plane
draw(surface(f, (xmin, ymin), (xmax, ymax)),
    surfacepen=emissive(blue + opacity(0.6)),
    meshpen = blue);

for (int ii = 0; ii < independentvars.length; ++ii) {
 triple pt = (independentvars[ii][0], independentvars[ii][1],
              dependentvars[ii]);
 draw(shift(pt) * unitsphere, material(yellow, emissivepen=0.2*yellow));
 real z = f((pt.x, pt.y));
 if (pt.z > z) draw (pt -- (pt.x, pt.y, z), green);
 else draw(pt -- (pt.x, pt.y, z), red);
}

xaxis3("income", Bounds(Min, Min), InTicks);
yaxis3("education", Bounds(Min, Min), InTicks);
zaxis3("prestige", Bounds(Min, Min), InTicks);