#include <vector>
#include <arithmetic_iterators/arithmetic_iterator.h>
#include <arithmetic_iterators/ai_square.h>
#include <arithmetic_iterators/linalg.h>



namespace traditional {
    template <class P1, class P2, class O1>
    inline void subtract(const P1 &x, const P2 &y, O1 &diff) {
	int l = x.size();
	for(int i=0; i<l; ++i)
	    diff[i] = x[i]-y[i];
    }
    template <class P1, class P2>
    inline vector<typename P1::value_type> subtract(const P1 &x, const P2 &y) {
	vector<typename P1::value_type> diff(x.size());
	subtract(x,y,diff);
	return diff;
    }

    template <class P1, class O1>
    inline void square(const P1 &x, O1 &sq) {
	int l = x.size();
	for(int i=0; i<l; ++i)
	    sq[i] = x[i]*x[i];
    }
    template <class P1>
    inline vector<typename P1::value_type> square(const P1 &x) {
	vector<typename P1::value_type> sq(x.size());
	square(x, sq);
	return sq;
    }
}




template <class P1, class P2>
typename P1::value_type test_lazy(const P1 &x, const P2 &y)
{
    return sum(square(x - y));
}


template <class P1, class P2>
typename P1::value_type test_hand(const P1 &x, const P2 &y)
{
    typename P1::const_iterator xit = x.begin();
    typename P2::const_iterator yit = y.begin();
    typename P1::value_type acc = 0;

    for(; xit != x.end(); ++xit, ++yit)
	acc += (*xit-*yit)*(*xit-*yit);
    return acc;
}


template <class P1, class P2, class VEC1, class VEC2>
typename P1::value_type test_hand2(const P1 &x, const P2 &y, VEC1 &diff, VEC2 &sq)
{
    int l = x.size();
    for(int i=0; i<l; ++i)
	diff[i] = x[i] - y[i];
    for(int i=0; i<l; ++i)
	sq[i] = diff[i]*diff[i];
    typename P1::value_type acc = 0;
    for(int i=0; i<l; ++i)
	acc += sq[i];
    return acc;
}



template <class P1, class P2>
typename P1::value_type test_traditional(const P1 &x, const P2 &y)
{
    return sum(traditional::square(traditional::subtract(x,y)));
}


template <class P1, class P2, class VEC1, class VEC2>
typename P1::value_type test_traditional2(const P1 &x, const P2 &y, VEC1 &diff, VEC2 &sq)
{
    traditional::subtract(x,y, diff);
    traditional::square(diff, sq);
    return sum(sq);
}


using namespace NTPM;


int
main()
{
    const int L = 10000;
    const int ITERS = 1000;
    float x[L];
    float y[L];


    for(int i=0; i<L; ++i)
    {
	x[i] = (float)i*0.3;
	y[i] = (float)i*0.2;
    }

    vector<float> x_v(x,x+L);
    vector<float> y_v(y,y+L);
    vector<float> diff(L);
    vector<float> sq(L);

    /* Build objects that promise the data. */
    NTPMai::Promise<float*> x_l = make_promise(x,x+L);
    NTPMai::Promise<float*> y_l = make_promise(y,y+L);

    cout << "lazy = " << test_lazy(x_l, y_l) << endl;
    cout << "hand = " << test_hand(x_v, y_v) << endl;
    cout << "hand = " << test_hand2(x_v, y_v, diff, sq) << endl;
    cout << "traditional = " << test_traditional(x_v, y_v) << endl;
    cout << "traditional = " << test_traditional2(x_v, y_v, diff, sq) << endl;


    /* Evaluate sum of squared difference of x and y. */

    for(int i=0; i<ITERS; ++i)
	test_hand2(x_v, y_v, diff, sq);

    for(int i=0; i<ITERS; ++i)
	test_lazy(x_l, y_l);

    for(int i=0; i<ITERS; ++i)
	test_hand(x_v, y_v);

    for(int i=0; i<ITERS; ++i)
	test_traditional(x_v, y_v);

    for(int i=0; i<ITERS; ++i)
	test_traditional2(x_v, y_v, diff, sq);
}


syntax highlighted by
Code2HTML, v. 0.8.12