////////////////////////////////////////////////////////////////////////////////
// 
// Vector.cc
//
//    produced: 13/03/98 jr
// 
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <ctype.h>
#include <string.h>

#include "Vector.hh"
#include "Permutation.hh"
#include "Symmetry.hh"

namespace topcom {


  const parameter_type Vector::capacity = 0;

  bool Vector::is_zero() const {
    for (parameter_type index = 0; index < size(); ++index) {
      if ((*this)(index) != FieldConstants::ZERO) {
	return false;
      }
    }
    return true;
  }
  Vector& Vector::canonicalize() {
    for (parameter_type index = 0; index < size(); ++index) {
      (*this)(index).canonicalize();
    }
    return *this;
  }

  Vector& Vector::add(const Vector& vector) {
#ifdef INDEX_CHECK
    assert(size() == vector.size());
#endif
    for (parameter_type index = 0; index < size(); ++index) {
      (*this)(index) += vector(index);
    }
    return *this;
  }
  Vector& Vector::scale(const Field& factor) {
    for (parameter_type index = 0; index < size(); ++index) {
      (*this)(index) *= factor;
    }
    return *this;  
  }
  Vector& Vector::stack(const Vector& vector) {
    const parameter_type current_maxindex(size());
    resize(size() + vector.size());
    for (parameter_type i = 0; i < vector.size(); ++i) {
      (*this)(i + current_maxindex) = vector(i);
    }
    return *this;
  }

  const Vector unit_vector(const parameter_type dim, const parameter_type pos) {
    Vector result(dim, FieldConstants::ZERO);
    result(pos) = FieldConstants::ONE;
    return result;
  }

  Field inner_product(const Vector& vector1, const Vector& vector2) {
#ifdef INDEX_CHECK
    assert(vector2.size() == vector1.size());
#endif
    Field result(FieldConstants::ZERO);
    for (parameter_type i = 0; i < vector1.size(); ++i) {
      result += (vector1(i) * vector2(i));
    }
    return result;
  }

  bool lex_compare(const Vector& vector1, 
		   const Vector& vector2, 
		   const parameter_type start) {

    // returns true if and only if vector1
    // is lex-smaller than vector2:
    if (start >= vector2.size()) {

      // vector2 has no elements with index start or larger,
      // while vector1 has elements (vector1 > vector2 for indices starting at start)
      // or has no elements either (vector1 == vector2 for indices starting at start):
      return false;
    }
    else if (start >= vector1.size()) {

      // vector1 has no elements with index start or larger,
      // while vector2 has further elements:
      return true;
    }

    // from now on, vector1 and vector2 both have elements at index start:
    if (vector1(start) > vector2(start)) {

      // the first element is strictly larger in vector1:
      return false;
    }
    else if (vector1(start) < vector2(start)) {

      // the first element is strictly larger in vector2:
      return true;
    }
    else {
      
      // the first elements coincide so that the remaing elements decide:
      return lex_compare(vector1, vector2, start + 1);
    }
  }
  
  bool lex_abs_compare(const Vector& vector1, 
		       const Vector& vector2, 
		       const parameter_type start) {

    // returns true if and only if abs(vector1)
    // is lex-smaller than abs(vector2)
    // with algorithm analogous to above:
    if (start >= vector2.size()) {
      return false;
    }
    else if (start >= vector1.size()) {
      return true;
    }
    if (abs(vector1(start)) > abs(vector2(start))) {
      return false;
    }
    else if (abs(vector1(start)) < abs(vector2(start))) {
      return true;
    }
    else {
      return lex_abs_compare(vector1, vector2, start + 1);
    }
  }

  bool lex_compare(const Vector& vector1, 
		   const Vector& vector2,
		   const Permutation& order,
		   const parameter_type start) {

    if (start >= vector2.size()) {
      return false;
    }
    else if (start >= vector1.size()) {
      return true;
    }
    if (vector1(order(start)) > vector2(order(start))) {
      return false;
    }
    else if (vector1(order(start)) < vector2(order(start))) {
      return true;
    }
    else {
      return lex_compare(vector1, vector2, order, start + 1);
    }
  }
  
  // stream input/output:
  std::istream& Vector::read(std::istream& ist) {
    char c;
    Field elem;

    vector_data::clear();
    ist >> std::ws >> c;
    if (c == ContainerChars::list_start_char) {
      while (ist >> std::ws >> c) {
	if (c == ContainerChars::list_end_char) {
	  break;
	}
	if (c == ContainerChars::delim_char) {
	  continue;
	}
	ist.putback(c);
	if (ist >> elem) {
	  vector_data::push_back(elem);
	}
	else {
#ifdef READ_DEBUG
	  MessageStreams::forced() << message::lock
				   << "Vector::read(std::istream& ist):"
				   << c << " not of appropriate type." << std::endl
				   << message::unlock;
#endif
	  ist.clear(std::ios::failbit);
	  return ist;
	}
      }
    }
    else {
#ifdef READ_DEBUG
      MessageStreams::forced() << message::lock
			       << "Vector::read(std::istream& ist):"
			       << "missing `" << ContainerChars::list_start_char << "'." << std::endl
			       << message::unlock;
#endif
      ist.clear(std::ios::failbit);
      return ist;
    }
    ist.clear(std::ios::goodbit);
    this->canonicalize();
    return ist;
  }

  std::ostream& Vector::write(std::ostream& ost) const {
    ost << ContainerChars::list_start_char;
    if (dim() > 0) {
      for (parameter_type i = 0; i < dim() - 1; ++i) {
	ost << (*this)[i] << ContainerChars::delim_char;
      }
      if (dim() > 0) {
	ost << (*this)[dim() - 1];
      }
    }
    ost << ContainerChars::list_end_char;
    return ost;
  }

}; // namespace topcom

// eof Vector.cc
