@q $Id: int_sequence.cweb 148 2005-04-19 15:12:26Z kamenik $ @>
@q Copyright 2004, Ondra Kamenik @>

@ Start of {\tt int\_sequence.cpp} file.

@c
#include "int_sequence.h"
#include "symmetry.h"
#include "tl_exception.h"

#include <cstdio>
#include <climits>

@<|IntSequence| constructor code 1@>;
@<|IntSequence| constructor code 2@>;
@<|IntSequence| constructor code 3@>;
@<|IntSequence| constructor code 4@>;
@<|IntSequence::operator=| code@>;
@<|IntSequence::operator==| code@>;
@<|IntSequence::operator<| code@>;
@<|IntSequence::lessEq| code@>;
@<|IntSequence::less| code@>;
@<|IntSequence::sort| code@>;
@<|IntSequence::monotone| code@>;
@<|IntSequence::pmonotone| code@>;
@<|IntSequence::sum| code@>;
@<|IntSequence::mult| code@>;
@<|IntSequence::getPrefixLength| code@>;
@<|IntSequence::getNumDistinct| code@>;
@<|IntSequence::getMax| code@>;
@<|IntSequence::add| code 1@>;
@<|IntSequence::add| code 2@>;
@<|IntSequence::isPositive| code@>;
@<|IntSequence::isConstant| code@>;
@<|IntSequence::isSorted| code@>;
@<|IntSequence::print| code@>;

@ This unfolds a given integer sequence with respect to the given
symmetry. If for example the symmetry is $(2,3)$, and the sequence is
$(a,b)$, then the result is $(a,a,b,b,b)$.

@<|IntSequence| constructor code 1@>=
IntSequence::IntSequence(const Symmetry& sy, const IntSequence& se)
	: data(new int[sy.dimen()]), length(sy.dimen()), destroy(true)
{
	int k = 0;
	for (int i = 0; i < sy.num(); i++)
		for (int j = 0;	 j < sy[i]; j++, k++)
			operator[](k) = se[i];
}


