You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

656 lines
24 KiB

/***************************************************************************
mpsymbols.cpp
-------------------
begin : Sun Nov 25 2001
copyright : (C) 2001 by Kamil
email : kamil@localhost.localdomain
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include"mpsymbols.h"
#include"mpdelunay.h"
#include<qobject.h>
#include<math.h>
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//bool MPCommonSymFactory::m_initialized = false;
//QAsciiDict<MPCommonSymFactory::item> MPCommonSymFactory::m_list;
//-------------------------------------------------------------------------//
MPCommonSymFactory::MPCommonSymFactory()
: MPSymbolFactory()
{
m_initialized = false;
if ( !m_initialized ) {
m_list.setAutoDelete( TRUE );
m_list.insert( "e", new item(CONST, MPSymConstant::E, QT_TR_NOOP(" e - base of the natural logarithm.") ) );
m_list.insert( "pi", new item(CONST, MPSymConstant::PI, QT_TR_NOOP(" pi - 3.141592..." ) ) );
m_list.insert( "floor", new item(FUNC1, MPSymFunction1::FLOOR, QT_TR_NOOP("floor(x) - rounds x downwards to the nearest integer.") ) );
m_list.insert( "ceil", new item(FUNC1, MPSymFunction1::CEIL, QT_TR_NOOP("ceil(x) - rounds x upwards to the nearest integer.") ) );
m_list.insert( "sign", new item(FUNC1, MPSymFunction1::SIGN, QT_TR_NOOP("sign(x) - returns -1 for x<0 and 1 for x>= 0.") ) );
m_list.insert( "abs", new item(FUNC1, MPSymFunction1::ABS, QT_TR_NOOP("abs(x) - returns the absolute value of x") ) );
m_list.insert( "sin", new item(FUNC1, MPSymFunction1::SIN, QT_TR_NOOP("sin(x) - returns the sine of x ( radians )") ) );
m_list.insert( "sinh", new item(FUNC1, MPSymFunction1::SINH, QT_TR_NOOP("sinh(x) - returns the hyperblic sine of x ( radians )") ) );
m_list.insert( "cos", new item(FUNC1, MPSymFunction1::COS, QT_TR_NOOP("cos(x) - returns the cosine of x ( radians )") ) );
m_list.insert( "cosh", new item(FUNC1, MPSymFunction1::COSH, QT_TR_NOOP("cosh(x) - returns the hyperbolic cosine of x ( radians )") ) );
m_list.insert( "tan", new item(FUNC1, MPSymFunction1::TAN, QT_TR_NOOP("tan(x) - returns the tangent of x ( radians ).") ) );
m_list.insert( "tanh", new item(FUNC1, MPSymFunction1::TANH, QT_TR_NOOP("tanh(x) - returns the hyperbolic tangent of x ( radians )") ) );
m_list.insert( "acos", new item(FUNC1, MPSymFunction1::ACOS, QT_TR_NOOP("acos(x) - returns the arc cosine of x for x=<-1,1>") ) );
m_list.insert( "acosh", new item(FUNC1, MPSymFunction1::ACOSH, QT_TR_NOOP("acosh(x) - returns the inverse hyperbolic cosine of x for x>=1") ) );
m_list.insert( "asin", new item(FUNC1, MPSymFunction1::ASIN, QT_TR_NOOP("asin(x) - returns the arc sine of x, x=<-1,1>") ) );
m_list.insert( "asinh", new item(FUNC1, MPSymFunction1::ASINH, QT_TR_NOOP("asinh(x) - returns the inverse hyperbolic sine of x") ) );
m_list.insert( "atan", new item(FUNC1, MPSymFunction1::ATAN, QT_TR_NOOP("atan(x) - returns the arc tangent of x. Result belongs to (-pi/2,pi/2>.") ) );
m_list.insert( "atanh", new item(FUNC1, MPSymFunction1::ATANH, QT_TR_NOOP("atanh(x) - returns the inverse hyperbolic tangent of x.") ) );
m_list.insert( "ln", new item(FUNC1, MPSymFunction1::LN, QT_TR_NOOP("ln(x) - returns the natural logarithm of x.") ) );
m_list.insert( "log10", new item(FUNC1, MPSymFunction1::LOG10, QT_TR_NOOP("log10(x) - returns the base-10 logarithm of x. ") ) );
m_list.insert( "log2", new item(FUNC1, MPSymFunction1::LOG2, QT_TR_NOOP("log2(x) - returns the base-2 logarithm of x.") ) );
m_list.insert( "sqrt", new item(FUNC1, MPSymFunction1::SQRT, QT_TR_NOOP("sqrt(x) - returns the square root of x for x >= 0..") ) );
m_list.insert( "mod", new item(FUNC2, MPSymFunction2::MOD, QT_TR_NOOP("mod(x,y) - returns remainder of dividing x by y.") ) );
m_list.insert( "min", new item(FUNC2, MPSymFunction2::MIN, QT_TR_NOOP("min(x,y) - returns the lower value of pair (x,y). ") ) );
m_list.insert( "max", new item(FUNC2, MPSymFunction2::MAX, QT_TR_NOOP("min(x,y) - returns the greater value of pair (x,y). ") ) );
m_list.insert( "log", new item(FUNC2, MPSymFunction2::LOG, QT_TR_NOOP("log(x,y) - returns the y-base logarithm of x. ") ) );
m_list.insert( "pow", new item(FUNC2, MPSymFunction2::POW, QT_TR_NOOP("pow(x,y) - raises x to the power y. ") ) );
m_list.insert( "atan2", new item(FUNC2, MPSymFunction2::ATAN2, QT_TR_NOOP("atan2(x,y) - returns the arc tangent of y/x. Result belongs to (-PI,PI>.") ) );
m_list.insert( "delunay", new item(DELUNAY, 0, QT_TR_NOOP("delunay(x,y) - performs a delunay triangulation of points in x, y column vectors.") ) );
m_initialized = true;
}
}
//-------------------------------------------------------------------------//
MPCommonSymFactory::~MPCommonSymFactory()
{
}
//-------------------------------------------------------------------------//
const char *MPCommonSymFactory::name() const
{
return QT_TR_NOOP("Built-in");
}
//-------------------------------------------------------------------------//
MPSymbol *MPCommonSymFactory::create( const char *identifier, MPSymbolList *args, int colFrom, int colTo )
{
item *new_item = m_list[identifier];
if ( new_item )
switch( new_item->m_type ) {
case CONST: return new MPSymConstant( (MPSymConstant::Constant )new_item->m_function, args, colFrom, colTo, identifier );
case FUNC1: return new MPSymFunction1( (MPSymFunction1::Function )new_item->m_function, args, colFrom, colTo, identifier );
case FUNC2: return new MPSymFunction2( (MPSymFunction2::Function )new_item->m_function, args, colFrom, colTo, identifier );
case DELUNAY: return new MPDelunay( args, colFrom, colTo, identifier );
}
return NULL;
}
//-------------------------------------------------------------------------//
int MPCommonSymFactory::symbolCount() const
{
return m_list.count();
}
//-------------------------------------------------------------------------//
const char *MPCommonSymFactory::symbolIdentifier( int symbolNumber )
{
QAsciiDictIterator<item> it(m_list);
it += symbolNumber;
return it.currentKey();
}
//-------------------------------------------------------------------------//
const char *MPCommonSymFactory::symbolDescription( int symbolNumber )
{
QAsciiDictIterator<item> it(m_list);
it += symbolNumber;
return it.current()->m_description;
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
MPSymValue::MPSymValue( double value, int columnFrom, int columnTo, const char *id )
: MPSymbol( NULL, columnFrom, columnTo, id )
{
m_value = value;
}
//-------------------------------------------------------------------------//
MPSymValue::~MPSymValue()
{
}
//-------------------------------------------------------------------------//
void MPSymValue::checkArgs( MPError& )
{
m_rows = 1;
m_cols = 1;
}
//-------------------------------------------------------------------------//
double MPSymValue::value( int, int )
{
return m_value;
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
MPSymColon::MPSymColon( int columnFrom, int columnTo, const char *id )
: MPSymbol( NULL, columnFrom, columnTo, id )
{
m_rows = 0;
m_cols = 0;
}
//-------------------------------------------------------------------------//
double MPSymColon::value( int, int )
{
return sqrt(-1);
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
MPSymColonExpr::MPSymColonExpr( MPSymbolList *args, int columnFrom, int columnTo, const char *id )
: MPSymbol( args, columnFrom, columnTo, id )
{
}
//-------------------------------------------------------------------------//
MPSymColonExpr::~MPSymColonExpr()
{
}
//-------------------------------------------------------------------------//
void MPSymColonExpr::checkArgs( MPError& error )
{
for ( int i=0; i<m_args->count(); i++ ) m_args->at(i)->checkArgs(error);
MPSymbol::checkArgs( error );
if ( m_args->count() != 2 &&
m_args->count() != 3 ) {
error.setWrongNumberOfArguments( m_args->count(), 3, this );
return;
}
for ( int i=0; i<m_args->count(); i++ )
if ( !m_args->at(i)->isScalar() ) {
error.setNonconformantArgument( i, m_args->at(i), this );
return;
}
if ( m_args->count() == 3 ) {
m_start = m_args->at(0)->value( 0, 0 );
m_step = m_args->at(1)->value( 0, 0 );
m_stop = m_args->at(2)->value( 0, 0 );
}
else
if ( m_args->count() == 2 ) {
m_start = m_args->at(0)->value( 0, 0 );
m_stop = m_args->at(1)->value( 0, 0 );
m_step = 1.0;
}
if ( m_step == 0.0 ) {
error.setNonconformantArgument( 1, m_args->at(1), this );
return;
}
m_rows = 1;
m_cols = QMAX( (int )floor( (m_stop-m_start)/m_step )+1, 0 );
}
//-------------------------------------------------------------------------//
double MPSymColonExpr::value( int, int col )
{
return m_start + col * m_step;
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
const double MPSymConstant::pi = 3.1415926535897932385;
const double MPSymConstant::e = 2.7182818284590452354;
//-------------------------------------------------------------------------//
MPSymConstant::MPSymConstant( Constant c, int columnFrom, int columnTo, const char *id )
: MPSymbol( NULL, columnFrom, columnTo, id )
{
m_c = c;
}
//-------------------------------------------------------------------------//
MPSymConstant::MPSymConstant( Constant c, MPSymbolList *args, int columnFrom, int columnTo, const char *id )
: MPSymbol( args, columnFrom, columnTo, id )
{
m_c = c;
}
//-------------------------------------------------------------------------//
MPSymConstant::~MPSymConstant()
{
}
//-------------------------------------------------------------------------//
void MPSymConstant::checkArgs( MPError& )
{
m_rows = 1;
m_cols = 1;
}
//-------------------------------------------------------------------------//
double MPSymConstant::value( int, int )
{
switch( m_c ) {
case E: return e;
case PI: return pi;
default: return sqrt(-1);
}
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
MPSymFunction1::MPSymFunction1( Function f, MPSymbolList *args, int columnFrom, int columnTo, const char *id )
: MPSymbol( args, columnFrom, columnTo, id )
{
m_f = f;
}
//-------------------------------------------------------------------------//
MPSymFunction1::~MPSymFunction1()
{
}
//-------------------------------------------------------------------------//
void MPSymFunction1::checkArgs( MPError& error )
{
if ( m_args->count() != 1 ) error.setWrongNumberOfArguments( m_args->count(), 1, this );
MPSymbol::checkArgs( error );
}
//-------------------------------------------------------------------------//
double MPSymFunction1::value( int row, int col )
{
double value = m_args->at(0)->value( row, col );
switch( m_f ) {
case FLOOR: return floor( value );
case CEIL: return ceil( value );
case SIGN: return value >= 0 ? 1.0 : -1.0; // should return 0 for value == 0 ???
case ABS: return fabs(value);
case COS: return cos(value);
case COSH: return cosh(value);
case SIN: return sin(value);
case SINH: return sinh(value);
case TAN: return tan(value);
case TANH: return tanh(value);
case ACOS: return acos(value);
case ACOSH: return acosh(value);
case ASIN: return asin(value);
case ASINH: return asinh(value);
case ATAN: return atan(value);
case ATANH: return atanh(value);
case LN: return log(value);
case LOG2: return log10(value)/log10(2.0);
case LOG10: return log10(value);
case SQRT: return sqrt(value);
case NEG: return -value;
default: return sqrt(-1);
};
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
MPSymFunction2::MPSymFunction2( Function f, MPSymbolList *args, int columnFrom, int columnTo, const char *id )
: MPSymbol( args, columnFrom, columnTo, id )
{
m_f = f;
}
//-------------------------------------------------------------------------//
MPSymFunction2::~MPSymFunction2()
{
}
//-------------------------------------------------------------------------//
void MPSymFunction2::checkArgs( MPError& error )
{
if ( m_args->count() != 2 ) error.setWrongNumberOfArguments( m_args->count(), 2, this );
MPSymbol::checkArgs( error );
}
//-------------------------------------------------------------------------//
double MPSymFunction2::value( int row, int col )
{
double val1 = m_args->at(0)->value(row,col);
double val2 = m_args->at(1)->value(row,col);
switch( m_f ) {
case ADD: return val1+val2;
case SUB: return val1-val2;
case MUL: return val1*val2;
case DIV: return val2 ? val1/val2 : sqrt(-1);
case MOD: return fmod( val1, val2 );
case MIN: return min( val1, val2 );
case MAX: return max( val1, val2 );
case LOG: return log10(val1)/log10(val2);
case POW: return pow( val1, val2 );
case ATAN2: return atan2( val1, val2 );
default: return sqrt(-1);
}
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
MPSymMatrixIndexer::MPSymMatrixIndexer( MPSymbol *sym, MPSymbolList *args, int columnFrom, int columnTo, const char *id )
: MPSymbol( args, columnFrom, columnTo, id )
{
m_symbol = sym;
}
//-------------------------------------------------------------------------//
MPSymMatrixIndexer::~MPSymMatrixIndexer()
{
delete m_symbol;
}
//-------------------------------------------------------------------------//
void MPSymMatrixIndexer::checkArgs( MPError& error )
// a bit complicated
{
if ( m_args->count() != 2 ) {
error.setWrongNumberOfArguments( m_args->count(), 2, this );
return;
}
m_symbol->checkArgs( error );
for( int i=0; i<m_args->count(); i++ ) m_args->at(i)->checkArgs(error);
if ( error.hasError() ) return;
m_rows = index_size(m_args->at(0)) == 0 ? m_symbol->rows() : index_size(m_args->at(0));
m_cols = index_size(m_args->at(1)) == 0 ? m_symbol->cols() : index_size(m_args->at(1));
for ( int row=0; row<m_rows; row++ )
if ( index_value(m_args->at(0),row) < 0 ||
index_value(m_args->at(0),row) >= m_symbol->rows() )
error.setError( QString(QT_TR_NOOP("Invalid row index value %1")).arg(index_value(m_args->at(0),row)), this );
for ( int col=0; col<m_cols; col++ )
if ( index_value(m_args->at(1),col) < 0 ||
index_value(m_args->at(1),col) >= m_symbol->cols() )
error.setError( QString(QT_TR_NOOP("Invalid column index value %1")).arg(index_value(m_args->at(1),col)), this );
}
//-------------------------------------------------------------------------//
double MPSymMatrixIndexer::value( int row, int col )
{
return m_symbol->value( index_value(m_args->at(0),row), index_value(m_args->at(1),col) );
}
//-------------------------------------------------------------------------//
int MPSymMatrixIndexer::index_size( MPSymbol *index )
{
return index->rows() * index->cols();
}
//-------------------------------------------------------------------------//
int MPSymMatrixIndexer::index_value( MPSymbol *index, int pos )
{
return index->rows() == 0 ? pos : (int )floor( index->value(pos/index->cols(),pos%index->cols()) );
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
MPSymVectorIndexer::MPSymVectorIndexer( MPSymbol *sym, MPSymbolList *args, int columnFrom, int columnTo, const char *id )
: MPSymbol( args, columnFrom, columnTo, id )
{
m_symbol = sym;
}
//-------------------------------------------------------------------------//
MPSymVectorIndexer::~MPSymVectorIndexer()
{
delete m_symbol;
}
//-------------------------------------------------------------------------//
void MPSymVectorIndexer::checkArgs( MPError& error )
// a bit complicated
{
if ( m_args->count() != 1 ) error.setWrongNumberOfArguments( m_args->count(), 1, this );
m_symbol->checkArgs( error );
m_args->at(0)->checkArgs(error);
if ( m_symbol->rows() != 1 && m_symbol->cols() != 1 ) error.setError( QT_TR_NOOP("Single index only valid for vectors;"), this );
if ( error.hasError() ) return;
// result will be a row vector
if ( m_symbol->rows() == 1 ) {
m_cols = index_size() == 0 ? m_symbol->cols() : index_size();
m_rows = 1;
} else {
// result will be a column vector
m_rows = index_size() == 0 ? m_symbol->rows() : index_size();
m_cols = 1;
}
for( int index=0;index<m_rows*m_cols; index++ )
if ( index_value(index) < 0 || index_value(index) >= m_symbol->rows()*m_symbol->cols() )
error.setError( QString(QT_TR_NOOP("Invalid index value %1")).arg(index_value(index)), this );
}
//-------------------------------------------------------------------------//
double MPSymVectorIndexer::value( int row, int col )
{
int index = index_value(row*m_cols+col);
return m_symbol->value( index/m_symbol->cols(), index%m_symbol->cols() );
}
//-------------------------------------------------------------------------//
int MPSymVectorIndexer::index_size()
{
return m_args->at(0)->rows() * m_args->at(0)->cols();
}
//-------------------------------------------------------------------------//
int MPSymVectorIndexer::index_value( int pos )
{
MPSymbol *index = m_args->at(0);
return index->rows() == 0 ? pos : (int )floor( index->value(pos/index->cols(),pos%index->cols()) );
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
MPSymTranspose::MPSymTranspose( MPSymbolList *args, int columnFrom, int columnTo, const char *id )
: MPSymbol( args, columnFrom, columnTo, id )
{
}
//-------------------------------------------------------------------------//
MPSymTranspose::~MPSymTranspose()
{
}
//-------------------------------------------------------------------------//
void MPSymTranspose::checkArgs( MPError& error )
{
if ( m_args->count() != 1 ) error.setWrongNumberOfArguments( m_args->count(), 1, this );
m_args->at(0)->checkArgs( error );
m_rows = m_args->at(0)->cols();
m_cols = m_args->at(0)->rows();
}
//-------------------------------------------------------------------------//
double MPSymTranspose::value( int row, int col )
{
return m_args->at(0)->value( col, row );
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
MPSymVector::MPSymVector( MPSymbolList *args, int columnFrom, int columnTo, const char *id )
: MPSymbol( args, columnFrom, columnTo, id )
{
m_vector = NULL;
}
//-------------------------------------------------------------------------//
MPSymVector::~MPSymVector()
{
delete m_vector;
}
//-------------------------------------------------------------------------//
void MPSymVector::checkArgs( MPError& error )
{
delete m_vector; m_vector = NULL;
MPSymbol::checkArgs( error );
m_rows = 1;
m_cols = 0;
if ( !error.hasError() )
for( int i=0; i<m_args->count(); i++ ) {
if ( m_args->at(i)->rows() != 1 ) { error.setNonconformantArgument( i, m_args->at(i), this ); break; }
m_cols += m_args->at(i)->cols();
}
int curr_col = 0;
m_vector = new double[m_cols];
for( int i=0; i<m_args->count(); i++ )
for( int col=0; col<m_args->at(i)->cols(); col++ )
m_vector[curr_col++] = m_args->at(i)->value(0,col);
}
//-------------------------------------------------------------------------//
double MPSymVector::value( int, int col )
{
return m_vector[col];
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
MPSymMatrix::MPSymMatrix( MPSymbolList *args, int columnFrom, int columnTo, const char *id )
: MPSymbol( args, columnFrom, columnTo, id )
{
}
//-------------------------------------------------------------------------//
MPSymMatrix::~MPSymMatrix()
{
}
//-------------------------------------------------------------------------//
void MPSymMatrix::checkArgs( MPError& error )
{
MPSymbol::checkArgs( error );
if ( !error.hasError() ) {
m_cols = m_args->at(0)->cols();
m_rows = m_args->count();
for( int i=0; i<m_args->count(); i++ ) {
if ( m_args->at(i)->rows() != 1 ||
m_args->at(i)->cols() != m_cols ) { error.setNonconformantArgument( i, m_args->at(i), this ); break; }
}
}
}
//-------------------------------------------------------------------------//
double MPSymMatrix::value( int row, int col )
{
return m_args->at(row)->value(0,col);
}
//-------------------------------------------------------------------------//