2019-01-08 16:09:25 +01:00
|
|
|
// Copyright 2004, Ondra Kamenik
|
|
|
|
|
|
|
|
// Integer sequence.
|
|
|
|
|
|
|
|
/* Here we define an auxiliary abstraction for a sequence of integers. The
|
|
|
|
basic functionality is to hold an ordered sequence of integers with
|
|
|
|
constant length. We prefer using this simple class before STL
|
|
|
|
|vector<int>| since it is more efficient for our purposes.
|
|
|
|
|
|
|
|
The class is used in index of a tensor, in symmetry definition, in
|
|
|
|
Kronecker product dimensions, or as a class of an equivalence. The
|
|
|
|
latter case is not ordered, but we always order equivalence classes in
|
|
|
|
order to ensure unique representativeness. For almost all cases we
|
|
|
|
need the integer sequence to be ordered (sort), or monotonize (indices
|
|
|
|
of folded tensors), or partially monotonize (indices of folded tensors
|
|
|
|
not fully symmetric), or calculate a product of all members or only of
|
|
|
|
a part (used in Kronecker product dimensions). When we calculate
|
|
|
|
offsets in folded tensors, we need to obtain a number of the same
|
|
|
|
items in the front (|getPrefixLength|), and also to add some integer
|
|
|
|
number to all items.
|
|
|
|
|
2019-02-06 18:39:46 +01:00
|
|
|
Also, we need to construct a subsequence of a sequence. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
#ifndef INT_SEQUENCE_H
|
|
|
|
#define INT_SEQUENCE_H
|
|
|
|
|
|
|
|
#include <vector>
|
2019-02-06 18:39:46 +01:00
|
|
|
#include <algorithm>
|
2019-02-08 18:38:05 +01:00
|
|
|
#include <initializer_list>
|
2019-01-08 16:09:25 +01:00
|
|
|
|
2019-02-06 18:39:46 +01:00
|
|
|
/* The implementation of |IntSequence| is straightforward. It has a pointer
|
|
|
|
|data|, an |offset| integer indicating the beginning of the data relatively
|
2019-02-08 18:38:05 +01:00
|
|
|
to the pointer and a |length| of the sequence.
|
|
|
|
|
|
|
|
WARNING: IntSequence(n) and IntSequence{n} are not the same. The former
|
|
|
|
initializes a sequence of length n, while the latter constructs a sequence
|
|
|
|
of a single element equal to n. This is similar to the behaviour of
|
|
|
|
std::vector. */
|
2019-01-08 16:09:25 +01:00
|
|
|
|
|
|
|
class Symmetry;
|
|
|
|
class IntSequence
|
|
|
|
{
|
2019-02-14 11:05:19 +01:00
|
|
|
int *data;
|
2019-01-08 16:09:25 +01:00
|
|
|
int length;
|
2019-02-14 11:05:19 +01:00
|
|
|
bool destroy{true};
|
2019-01-08 16:09:25 +01:00
|
|
|
public:
|
2019-02-08 18:38:05 +01:00
|
|
|
// Constructor allocating a given length of (uninitialized) data
|
2019-02-06 18:39:46 +01:00
|
|
|
explicit IntSequence(int l)
|
2019-02-14 11:05:19 +01:00
|
|
|
: data{new int[l]}, length{l}
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
|
|
|
}
|
2019-02-08 18:38:05 +01:00
|
|
|
// Constructor allocating and then initializing all members to a given number
|
2019-01-08 16:09:25 +01:00
|
|
|
IntSequence(int l, int n)
|
2019-02-14 11:05:19 +01:00
|
|
|
: data{new int[l]}, length{l}
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
2019-02-14 11:05:19 +01:00
|
|
|
std::fill_n(data, length, n);
|
2019-01-08 16:09:25 +01:00
|
|
|
}
|
2019-02-08 18:38:05 +01:00
|
|
|
/* Constructor using an initializer list (gives the contents of the
|
|
|
|
IntSequence, similarly to std::vector) */
|
|
|
|
IntSequence(std::initializer_list<int> init)
|
2019-02-14 11:05:19 +01:00
|
|
|
: data{new int[init.size()]},
|
2019-02-08 18:38:05 +01:00
|
|
|
length{static_cast<int>(init.size())}
|
|
|
|
{
|
2019-02-14 11:05:19 +01:00
|
|
|
std::copy(init.begin(), init.end(), data);
|
2019-02-08 18:38:05 +01:00
|
|
|
}
|
|
|
|
// Copy constructor
|
2019-01-08 16:09:25 +01:00
|
|
|
IntSequence(const IntSequence &s)
|
2019-02-14 11:05:19 +01:00
|
|
|
: data{new int[s.length]}, length{s.length}
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
2019-02-14 11:05:19 +01:00
|
|
|
std::copy_n(s.data, length, data);
|
2019-01-08 16:09:25 +01:00
|
|
|
}
|
2019-02-08 18:38:05 +01:00
|
|
|
// Move constructor
|
2019-02-14 11:05:19 +01:00
|
|
|
IntSequence(IntSequence &&s)
|
|
|
|
: data{s.data}, length{s.length}, destroy{s.destroy}
|
|
|
|
{
|
|
|
|
s.data = nullptr;
|
|
|
|
s.length = 0;
|
|
|
|
s.destroy = false;
|
|
|
|
}
|
2019-02-08 18:38:05 +01:00
|
|
|
// Subsequence constructor (which shares the data pointer)
|
2019-01-08 16:09:25 +01:00
|
|
|
IntSequence(IntSequence &s, int i1, int i2)
|
2019-02-14 11:05:19 +01:00
|
|
|
: data{s.data+i1}, length{i2-i1}, destroy{false}
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
|
|
|
}
|
2019-02-08 18:38:05 +01:00
|
|
|
// Subsequence constructor (without pointer sharing)
|
2019-01-08 16:09:25 +01:00
|
|
|
IntSequence(const IntSequence &s, int i1, int i2)
|
2019-02-14 11:05:19 +01:00
|
|
|
: data{new int[i2-i1]}, length{i2-i1}
|
2019-01-08 16:09:25 +01:00
|
|
|
{
|
2019-02-14 11:05:19 +01:00
|
|
|
std::copy_n(s.data+i1, length, data);
|
2019-01-08 16:09:25 +01:00
|
|
|
}
|
2019-02-08 18:38:05 +01:00
|
|
|
/* Constructor used for calculating implied symmetry from a more general
|
|
|
|
symmetry and one equivalence class */
|
2019-02-06 15:50:01 +01:00
|
|
|
IntSequence(const Symmetry &sy, const std::vector<int> &se);
|
2019-02-08 18:38:05 +01:00
|
|
|
// Unfolds a given integer sequence with respect to a given symmetry
|
2019-01-08 16:09:25 +01:00
|
|
|
IntSequence(const Symmetry &sy, const IntSequence &se);
|
|
|
|
|
2019-02-22 16:54:00 +01:00
|
|
|
IntSequence &operator=(const IntSequence &s);
|
|
|
|
IntSequence &operator=(IntSequence &&s);
|
2019-02-14 11:05:19 +01:00
|
|
|
virtual ~IntSequence()
|
|
|
|
{
|
|
|
|
if (destroy)
|
|
|
|
delete[] data;
|
|
|
|
}
|
2019-01-08 16:09:25 +01:00
|
|
|
bool operator==(const IntSequence &s) const;
|
|
|
|
bool
|
|
|
|
operator!=(const IntSequence &s) const
|
|
|
|
{
|
|
|
|
return !operator==(s);
|
|
|
|
}
|
|
|
|
int &
|
|
|
|
operator[](int i)
|
|
|
|
{
|
2019-02-14 11:05:19 +01:00
|
|
|
return data[i];
|
2019-01-08 16:09:25 +01:00
|
|
|
}
|
|
|
|
int
|
|
|
|
operator[](int i) const
|
|
|
|
{
|
2019-02-14 11:05:19 +01:00
|
|
|
return data[i];
|
2019-01-08 16:09:25 +01:00
|
|
|
}
|
|
|
|
int
|
|
|
|
size() const
|
|
|
|
{
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We provide two orderings. The first |operator<| is the linear
|
|
|
|
lexicographic ordering, the second |less| is the non-linear Cartesian
|
|
|
|
ordering. */
|
|
|
|
bool operator<(const IntSequence &s) const;
|
|
|
|
bool
|
|
|
|
operator<=(const IntSequence &s) const
|
|
|
|
{
|
|
|
|
return (operator==(s) || operator<(s));
|
|
|
|
}
|
|
|
|
bool lessEq(const IntSequence &s) const;
|
|
|
|
bool less(const IntSequence &s) const;
|
|
|
|
|
2019-02-27 14:34:28 +01:00
|
|
|
// Inserts an element into an ordered sequence
|
|
|
|
IntSequence insert(int i) const;
|
|
|
|
// Inserts an element at a given position
|
|
|
|
/* For appending at the end, use pos = size() */
|
|
|
|
IntSequence insert(int i, int pos) const;
|
|
|
|
|
2019-01-08 16:09:25 +01:00
|
|
|
void sort();
|
|
|
|
void monotone();
|
|
|
|
void pmonotone(const Symmetry &s);
|
|
|
|
int sum() const;
|
|
|
|
int mult(int i1, int i2) const;
|
|
|
|
int
|
|
|
|
mult() const
|
|
|
|
{
|
|
|
|
return mult(0, length);
|
|
|
|
}
|
|
|
|
void add(int i);
|
|
|
|
void add(int f, const IntSequence &s);
|
|
|
|
int getPrefixLength() const;
|
|
|
|
int getNumDistinct() const;
|
|
|
|
int getMax() const;
|
|
|
|
bool isPositive() const;
|
|
|
|
bool isConstant() const;
|
|
|
|
bool isSorted() const;
|
|
|
|
void print() const;
|
2019-02-20 11:56:56 +01:00
|
|
|
// Compute multinomial coefficient (sum(this); this)
|
|
|
|
/* Warning: this operation is destructive; make a copy if you want to keep
|
|
|
|
the original sequence */
|
|
|
|
int noverseq();
|
2019-01-08 16:09:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|