PolynomialFit3<Real>::PolynomialFit3 (int numXSamples, int numYSamples,
    const Real* xSamples, const Real* ySamples, const Real* wSamples,
    int numPowers, const Tuple<2,int>* powers)
{
    InitializePowers(numPowers, powers);

    // Repackage the input into samples of the form (x[i],y[i],w[i]).
    int numSamples = numXSamples*numYSamples;
    Real* xRepackage = new1<Real>(numSamples);
    Real* yRepackage = new1<Real>(numSamples);
    for (int y = 0, i = 0; y < numYSamples; ++y)
    {
        Real yInput = ySamples[y];
        for (int x = 0; x < numXSamples; ++x, ++i)
        {
            xRepackage[i] = xSamples[x];
            yRepackage[i] = yInput;
        }
    }

    const Real* srcSamples[3] = { xRepackage, yRepackage, wSamples };
    Real* trgSamples[3] = { 0, 0, 0 };
    TransformToUnit(numSamples, srcSamples, trgSamples);

    DoLeastSquaresFit(numSamples, trgSamples);

    delete1(trgSamples[0]);
    delete1(trgSamples[1]);
    delete1(trgSamples[2]);
    delete1(xRepackage);
    delete1(yRepackage);
}
PolynomialFit3<Real>::PolynomialFit3 (int numSamples, const Real* xSamples,
    const Real* ySamples, const Real* wSamples, int numPowers,
    const Tuple<2,int>* powers)
{
    InitializePowers(numPowers, powers);

    const Real* srcSamples[3] = { xSamples, ySamples, wSamples };
    Real* trgSamples[3] = { 0, 0, 0 };
    TransformToUnit(numSamples, srcSamples, trgSamples);

    DoLeastSquaresFit(numSamples, trgSamples);

    delete1(trgSamples[0]);
    delete1(trgSamples[1]);
    delete1(trgSamples[2]);
}
    PolynomialFit2<Real>::PolynomialFit2 ( int numSamples, const Real* xSamples,
                                           const Real* wSamples, int numPowers, const int* powers )
        :
        mNumPowers( numPowers )
    {
        InitializePowers( numPowers, powers );

        mPowers = new1<int>( mNumPowers );
        memcpy( mPowers, powers, mNumPowers * sizeof( int ) );
        mCoefficients = new1<Real>( mNumPowers );
        GMatrix<Real> mat( mNumPowers, mNumPowers ); // initially zero
        GVector<Real> rhs( mNumPowers ); // initially zero
        GVector<Real> xPower( mNumPowers );

        int i, row, col;
        for ( i = 0; i < numSamples; ++i )
        {
            // Compute relevant powers of x.  TODO: Build minimum tree for
            // powers of x?
            Real x = xSamples[i];
            Real w = wSamples[i];
            for ( int j = 0; j < mNumPowers; ++j )
            {
                xPower[j] = Math<Real>::Pow( x, ( Real )mPowers[j] );
            }

            for ( row = 0; row < mNumPowers; ++row )
            {
                // Update the upper-triangular portion of the symmetric matrix.
                for ( col = row; col < mNumPowers; ++col )
                {
                    mat[row][col] += xPower[mPowers[row] + mPowers[col]];
                }

                // Update the right-hand side of the system.
                rhs[row] += w * xPower[mPowers[row]];
            }
        }

        // Copy the upper-triangular portion of the symmetric matrix to the
        // lower-triangular portion.
        for ( row = 0; row < mNumPowers; ++row )
        {
            for ( col = 0; col < row; ++col )
            {
                mat[row][col] = mat[col][row];
            }
        }

        // Precondition by normalizing the sums.
        Real invNumSamples = ( ( Real )1 ) / ( Real )numSamples;
        for ( row = 0; row < mNumPowers; ++row )
        {
            for ( col = 0; col < mNumPowers; ++col )
            {
                mat[row][col] *= invNumSamples;
            }
            rhs[row] *= invNumSamples;
        }

        if ( LinearSystem<Real>().Solve( mat, rhs, mCoefficients ) )
        {
            mSolved = true;
        }
        else
        {
            memset( mCoefficients, 0, mNumPowers * sizeof( Real ) );
            mSolved = false;
        }
    }