@ This constructs an implied symmetry (implemented as |IntSequence|
from a more general symmetry and equivalence class (implemented as
|vector<int>|). For example, let the general symmetry be $y^3u^2$ and
the equivalence class is $\{0,4\}$ picking up first and fifth
variable, we calculate symmetry (at this point only |IntSequence|)
corresponding to the picked variables. These are $yu$. Thus the
constructed sequence must be $(1,1)$, meaning that we picked one $y$
and one $u$.


@<|IntSequence| constructor code 2@>=
IntSequence::IntSequence(const Symmetry& sy, const vector<int>& se)
	: data(new int[sy.num()]), length(sy.num()), destroy(true)
{
	TL_RAISE_IF(sy.dimen() <= se[se.size()-1],
				"Sequence is not reachable by symmetry in IntSequence()");
	for (int i = 0; i < length; i++) @/
		operator[](i) = 0;

    for (unsigned int i = 0; i < se.size(); i++) @/
		operator[](sy.findClass(se[i]))++;
}

@ This constructs an ordered integer sequence from the given ordered
sequence inserting the given number to the sequence.

@<|IntSequence| constructor code 3@>=
IntSequence::IntSequence(int i, const IntSequence& s)
	: data(new int[s.size()+1]), length(s.size()+1), destroy(true)
{
	int j = 0;
	while (j < s.size() && s[j] < i)
		j++;
	for (int jj = 0; jj < j; jj++)
		operator[](jj) = s[jj];
	operator[](j) = i;
	for (int jj = j; jj < s.size(); jj++)
		operator[](jj+1) = s[jj];
}

@ 
@<|IntSequence| constructor code 4@>=
IntSequence::IntSequence(int i, const IntSequence& s, int pos)
	: data(new int[s.size()+1]), length(s.size()+1), destroy(true)
{
	TL_RAISE_IF(pos < 0 || pos > s.size(),
				"Wrong position for insertion IntSequence constructor");
	for (int jj = 0; jj < pos; jj++)
		operator[](jj) = s[jj];
	operator[](pos) = i;
	for (int jj = pos; jj < s.size(); jj++)
		operator[](jj+1) = s[jj];
}

@ 
@<|IntSequence::operator=| code@>=
const IntSequence& IntSequence::operator=(const IntSequence& s)
 {
	 TL_RAISE_IF(!destroy && length != s.length,
				 "Wrong length for in-place IntSequence::operator=");
	 if (destroy && length != s.length) {
		 delete [] data;
		 data = new int[s.length];
		 destroy = true;
		 length = s.length;
	 }
	 memcpy(data, s.data, sizeof(int)*length);
	 return *this;
 }


@ 
@<|IntSequence::operator==| code@>=
bool IntSequence::operator==(const IntSequence& s) const
{
	if (size() != s.size())
		return false;

	int i = 0;
	while (i < size() && operator[](i) == s[i])
		i++;
	return i == size();
}

@ We need some linear irreflexive ordering, we implement it as
lexicographic ordering without identity.
@<|IntSequence::operator<| code@>=
bool IntSequence::operator<(const IntSequence& s) const
{
	int len = min(size(), s.size());

	int i = 0;
	while (i < len && operator[](i) == s[i])
		i++;
	return (i < s.size() && (i == size() || operator[](i) < s[i]));
}

@ 
@<|IntSequence::lessEq| code@>=
bool IntSequence::lessEq(const IntSequence& s) const
{
	TL_RAISE_IF(size() != s.size(),
				"Sequence with different lengths in IntSequence::lessEq");

	int i = 0;
	while (i < size() && operator[](i) <= s[i])
		i++;
	return (i == size());
}

@ 
@<|IntSequence::less| code@>=
bool IntSequence::less(const IntSequence& s) const
{
	TL_RAISE_IF(size() != s.size(),
				"Sequence with different lengths in IntSequence::less");

	int i = 0;
	while (i < size() && operator[](i) < s[i])
		i++;
	return (i == size());
}

@ This is a bubble sort, all sequences are usually very short, so this
sin might be forgiven.

@<|IntSequence::sort| code@>=
void IntSequence::sort()
{
	for (int i = 0; i < length; i++) {
		int swaps = 0;
		for (int j = 0; j < length-1; j++) {
			if (data[j] > data[j+1]) {
				int s = data[j+1];
				data[j+1] = data[j];
				data[j] = s;
				swaps++;
			}
		}
		if (swaps == 0)
			return;
	}
}

@ Here we monotonize the sequence. If an item is less then its
predecessor, it is equalized.

@<|IntSequence::monotone| code@>=
void IntSequence::monotone()
{
	for (int i = 1; i < length; i++)
		if (data[i-1] > data[i])@/
			data[i] = data[i-1];
}

@ This partially monotones the sequence. The partitioning is done by a
symmetry. So the subsequence given by the symmetry classes are
monotonized. For example, if the symmetry is $y^2u^3$, and the
|IntSequence| is $(5,3,1,6,4)$, the result is $(5,5,1,6,6)$.

@<|IntSequence::pmonotone| code@>=
void IntSequence::pmonotone(const Symmetry& s)
{
	int cum = 0;
	for (int i = 0; i < s.num(); i++) {
		for (int j = cum + 1; j < cum + s[i]; j++)
			if (data[j-1] > data[j])@/
				data[j] = data[j-1];
		cum += s[i];
	}
}

@ This returns sum of all elements. Useful for symmetries.
@<|IntSequence::sum| code@>=
int IntSequence::sum() const
{
	int res = 0;
	for (int i = 0; i < length; i++) @/
		res += operator[](i);
	return res;
}

@ This returns product of subsequent items. Useful for Kronecker product
dimensions.

@<|IntSequence::mult| code@>=
int IntSequence::mult(int i1, int i2) const
{
	int res = 1;
	for (int i = i1; i < i2; i++)@/
		res *= operator[](i);
	return res;
}

@ Return a number of the same items in the beginning of the sequence.
@<|IntSequence::getPrefixLength| code@>=
int IntSequence::getPrefixLength() const
{
	int i = 0;
	while (i+1 < size() && operator[](i+1) == operator[](0))
		i++;
	return i+1;
}

@ This returns a number of distinct items in the sequence. It supposes
that the sequence is ordered. For the empty sequence it returns zero.

@<|IntSequence::getNumDistinct| code@>=
int IntSequence::getNumDistinct() const
{
	int res = 0;
	if (size() > 0)
		res++;
	for (int i = 1; i < size(); i++)
		if (operator[](i) != operator[](i-1))
			res++;
	return res;
}

@ This returns a maximum of the sequence. If the sequence is empty, it
returns the least possible |int| value.

@<|IntSequence::getMax| code@>=
int IntSequence::getMax() const
{
	int res = INT_MIN;
	for (int i = 0; i < size(); i++)
		if (operator[](i) > res)
			res = operator[](i);
	return res;
}

@ 
@<|IntSequence::add| code 1@>=
void IntSequence::add(int i)
{
	for (int j = 0; j < size(); j++)
		operator[](j) += i;
}

@ 
@<|IntSequence::add| code 2@>=
void IntSequence::add(int f, const IntSequence& s)
{
	TL_RAISE_IF(size() != s.size(),
				"Wrong sequence length in IntSequence::add");
	for (int j = 0; j < size(); j++)
		operator[](j) += f*s[j];
}

@ 
@<|IntSequence::isPositive| code@>=
bool IntSequence::isPositive() const
{
	int i = 0;
	while (i < size() && operator[](i) >= 0)
		i++;
	return (i == size());
}

@ 
@<|IntSequence::isConstant| code@>=
bool IntSequence::isConstant() const
{
	bool res = true;
	int i = 1;
	while (res && i < size()) {
		res = res && operator[](0) == operator[](i);
		i++;
	}
	return res;
}

@ 
@<|IntSequence::isSorted| code@>=
bool IntSequence::isSorted() const
{
	bool res = true;
	int i = 1;
	while (res && i < size()) {
		res = res && operator[](i-1) <= operator[](i);
		i++;
	}
	return res;
}



@ Debug print.
@<|IntSequence::print| code@>=
void IntSequence::print() const
{
	printf("[");
	for (int i = 0; i < size(); i++)@/
		printf("%2d ",operator[](i));
	printf("]\n");
}

@ End of {\tt int\_sequence.cpp} file.