// space.cc: Test of subspace package
//////////////////////////////////////////////////////////////////////////
//
// Copyright 1990-2026 John Cremona
// 
// This file is part of the eclib package.
// 
// eclib is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
// 
// eclib 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 General Public License
// for more details.
// 
// You should have received a copy of the GNU General Public License
// along with eclib; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
// 
//////////////////////////////////////////////////////////////////////////
 
#include <eclib/linalg.h>

const scalar modulus(default_modulus<scalar>());

int main()
{
cout << "Subspace test program with scalar type " << scalar_type << "\n\n";

int times,ntimes,r=0;

while (cout << "Enter size of square matrix M: ", cin >> r, r>0 )
{
  mat m(r,r);
  cout << "Enter entries of M: ";
  cin >> m;
  cout << " M = \n" << m << endl;
  cout << "Trace(M) = " << m.trace() << endl;
/*
  int i;
  mat mpower=m;
  for (i=2; i<=r; i++)
    {mpower=mpower*m;
     cout << "m^" << i << " = \n" << mpower << endl;
     cout << "Trace(m^" << i << ") = " << mpower.trace() << endl;
   }
  {
    vector<long> cp = m.charpoly();
    cout << "char. poly. of m has coefficients " << cp << endl;
  }
  cout << "det(M) = " << m.determinant() << endl;
  cout << "rank(M) = " << m.rank() << endl;
  cout << "nullity(M) = " << m.nullity() << endl;
*/
  cout << endl << "Enter number of times to repeat kernel tests: ";
  cin >> ntimes;
  {
    subspace ker;
    times=ntimes;
    while(times--) ker = kernel(m);
    mat kerbasis = ker.bas();
    cout << "kernel(m) has basis\n" << kerbasis << endl;
    vec_i kerpivs = ker.pivs();
    cout << "pivots: " << kerpivs << "\n";
    scalar kerdenom = ker.den();
    cout << "denom:  " << kerdenom  << "\n";
    // test of inclusion of vectors in subspace:
    for (int i=1; i<=r; i++)
      {
        vec v = vec::unit_vector(r,i);
        int isin = ker.contains(v);
        cout << "v = " << v << (isin?" IS ":" is NOT ")<<"in the kernel";
        if (trivial(m*v)==isin)
          cout <<" and m*v = "<<m*v<<" --OK"<<endl;
        else
          cout <<" but m*v = "<<m*v<<" --WRONG"<<endl;
      }
  }
  scalar p = modulus;
  cout << "Now compute kernel mod p, p = " << p << endl;
  {
    times=ntimes; subspace ker;
    while(times--) ker = pkernel(m, p);
    mat kerbasis = ker.bas();
    cout << "kernel(m) has basis\n" << kerbasis << endl;
    vec_i kerpivs = ker.pivs();
    cout << "pivots: " << kerpivs << "\n";
    subspace oldker;
    times=ntimes;
    while(times--) oldker = oldpkernel(m, p);
    if((kerbasis != oldker.bas()) || (kerpivs != oldker.pivs()))
      {
	cout << "!!! Differs from old version !!!" << endl;
	cout << "Old basis = \n" << oldker.bas()<<endl;
      }
    else
      cout << "!!! Agrees  with old version !!!" << endl;
  }
/*
  {
    subspace im = image(m);
    cout << "image(m) has basis\n" << im.bas();
    cout << "pivots: " << im.pivs() << "\n";
    cout << "denom:  " << im.den()  << "\n";
  }
  {
    scalar lambda;
    cout << "Enter lambda: "; cin >> lambda;
    subspace elambda = eigenspace(m,lambda);
    cout << "eigenspace for lambda has basis\n" << elambda.bas();
    cout << "with dimension " << elambda.dim() << endl;
  }
*/
}
 cout<<endl;
}
