#include "subspace.h"

#include "division.h"
#include "buchberger.h"
#include "field_rationals.h"


static Polynomial vectorToPolynomial(IntegerVector const &v)
{
  static Field* field;

  if(!field)field=Field::find("GmpRationals"); // this is a bit stupid. We should add a field_rationals header file instead
  assert(field);

  Polynomial ret;

  for(int i=0;i<v.size();i++)
    if(v[i])
      {
	ret+=Term(field->zHomomorphism(v[i]),IntegerVector::standardVector(v.size(),i));
      }

  return ret;
}


static IntegerVector polynomialToVector(Polynomial const &f)
{
  static Field* field;

  if(!field)field=Field::find("GmpRationals"); // this is a bit stupid. We should add a field_rationals header file instead
  assert(field);

  int n=f.getNumberOfVariables();

  //  fprintf(Stderr,"%i\n",n);
  
  vector<FieldElement> r(n);

  for(int i=0;i<n;i++)
    r[i]=field->zHomomorphism(0);

  for(TermMap::const_iterator i=f.terms.begin();i!=f.terms.end();i++)
    {
      for(int j=0;j<n;j++)
	if(i->first.exponent==IntegerVector::standardVector(n,j))
	  {
	    r[j]=i->second;
	  }
    }

  return primitiveVector(r);
}

Subspace::Subspace(IntegerVectorList const &generators, int ambientDimension)
{
  n=ambientDimension;
  if(n==-1)
    {
      assert(!generators.empty());
      n=generators.begin()->size();
    }
  for(IntegerVectorList::const_iterator i=generators.begin();i!=generators.end();i++)
    {
      assert(i->size()==n);
      basis.push_back(vectorToPolynomial(*i));
    }
  buchberger(&basis,LexicographicTermOrder());
}

bool Subspace::contains(IntegerVector const &v)const
{
  assert(v.size()==n);

  return division(vectorToPolynomial(v),basis,LexicographicTermOrder()).isZero();
}


int Subspace::dimension()
{
  return basis.size();
}


int Subspace::ambientDimension()
{
  return n;
}


Subspace sum(Subspace const &a, Subspace const &b)
{
  Subspace ret=a;

  ret.basis.insert(ret.basis.end(),b.basis.begin(),b.basis.end());
  buchberger(&ret.basis,LexicographicTermOrder());

  return ret;
}


IntegerVectorList Subspace::getRepresentation()const
{
  IntegerVectorList ret;

  for(PolynomialSet::const_iterator i=basis.begin();i!=basis.end();i++)
    {
      ret.push_back(polynomialToVector(*i));
    }

  return ret;
}

IntegerVector Subspace::canonicalizeVector(IntegerVector const &v)const
{
  Polynomial f=vectorToPolynomial(v);
  f=division(f,basis,LexicographicTermOrder());

  return polynomialToVector(f);
}
