/* * function.cpp - part of abakus * Copyright (C) 2004, 2005 Michael Pyne * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "numerictypes.h" #include #include #include #include #include #include "function.h" #include "node.h" #include "valuemanager.h" #include "hmath.h" // Used to try and avoid recursive function definitions class DupFinder : public NodeFunctor { public: DupFinder(const TQString &nameToFind) : m_name(nameToFind), m_valid(true) { } virtual ~DupFinder() { } bool isValid() const { return m_valid; } virtual void operator()(const Node *node) { if(!m_valid) return; const BaseFunction *fn = dynamic_cast(node); if(fn && fn->name() == m_name) m_valid = false; // Duplicate detected } private: TQString m_name; bool m_valid; }; // Define static member for FunctionManager FunctionManager *FunctionManager::m_manager = 0; FunctionManager *FunctionManager::instance() { if(!m_manager) m_manager = new FunctionManager; return m_manager; } FunctionManager::FunctionManager(TQObject *parent, const char *name) : TQObject(parent, name) { m_dict.setAutoDelete(true); } // Dummy return value to enable static initialization in the DECL_*() // macros. bool FunctionManager::addFunction(const TQString &name, function_t fn, const TQString &desc) { Function *newFn = new Function; TQRegExp returnTrigRE("^a(cos|sin|tan)"); TQRegExp needsTrigRE("^(cos|sin|tan)"); TQString fnName(name); newFn->name = name; newFn->description = desc; newFn->fn = fn; newFn->userDefined = false; newFn->returnsTrig = fnName.contains(returnTrigRE); newFn->needsTrig = fnName.contains(needsTrigRE); m_dict.insert(name, newFn); return false; } #define DECLARE_FUNC(name, fn, desc) bool dummy##name = FunctionManager::instance()->addFunction(#name, fn, desc) // Declares a function name that is implemented by the function of a different // name. e.g. atan -> Abakus::number_t::arctan() #define DECLARE_FUNC2(name, fnName, desc) DECLARE_FUNC(name, &Abakus::number_t::fnName, desc) // Declares a function name that is implemented by the function of the // same base name. #define DECLARE_FUNC1(name, desc) DECLARE_FUNC2(name, name, desc) DECLARE_FUNC1(sin, "Trigonometric sine"); DECLARE_FUNC1(cos, "Trigonometric cosine"); DECLARE_FUNC1(tan, "Trigonometric tangent"); DECLARE_FUNC1(sinh, "Hyperbolic sine"); DECLARE_FUNC1(cosh, "Hyperbolic cosine"); DECLARE_FUNC1(tanh, "Hyperbolic tangent"); DECLARE_FUNC1(atan, "Inverse tangent"); DECLARE_FUNC1(acos, "Inverse cosine"); DECLARE_FUNC1(asin, "Inverse sine"); DECLARE_FUNC1(asinh, "Inverse hyperbolic sine"); DECLARE_FUNC1(acosh, "Inverse hyperbolic cosine"); DECLARE_FUNC1(atanh, "Inverse hyperbolic tangent"); DECLARE_FUNC1(abs, "Absolute value of number"); DECLARE_FUNC1(sqrt, "Square root"); DECLARE_FUNC1(ln, "Natural logarithm (base e)"); DECLARE_FUNC1(log, "Logarithm (base 10)"); DECLARE_FUNC1(exp, "Natural exponential function"); DECLARE_FUNC1(round, "Round to nearest number"); DECLARE_FUNC1(ceil, "Nearest greatest integer"); DECLARE_FUNC1(floor, "Nearest lesser integer"); DECLARE_FUNC2(int, integer, "Integral part of number"); DECLARE_FUNC1(frac, "Fractional part of number"); Function *FunctionManager::function(const TQString &name) { return m_dict[name]; } // Returns true if the named identifier is a function, false otherwise. bool FunctionManager::isFunction(const TQString &name) { return function(name) != 0; } bool FunctionManager::isFunctionUserDefined(const TQString &name) { const Function *fn = function(name); return (fn != 0) && (fn->userDefined); } bool FunctionManager::addFunction(BaseFunction *fn, const TQString &dependantVar) { // First see if this function is recursive DupFinder dupFinder(fn->name()); UnaryFunction *unFunction = dynamic_cast(fn); if(unFunction && unFunction->operand()) { unFunction->operand()->applyMap(dupFinder); if(!dupFinder.isValid()) return false; } // Structure holds extra data needed to call the user defined // function. UserFunction *newFn = new UserFunction; newFn->sequenceNumber = m_dict.count(); newFn->fn = fn; newFn->varName = TQString(dependantVar); // Now setup the Function data structure that holds the information // we need to access and call the function later. Function *fnTabEntry = new Function; fnTabEntry->name = fn->name(); fnTabEntry->userFn = newFn; fnTabEntry->returnsTrig = false; fnTabEntry->needsTrig = false; fnTabEntry->userDefined = true; if(m_dict.find(fn->name())) emit signalFunctionRemoved(fn->name()); m_dict.replace(fn->name(), fnTabEntry); emit signalFunctionAdded(fn->name()); return true; } void FunctionManager::removeFunction(const TQString &name) { Function *fn = function(name); // If we remove a function, we need to decrement the sequenceNumber of // functions after this one. if(fn && fn->userDefined) { int savedSeqNum = fn->userFn->sequenceNumber; // Emit before we actually remove it so that the info on the function // can still be looked up. emit signalFunctionRemoved(name); delete fn->userFn; fn->userFn = 0; m_dict.remove(name); TQDictIterator it(m_dict); for (; it.current(); ++it) { UserFunction *userFn = it.current()->userDefined ? it.current()->userFn : 0; if(userFn && userFn->sequenceNumber > savedSeqNum) --it.current()->userFn->sequenceNumber; } } } TQStringList FunctionManager::functionList(FunctionManager::FunctionType type) { TQDictIterator it(m_dict); TQStringList functions; switch(type) { case Builtin: for(; it.current(); ++it) if(!it.current()->userDefined) functions += it.current()->name; break; case UserDefined: // We want to return the function names in the order they were // added. { TQValueVector fnTable(m_dict.count(), 0); TQValueVector sequenceNumberTable(m_dict.count(), -1); // First find out what sequence numbers we have. for(; it.current(); ++it) if(it.current()->userDefined) { int id = it.current()->userFn->sequenceNumber; fnTable[id] = it.current(); sequenceNumberTable.append(id); } // Now sort the sequence numbers and return the ordered list qHeapSort(sequenceNumberTable.begin(), sequenceNumberTable.end()); for(unsigned i = 0; i < sequenceNumberTable.count(); ++i) if(sequenceNumberTable[i] >= 0) functions += fnTable[sequenceNumberTable[i]]->name; } break; case All: functions += functionList(Builtin); functions += functionList(UserDefined); break; } return functions; } // Applies the function identified by func, using value as a parameter. Abakus::number_t evaluateFunction(const Function *func, const Abakus::number_t value) { if(func->userDefined) { // Pull real entry from userFunctionTable UserFunction *realFunction = func->userFn; bool wasSet = ValueManager::instance()->isValueSet(realFunction->varName); Abakus::number_t oldValue; if(wasSet) oldValue = ValueManager::instance()->value(realFunction->varName); ValueManager::instance()->setValue(realFunction->varName, value); Abakus::number_t result = realFunction->fn->value(); if(wasSet) ValueManager::instance()->setValue(realFunction->varName, oldValue); else ValueManager::instance()->removeValue(realFunction->varName); return result; } return (value.*(func->fn))(); } void setTrigMode(Abakus::TrigMode mode) { Abakus::m_trigMode = mode; } Abakus::TrigMode trigMode() { return Abakus::m_trigMode; } #include "function.moc"