/* -*- mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
// vim:sts=4:sw=4:ts=4:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/*
 * Copyright (C) the FFLAS-FFPACK group
 * Written by Clément Pernet
 * This file is Free Software and part of FFLAS-FFPACK.
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *.
 */


#include "fflas-ffpack/fflas-ffpack-config.h"
#include <iostream>
#include <givaro/modular.h>

Givaro::Timer tperm, tgemm, tBC, ttrsm,trest,timtot;

#include "fflas-ffpack/ffpack/ffpack.h"

#include "fflas-ffpack/utils/Matio.h"



using namespace std;
using namespace FFLAS;
using namespace FFPACK;
using Givaro::Modular;

bool checkMonotonicApplyP(FFLAS_SIDE Side, FFLAS_TRANSPOSE trans, size_t * P, size_t N, size_t R){
	bool ok = true;
	
	typedef Modular<double> Field;
    Field F(101);
	size_t M = 2;
	size_t lda = (Side == FflasLeft)? M : N;
	size_t ldb = lda;
	Field::Element_ptr A = fflas_new(F, M, N);
	Field::Element_ptr B = fflas_new(F, M, N);
	if (Side == FflasLeft)
		for (size_t i = 0; i<N; ++i)
			for (size_t j = 0; j<M; ++j)
				F.init(A[i*lda+j],i*10+j);
	else
		for (size_t i = 0; i<N; ++i)
			for (size_t j = 0; j<M; ++j)
				F.init(A[i+j*lda],i*10+j);

	fassign(F, N,M, A, lda, B, ldb);

    write_field(F, std::cerr<<"Before MonotonicApplyP, A = "<<std::endl, A, N,M, lda);

	MonotonicApplyP (F, FflasLeft, FflasNoTrans, M, 0, N, A, lda, P, R);

    write_field(F, std::cerr<<"After MonotonicApplyP, A = "<<std::endl, A, N,M, lda);

		// checking that cols have not been permuted
	typename Field::Element x;
	F.init(x);
	for (size_t i=0; i<N; i++){
		F.sub(x,A[lda*i+1],A[lda*i]);
		if (!F.isOne(x)){
			std::cerr<<"ERROR: A["<<i<<", 1] = "<<A[i*lda+1]<<" != "<<A[i*lda]+1<<" = A["<<i<<", 0]+1"<<std::endl;
			ok = false;
		}
	}
	
		// Checking that the non pivot rows are monotonically increasing
	for (size_t i=R; i<N-1; i++){
		if (A[i*lda] >= A[(i+1)*lda]){
			std::cerr<<"ERROR: A["<<i<<", 0] = "<<A[i*lda]<<" >= "<<A[(i+1)*lda]<<" = A["<<i+1<<", 0]"<<std::endl;
			ok = false;
		}
	}

		// Checking that the first R rows have been permuted correctly
	applyP(F, Side, trans, M, 0, R, B, ldb, P);
	if (!fequal(F, R, M,A, lda, B, ldb)){
		std::cerr<<"ERROR: first R rows are not permuted correctly"<<std::endl;
		ok =false;
	}
	fflas_delete(A);
	fflas_delete(B);
	
	return ok;
}

int main(){
    
    
	bool ok = true;
    
    size_t  P1[10] = {0,5,6,6,7,9,6,7,8,9};
	ok &= checkMonotonicApplyP(FflasLeft, FflasNoTrans, P1, 10, 6);
    size_t  P2[10] = {0,3,3,6,6,5,6,7,8,9};
	ok &= checkMonotonicApplyP(FflasLeft, FflasNoTrans, P2, 10, 5);
    size_t  P3[10] = {0,4,2,4,5,5,6,7,8,9};
	ok &= checkMonotonicApplyP(FflasLeft, FflasNoTrans, P3, 10, 6);
	
	return !ok;
}
