/*
* 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
*
*/
#include "Dimensions.hpp"
#include "Exception.hpp"
#include <stdlib.h>
#include <string>
#include <stdio.h>
#include "Malloc.hpp"
#include "Interpreter.hpp"
#define MSGBUFLEN 2048
//Slimming down Dimensions... In demo(6), the Dimension related
//codes occupy 14+6.5+4+3.5+3+2.65+2.45+2.35 = 37% of the time!
//I want this factor back. One issue that is clear is that the
//Dimension class itself is relatively clean. But because of the
//operator[] call, Dimensions does not know its state (e.g., am I
//a vector?). So what I want to do is move the cache of the dimension
//quantities from Data to Dimensions. And to have Dimensions be
//responsible for cacheing the quantities of interest.
int Dimensions::getMax() {
int maxL;
maxL = 0;
for (int i=0;i<length;i++)
maxL = (maxL > data[i]) ? maxL : data[i];
return maxL;
}
void Dimensions::updateCacheVariables() {
m_cache_getElementCount = 0;
if (length == 0)
m_cache_getElementCount = 0;
else {
m_cache_getElementCount = 1;
for (int i=0;i<length;i++)
m_cache_getElementCount *= data[i];
}
m_cache_isScalar = (m_cache_getElementCount == 1);
if (length == 0)
m_cache_getRows = 0;
else
m_cache_getRows = data[0];
if (length == 0)
m_cache_getColumns = 0;
else if (length == 1)
m_cache_getColumns = 1;
else
m_cache_getColumns = data[1];
m_cache_is2D = (m_cache_getRows*m_cache_getColumns==m_cache_getElementCount);
m_cache_isVector = (m_cache_getRows==m_cache_getElementCount) ||
(m_cache_getColumns == m_cache_getElementCount);
}
void Dimensions::setDimensionLength(int dim, int len) {
if (dim >= maxDims )
throw Exception("Too many dimensions! Current limit is 6.");
if (dim >= length) {
int new_length = dim+1;
for (int j=length;j<new_length;j++)
data[j] = 1;
length = new_length;
}
data[dim] = len;
updateCacheVariables();
}
int Dimensions::mapPoint(const Dimensions& point) const {
int retval;
int nextCoeff;
int testableDims;
retval = 0;
nextCoeff = 1;
testableDims = (point.length < length) ? point.length : length;
for (int i=0;i<testableDims;i++) {
if ((point.data[i] < 0) || (point.data[i] >= data[i]))
throw Exception("Array index out of bounds");
retval += nextCoeff*point.data[i];
nextCoeff *= data[i];
}
for (int j=testableDims;j<point.length;j++) {
if (point.data[j] != 0)
throw Exception("Array index out of bounds");
}
return retval;
}
void Dimensions::expandToCover(const Dimensions& a) {
int sze;
int i;
Dimensions dimensions(*this);
/**
* First, compute the larger of the two: the number of current dimensions
* and the number of requested dimensions.
*/
sze = (a.length > length) ? a.length : dimensions.length;
/**
* Allocate a dimension vector to hold the new dimensions. It should
* be of size sze.
*/
reset();
/**
* Now we loop over the dimensions. For each dimensions, we could have
* three cases to deal with:
* 1. a[i] is undefined but dimensions[i] is -> newsize[i] = dimensions[i];
* 2. a[i] is defined but dimensions[i] is not -> newsize[i] = a[i];
* 3. a[i] and dimensions[i] are both defined ->
* newsize[i] = max(a[i],dimensions[i]);
*/
for (i=0;i<sze;i++) {
/**
* Case 1:
*/
if (i>=a.length)
set(i,dimensions.get(i));
/**
* Case 2:
*/
else if (i>=dimensions.length)
set(i,a.data[i]);
else
set(i,((a.data[i] > dimensions.get(i)) ? a.data[i] : dimensions.get(i)));
}
}
void Dimensions::incrementModulo(const Dimensions& limit, int ordinal) {
int n;
data[ordinal]++;
for (n=ordinal;n<length-1;n++)
if (data[n] >= limit.data[n]) {
data[n] = 0;
data[n+1]++;
}
updateCacheVariables();
}
void Dimensions::simplify() {
if (length <= 2) return;
int trimcount = 0;
int i = length-1;
while (i>1 && data[i] == 1) i--;
length = i+1;
updateCacheVariables();
}
bool Dimensions::equals(const Dimensions &alt) const {
bool retval;
retval = (length == alt.length);
for (int i=0;i<length;i++)
retval = retval && (data[i] == alt.data[i]);
return retval;
}
std::string Dimensions::asString() const {
char msgBuffer[MSGBUFLEN];
std::string output;
output.append("[");
for (int i=0;i<length-1;i++) {
snprintf(msgBuffer,MSGBUFLEN,"%d ",data[i]);
output.append(msgBuffer);;
}
if (length >= 1)
snprintf(msgBuffer,MSGBUFLEN,"%d]",data[length-1]);
else
snprintf(msgBuffer,MSGBUFLEN,"]");
output.append(msgBuffer);
return output;
}
void Dimensions::printMe(Interpreter* eval) const {
char msgBuffer[MSGBUFLEN];
snprintf(msgBuffer,MSGBUFLEN,"[");
eval->outputMessage(msgBuffer);
for (int i=0;i<length-1;i++) {
snprintf(msgBuffer,MSGBUFLEN,"%d ",data[i]);
eval->outputMessage(msgBuffer);
}
if (length >= 1)
snprintf(msgBuffer,MSGBUFLEN,"%d]",data[length-1]);
else
snprintf(msgBuffer,MSGBUFLEN,"]");
eval->outputMessage(msgBuffer);
}
void Dimensions::reset() {
length = 0;
memset(data, 0, sizeof(int)*maxDims);
updateCacheVariables();
}
void Dimensions::zeroOut() {
for (int i=0;i<length;i++)
data[i] = 0;
updateCacheVariables();
}
void Dimensions::makeScalar() {
reset();
length = 2;
data[0] = 1;
data[1] = 1;
updateCacheVariables();
}
Dimensions Dimensions::permute(const int32* permutation) const {
Dimensions out(length);
for (int i=0;i<length;i++)
out.data[i] = data[permutation[i]-1];
return out;
}
syntax highlighted by Code2HTML, v. 0.9.1