file Backends/mathematica_variable.hpp
[No description available] More…
Namespaces
| Name | 
|---|
| Gambit TODO: see if we can use this one: | 
Classes
| Name | |
|---|---|
| class | Gambit::mathematica_variable | 
Detailed Description
Class mathematica_variable, needed to overload constructor and assignment operators to send messages throught WSTP
Authors
(add name and date if you modify)
Tomas Gonzalo (t.e.gonzalo@fys.uio.no)
2016 Nov
Pat Scott (p.scott@imperial.ac.uk)
2017 Dec
Source code
//   GAMBIT: Global and Modular BSM Inference Tool
//   *********************************************
///  \file
///
///  Class mathematica_variable, needed to overload
///  constructor and assignment operators to send
///  messages throught WSTP
///
///  ***********************************************
///
///  Authors
///  =======
///
///  (add name and date if you modify)
///
///  \author Tomas Gonzalo
///          (t.e.gonzalo@fys.uio.no)
///  \date 2016 Nov
///
///  \author Pat Scott
///          (p.scott@imperial.ac.uk)
///  \date 2017 Dec
///
///  ***********************************************
#ifndef __mathematica_variable_hpp__
#define __mathematica_variable_hpp__
#include "gambit/Elements/ini_catch.hpp"
#include "gambit/Backends/backend_singleton.hpp"
#include "gambit/cmake/cmake_variables.hpp"
#include <boost/algorithm/string/replace.hpp>
#ifdef HAVE_MATHEMATICA
 #include "gambit/Backends/mathematica_helpers.hpp"
 #include MATHEMATICA_WSTP_H
