/*
* Copyright (c) 2002-2006 Samit Basu
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __Dimensions_hpp__
#define __Dimensions_hpp__
#include <iostream>
#include "Exception.hpp"
#include "Types.hpp"
class Interpreter;
const unsigned int maxDims = 6;
/**
* The Dimensions class is used to keep track of the number of
* dimensions for a given Array. The Dimensions class represents
* an N-tuple of integers (each non-negative). N can be made
* arbitrarily large. The '[]' operator is overloaded to return
* a reference to the dimension of interest. Indexing beyond
* the number of current dimensions automatically increases the
* length of the dimension vector, and pads it with 1's. For example
* if our current contents are $$[3,5,2,1]$$, and we index element
* 5, the dimension vector is automatically padded to $$[3,5,2,1,1,1]$$.
* Calling simplify() removes the trailing '1's.
*/
class Dimensions {
private:
/**
* The data array of dimensions.
*/
int data[maxDims];
/**
* The number of dimensions currently allocated.
*/
int length;
/**
* Cache values for frequently called functions.
*/
int m_cache_getElementCount;
bool m_cache_isScalar;
int m_cache_getRows;
int m_cache_getColumns;
bool m_cache_is2D;
bool m_cache_isVector;
public:
/**
* The default constructor - length is set to zero.
*/
inline Dimensions() {
length = 0;
m_cache_getElementCount = 0;
m_cache_isScalar = false;
m_cache_getRows = 0;
m_cache_getColumns = 0;
m_cache_is2D = true;
m_cache_isVector = true;
}
/**
* Initialize the object with the given number of dimensions
* and all contents set to zero.
* Throws an Exception if the dimension count is negative.
*/
inline Dimensions(int dimCount) {
if (dimCount < 0)
throw Exception("Illegal argument to Dimensions constructor");
memset(data, 0, sizeof(int)*dimCount);
length = dimCount;
updateCacheVariables();
}
/**
* Return a 2-D dimension object with the specified number of
* rows and columns.
*/
inline Dimensions(int rows, int cols) {
data[0] = rows;
data[1] = cols;
length = 2;
m_cache_getElementCount = rows*cols;
m_cache_isScalar = ((rows==1)&&(cols==1));
m_cache_getRows = rows;
m_cache_getColumns = cols;
m_cache_is2D = true;
m_cache_isVector = ((rows==1)||(cols==1));
}
/**
* Return a 3-D dimension object with the specified number of
* rows and columns and slices.
*/
inline Dimensions(int rows, int cols, int slices) {
data[0] = rows;
data[1] = cols;
data[2] = slices;
length = 3;
m_cache_getElementCount = rows*cols*slices;
m_cache_isScalar = ((rows==1)&&(cols==1)&&(slices==1));
m_cache_getRows = rows;
m_cache_getColumns = cols;
m_cache_is2D = (slices == 1);
m_cache_isVector = (((rows==1)||(cols==1))&&(slices==1));
}
/**
* Return a reference to the ith dimension. This member function
* will adjust the number of dimensions present if the argument
* exceeds the current number allocated. The extra dimensions are
* padded with 1's. Thus, if our contents are $$[2,3]$$, then
* a reference to dimension 2 (these are zero-based indexing) converts
* our contents to $$[2,3,1]$$.
* Throws an exception if the argument is negative.
*/
// int& operator[](unsigned i) throw(Exception);
/**
* Get the number of currently allocated dimensions.
*/
inline int getLength() const {
return length;
}
/**
* Update the cache variables. Call this when
* finished mucking with dimension data!
*/
void updateCacheVariables();
/**
* Get the pointer to the dimension data.
*/
// int* getDimensionData() const;
/**
* Return the total number of elements in the associated Array object.
* calculated via $$\Prod_{i=0}^{L-1} a_i$$, where $$L$$ is the value
* of length, and $$a_i$$ is equivalent to data[i].
*/
inline int getElementCount() const {
return m_cache_getElementCount;
}
/**
* Map the given point using the current Dimensions. If the argument
* values are denoted as $$b_i$$, and our dimensions are $$a_i$$, then
* this member function computes $$\Sum_{i=0}^{L-1} b_i \Prod_{j=0}^{j=i} a_j$$.
* Throws an exception if:
* - the argument has more dimensions than the current object
* - any of the arguments are outside the valid range, i.e.,
* $$b_i < 0$$ or $$b_i >= a_i$$.
*/
int mapPoint(const Dimensions& point) const;
/**
* Returns the first dimension value (or zero if no dimensions have
* been defined yet).
*/
inline int getRows() const {
return m_cache_getRows;
}
/**
* Returns the second dimension value (or zero if no dimensions have
* been defined yet).
*/
inline int getColumns() const {
return m_cache_getColumns;
}
/**
* Returns the requested dimension, or a 1 if the requested dimension
* exceeds the currently allocated number of dimensions. Unlike
* the access operator, this call does not modify the contents of
* the class.
*/
inline int getDimensionLength(int arg) const {
if (length <= arg)
return 1;
else
return data[arg];
}
/**
* Less verbose synonym
*/
inline int get(int arg) const {
return getDimensionLength(arg);
}
/**
* A synonym for (*this)[dim] = len.
*/
void setDimensionLength(int dim, int len);
/**
* Less verbose synonym
*/
inline void set(int dim, int len) {
setDimensionLength(dim,len);
}
/**
* Expand our dimensions so as to include the given point. This operation
* involves a sequence of operations. Let $$b$$ denote the argument, and
* $$a$$ denote this object. Then first we update the length of $$a$$
* as $$ |a| \leftarrow \max(|a|,|b|) $$. Next, we loop over each dimension
* and apply the following algorithm:
* - if $$a_i$$ is undefined but $$b_i$$ is defined, $$a_i \leftarrow b_i$$.
* - if $$a_i$$ is defined but $$b_i$$ is undefined, $$a_i \leftarrow a_i$$.
* - if $$a_i$$ and $$b_i$$ are both defined, $$a_i \leftarrow \max(a_i,b_i)$$.
*/
void expandToCover(const Dimensions& resize);
/**
* Increment our current value in the given dimension (ordinal),
* modulo the limit. This is equivalent to first incrementing
* the $$n$$-th dimension (where $$n$$ is the second argument) via
* $$a_n \leftarrow a_n + 1$$. Then, $$a_n$$ is checked against
* the limit $$b_n$$. If $$a_n >= b_n$$, then $$a_n \leftarrow 0$$,
* and the algorithm is repeated with ordinal+1.
*/
void incrementModulo(const Dimensions& limit, int ordinal);
/**
* Returns comparison of $$a_n < b_n$$, where $$n$$ is the maximum defined
* dimension in $$a$$ (this object), and $$b$$ is the given argument.
*/
inline bool inside(const Dimensions& limit) const {
return (data[length-1] < limit.data[length-1]);
}
/**
* Returns true if we match the argument (exactly).
*/
bool equals(const Dimensions& alt) const;
/**
* This member function trims any excess singleton (length 1) dimensions
* from our data array after the second dimension. Thus, the dimension
* vector $$[3,4,5,1,1]$$, will become $$[3,4,5]$$ after simplify() is
* called.
*/
void simplify();
/**
* Print some representation of this object as a row vector, i.e.,
* $$[a_1 a_2 \ldots a_n]$$.
*/
void printMe(Interpreter *io) const;
/**
* Returns a string containing the dimensions as a row vector.
*/
std::string asString() const;
/**
* Reset the number of allocated dimensions to zero, and reset the
* data pointer to NULL.
*/
void reset();
/**
* Set all of the allocated dimensions to zero.
*/
void zeroOut();
/**
* Force the contents to be $$[1,1]$$.
*/
void makeScalar();
/**
* Get the largest dimension value, i.e., $$\max_{i=1,\ldots,n} \{a_i\}$$.
*/
int getMax();
/**
* Returns true if and only if we are equal to $$[1,1]$$.
*/
inline bool isScalar() const {
return m_cache_isScalar;
}
/**
* Returns true if and only if we are equal to $$[1,n]$$ or $$[n,1]$$ for
* some value of $$n$$.
*/
inline bool isVector() const {
return m_cache_isVector;
}
/**
* Returns true if we have exactly 2 dimensions allocated.
*/
inline bool is2D() const {
return m_cache_is2D;
}
/**
* Applies a permutation (assumed legal) to this dimension vector, and returns the permuted vector
*/
Dimensions permute(const int32* permutation) const;
};
#endif
syntax highlighted by Code2HTML, v. 0.9.1