#endif
namespace Gambit
{
  // Class mathematica_variable
  template <typename TYPE>
  class mathematica_variable
  {
    private:
      #ifdef HAVE_MATHEMATICA
        WSLINK _WSlink;
      #endif
      TYPE _var;
      str _symbol;
    public:
      // Constructor
      mathematica_variable(const str& be, const str& ver, const str& symbol) :  _symbol(symbol)
      {
        #ifdef HAVE_MATHEMATICA
          using namespace Backends;
          try
          {
            /* Extract the backend WSLINK pointer from the backendInfo object */
            if (backendInfo().works.at(be+ver))
            {
              _WSlink = backendInfo().loaded_mathematica_backends.at(be+ver);
            }
            else
            {
              _WSlink = (WSLINK)0;
              return;
            }
            /* If TYPE is a numeric type, send N first */
            if(boost::is_same<TYPE, int>::value or
               boost::is_same<TYPE, float>::value or
               boost::is_same<TYPE, double>::value)
              if(!WSPutFunction(_WSlink, "N", 1))
              {
                math_error(_WSlink, LOCAL_INFO, "Error sending packet through WSTP");
                return ;
              }
            /* Send the variable symbol, preceeded by functions to parse non-alphanumerical chars */
            boost::replace_all(_symbol, "\\[", "\\\\[");
            if(!WSPutFunction(_WSlink, "ToExpression",1) or
               !WSPutString(_WSlink, _symbol.c_str()))
            {
              math_error(_WSlink, LOCAL_INFO, "Error sending packet through WSTP");
              return ;
            }
            /* Mark the end of the message */
            if(!WSEndPacket(_WSlink))
            {
              math_error(_WSlink, LOCAL_INFO, "Error sending packet through WSTP");
              return ;
            }
            /* Wait to receive a packet from the kernel */
            int pkt;
            while( (pkt = WSNextPacket(_WSlink), pkt) && pkt != RETURNPKT)
            {
              WSNewPacket(_WSlink);
              if (WSError(_WSlink))
              {
                math_error(_WSlink, LOCAL_INFO, "Error reading packet from WSTP");
                return ;
              }
            }
            /* Read the received packet into the return value, unless it's void */
            if(!boost::is_same<TYPE, void>::value)
            {
              if(!boost::is_same<TYPE, int>::value and
                 !boost::is_same<TYPE, float>::value and
                 !boost::is_same<TYPE, double>::value and
                 !boost::is_same<TYPE, bool>::value and
                 !boost::is_same<TYPE, char>::value and
                 !boost::is_same<TYPE, str>::value)
                backend_warning().raise(LOCAL_INFO, "Error, WSTP type not recognised");
              else if(!WSGetVariable(_WSlink, &_var))
                math_error(_WSlink, LOCAL_INFO, "Error reading packet from WSTP");
            }
          }
          catch (std::exception& e) { ini_catch(e); }
        #else
          // Avoid compiler warnings
          (void)be;
          (void)ver;
        #endif
      }
      // Assignment operator with TYPE
      mathematica_variable& operator=(const TYPE& val)
      {
        #ifdef HAVE_MATHEMATICA
          using namespace Backends;
          if (_WSlink == (WSLINK)0) backend_error().raise(LOCAL_INFO, "Backend is missing.");
          // Clear the variable that is to be replaced
          if(!WSPutFunction(_WSlink, "Clear", 1) or
             !WSPutFunction(_WSlink, "StringDrop", 2) or
             !WSPutFunction(_WSlink, "StringDrop", 2) or
             !WSPutFunction(_WSlink, "ToString", 1) or
             !WSPutFunction(_WSlink, "ToExpression", 3) or
             !WSPutString(_WSlink, _symbol.c_str()) or
             !WSPutSymbol(_WSlink, "StandardForm") or
             !WSPutSymbol(_WSlink, "Hold") or
             !WSPutInteger(_WSlink, 5) or
             !WSPutInteger(_WSlink, -1) )
          {
            math_error(_WSlink, LOCAL_INFO, "Error sending packet through WSTP");
            return *this;
          }
          // Mark the end of the message
          if(!WSEndPacket(_WSlink))
          {
            math_error(_WSlink, LOCAL_INFO, "Error sending packet through WSTP");
            return *this;
          }
          // Wait to receive a packet from the kernel
          int pkt;
          while( (pkt = WSNextPacket(_WSlink), pkt) && pkt != RETURNPKT)
          {
            WSNewPacket(_WSlink);
            if (WSError(_WSlink))
            {
              math_error(_WSlink, LOCAL_INFO, "Error reading packet from WSTP");
              return *this;
            }
          }
          // Discard it
          WSNewPacket(_WSlink);
          // Send the expression SYMBOL = val
          std::stringstream ss;
          ss << _symbol << " = " << val;
          if(!WSPutFunction(_WSlink, "ToExpression", 1) or
             !WSPutString(_WSlink, ss.str().c_str()))
          {
            math_error(_WSlink, LOCAL_INFO, "Error sending packet through WSTP");
            return *this;
          }
          // Mark the end of the message
          if(!WSEndPacket(_WSlink))
          {
            math_error(_WSlink, LOCAL_INFO, "Error sending packet through WSTP");
            return *this;
          }
          // Wait to receive a packet from the kernel
          while( (pkt = WSNextPacket(_WSlink), pkt) && pkt != RETURNPKT)
          {
            WSNewPacket(_WSlink);
            if (WSError(_WSlink))
            {
              math_error(_WSlink, LOCAL_INFO, "Error reading packet from WSTP");
              return *this;
            }
          }
          // Read the received packet into the return value, unless it's void
          if(!boost::is_same<TYPE, void>::value)
          {
            if(!boost::is_same<TYPE, int>::value and
               !boost::is_same<TYPE, float>::value and
               !boost::is_same<TYPE, double>::value and
               !boost::is_same<TYPE, bool>::value and
               !boost::is_same<TYPE, char>::value and
               !boost::is_same<TYPE, str>::value)
              backend_warning().raise(LOCAL_INFO, "Error, WSTP type not recognised");
            else if(!WSGetVariable(_WSlink, &_var))
            {
              math_error(_WSlink, LOCAL_INFO, "Error reading packet from WSTP");
              return *this;
            }
          }
        #else
          backend_error().raise(LOCAL_INFO, "Attempted to assign a C++ type to a mathematica_variable without Mathematica.");
        #endif
        _var = val;
        return *this;
      }
      // Cast operator for type TYPE
      operator TYPE const()
      {
        #ifdef HAVE_MATHEMATICA
          using namespace Backends;
          if (_WSlink == (WSLINK)0) backend_error().raise(LOCAL_INFO, "Backend is missing.");
          try
          {
            /* If TYPE is a numeric type, send N first */
            if(boost::is_same<TYPE, int>::value or
               boost::is_same<TYPE, float>::value or
               boost::is_same<TYPE, double>::value)
              if(!WSPutFunction(_WSlink, "N", 1))
              {
                math_error(_WSlink, LOCAL_INFO, "Error sending packet through WSTP");
                return _var;
              }
            /* Send the variable symbol */
            if(!WSPutFunction(_WSlink, "ToExpression", 1) or
               !WSPutString(_WSlink, _symbol.c_str()))
            {
              math_error(_WSlink, LOCAL_INFO, "Error sending packet through WSTP");
              return _var;
            }
            /* Mark the end of the message */
            if(!WSEndPacket(_WSlink))
            {
              math_error(_WSlink, LOCAL_INFO, "Error sending packet through WSTP");
              return _var;
            }
            /* Wait to receive a packet from the kernel */
            int pkt;
            while( (pkt = WSNextPacket(_WSlink), pkt) && pkt != RETURNPKT)
            {
              WSNewPacket(_WSlink);
              if (WSError(_WSlink))
              {
                math_error(_WSlink, LOCAL_INFO, "Error reading packet from WSTP");
                return _var;
              }
            }
            /* Read the received packet into the return value, unless it's void */
            if(!boost::is_same<TYPE, void>::value)
            {
              if(!boost::is_same<TYPE, int>::value and
                 !boost::is_same<TYPE, float>::value and
                 !boost::is_same<TYPE, double>::value and
                 !boost::is_same<TYPE, bool>::value and
                 !boost::is_same<TYPE, char>::value and
                 !boost::is_same<TYPE, str>::value)
                backend_warning().raise(LOCAL_INFO, "Error, WSTP type nor recognised");
              else if(!WSGetVariable(_WSlink, &_var))
                math_error(_WSlink, LOCAL_INFO, "Error reading packet from WSTP");
            }
          }
          catch (std::exception &e) { ini_catch(e); }
          return _var;
        #else
          backend_error().raise(LOCAL_INFO, "Attempted to assign a C++ type to a mathematica_variable without Mathematica.");
        #endif
        return _var;
      }
  };
}
#endif /* __mathematica_variable_hpp__ */
Updated on 2025-02-12 at 16:10:36 +0000