Difference between revisions of "ApCoCoA-1:MatlabInterface"

From ApCoCoAWiki
(New page: = MatlabToolbox Interface = The ApCoCoALib is written in C++ and therefore the potential number of users is limited to people who are comfortable writing C++ code. But many users of Compu...)
 
m (page moved)
 
(11 intermediate revisions by 2 users not shown)
Line 11: Line 11:
  
 
= Downloads =
 
= Downloads =
'''Caution''': The current source codes are prepared to compile with MSVC 2005 only. The use of any other compiler but MSVC 2005 will lead to spectacular link failures since one cannot link C++ binaries produced by MSVC 2005 with for example MSVC 2003. You also need to have the runtime of MSVC 2005 installed on your system to make this work. In case you experience problems you can always ask questions in the [http://www.apcocoa.org/forum ApCoCoA forum].  
+
The current version of the toolbox is compiled with MSVC 2003 Express with MS Platform SDK. In case you experience problems you can always ask questions in the [http://www.apcocoa.org/forum ApCoCoA forum].  
  
* Date: 12.11.2006
+
The process of building the MatlabInterface is described at [[ApCoCoA-1:HowTo:Compile_MatlabToolbox_on_Windows | Compile on Windows]]. Links for downloads are also offered there.
** Precompiled for Windows (32bit): (add link) ApCoCoAInterface.zip ........ (contains precompiled versions: ApCoCoALib.dll, gmplib.dll, PreProcessing.mexw32)
 
** Source code: (add link)
 
* [http://fsmath.mathematik.uni-dortmund.de/~mabshoff/CoCoA/MatLabToolbox/MatLabToolbox-2006-11-22.rar MatLabToolbox-2006-11-27.rar] (3.2MB). For help type '''nmake -f makefile.vc''' in the root directory.
 
* [http://fsmath.mathematik.uni-dortmund.de/~mabshoff/CoCoA/MatLabToolbox/MatLabToolbox-2006-11-22.rar MatLabToolbox-2006-11-22.rar] (3.4MB)
 
  
 
=Design=
 
=Design=
Line 35: Line 31:
 
ApCoCoALib.cpp:
 
ApCoCoALib.cpp:
 
<cpp>#include "CoCoA/library.H"
 
<cpp>#include "CoCoA/library.H"
using namespace CoCoA;
+
#include "ApCoCoA/Library.H"
 +
#include "mex.h"
 
#include <vector>
 
#include <vector>
 
using std::vector;
 
using std::vector;
extern "C" __declspec(dllexport) int PreProcess(double
 
*tolerance, int rows, int cols, double *OrigArray, double
 
*PreProcessedArray, int aType)
 
{
 
// Variables
 
vector<double> toler(cols);
 
vector<ApproxPts::ApproxPt> OrigPts(rows,
 
  
ApproxPts::ApproxPt(cols));
+
extern "C" __declspec(dllexport) int LibPreprocess(mxArray *Tolerance, mxArray *OrigArray,
vector<ApproxPts::ApproxPt> PreprocessedPts;
+
                                                int aType, mxArray *PreProcessedArray){
// Define toler parameter
+
 
for (int i=0; i < cols; i++)
+
  double *tolerance = mxGetPr(Tolerance);
{toler[i]=tolerance[i];}
+
  double *OrigData = mxGetPr(OrigArray);
// Rearrange original points to fit needed parameter structure
+
  int rows = (int) mxGetM(OrigArray);
for (int i=0; i < rows; ++i)
+
  int cols = (int) mxGetN(OrigArray);
for (int j=0; j < cols; ++j)
+
 
{OrigPts[i][j]=OrigArray[i*cols+j];}
+
  CoCoA::GlobalManager CoCoAFoundations;
// Call Preprocess function in ApCoCoALib
+
 
switch ( aType ) {
+
  std::vector<double> toler(cols);
case 1 :  
+
  std::vector<CoCoA::ApproxPts::ApproxPt> OrigPts(rows, CoCoA::ApproxPts::ApproxPt(cols));
ApproxPts::PreprocessGridAlgm(PreprocessedPts, OrigPts, toler);
+
  std::vector<CoCoA::ApproxPts::ApproxPt> PreprocessedPts;
break;
+
 
case 2 :  
+
  // Build tolerance parameter
ApproxPts::PreprocessAggrAlgm(PreprocessedPts, OrigPts, toler);
+
  for (int i=0; i < cols; i++)
break;
+
    {toler[i]=tolerance[i];}
case 3:
+
 
                ApproxPts::PreprocessSubdivAlgm(PreprocessedPts, OrigPts, toler);
+
  // Copy original data to vector
break;
+
  for (int i=0; i < rows; ++i) {
}
+
    for (int j=0; j < cols; ++j){
// Rearrange preprocessed points
+
      OrigPts[i][j]=OrigData[j*rows+i];
for (int i=0; i < PreprocessedPts.size(); i++)
+
    }
for (int j=0; j < cols; j++)
+
  }
{PreProcessedArray[i*cols+j] = PreprocessedPts[i][j];}
+
 
// Return number of calculated rows/points
+
  // Call Preprocess function in ApCoCoALib
return PreprocessedPts.size();
+
  switch ( aType ) {
}</cpp>
+
    case 1 :  
 +
    CoCoA::ApproxPts::PreprocessGridAlgm(PreprocessedPts, OrigPts, toler);
 +
    break;
 +
    case 2 :  
 +
    CoCoA::ApproxPts::PreprocessAggrAlgm(PreprocessedPts, OrigPts, toler);
 +
    break;
 +
    case 3:
 +
    CoCoA::ApproxPts::PreprocessSubdivAlgm(PreprocessedPts, OrigPts, toler);
 +
    break;
 +
  }
 +
 
 +
  // Rearrange preprocessed points
 +
  int rowsRes = PreprocessedPts.size();
 +
 
 +
  double *content;
 +
  size_t noBytes = cols * rowsRes * sizeof(double);
 +
 
 +
  if ((content = (double*)mxRealloc(mxGetPr(PreProcessedArray), noBytes))==NULL){
 +
    return -1;
 +
  }
 +
  mxSetPr(PreProcessedArray, content);
 +
  mxSetM(PreProcessedArray, rowsRes);
 +
  mxSetN(PreProcessedArray, cols);
 +
 
 +
  for (int i=0; i < rowsRes; i++) {
 +
    for (int j=0; j < cols; j++) {
 +
    content[j*rowsRes+i] = PreprocessedPts[i][j];
 +
    }
 +
  }
  
and PreProcessing.c
+
  return 0;
<c> #include "mex.h"
+
}</cpp>
#include "matrix.h"
 
__declspec(dllexport) int PreProcess(double *tolerance, int rows, int cols,
 
                    double *OrigArray, double *PreProcessedArray, int aType);
 
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const
 
  
mxArray *prhs[])
+
and Preprocess.c
{
+
<c> #include "mex.h"
// Variables
+
  #include "matrix.h"
mxArray *Toler, *Rows, *Cols, *OrigPts, *AlgType;
 
double *preProcessed, *origData, *result, *tol;
 
int rowLen, colLen, strLen, numPP, nElPP, nEl, i, algo;
 
/*
 
Check for proper number of input arguments.  
 
  Required are:
 
1. Tooler (tolerance vector, for each dimension)
 
2. Rows (of original data matrix - points of data)
 
3. Cols (of original data matrix - dimension of data)
 
4. OrigPoints (Pointer for data, 1xn matrix)
 
5. AlgType (1 = Grid, 2 = Aggr, 3 = Subdiv)
 
*/   
 
if (nrhs != 5)
 
{mexErrMsgTxt("5 input arguments required.");}
 
// Get input data
 
Toler = prhs[0];
 
Rows = prhs[1];
 
Cols = prhs[2];
 
OrigPts = prhs[3];
 
AlgType = prhs[4];
 
tol=mxGetPr(Toler);
 
rowLen = (int) mxGetScalar(Rows);
 
colLen = (int) mxGetScalar(Cols);
 
origData = mxGetPr(OrigPts);
 
algo = mxGetScalar(AlgType);
 
// Prepare array for result
 
nEl = rowLen*colLen;
 
preProcessed = malloc(nEl * sizeof(double));
 
// Run calculation
 
numPP = PreProcess(tol, rowLen, colLen, origData, preProcessed, algo);
 
nElPP = numPP*colLen;
 
// Return preprocessed points
 
plhs[0] = mxCreateDoubleMatrix(1, nElPP, mxREAL);
 
for (i=0; i < nElPP; i++)
 
{
 
result = mxGetPr(plhs[0]);
 
result[i] = preProcessed[i];
 
}
 
// clean up
 
free(preProcessed);
 
}</c>
 
  
We use '''mex.bat''' to compile the second file into a mex plugin (as '''C''' code) while we use '''cl.exe''' to compile the first file into a DLL.
+
  __declspec(dllimport) int LibPreprocess(mxArray *Tolerance, mxArray *OrigArray, int aType, mxArray *PreProcessedArray);
  
=Functions provided=
+
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
 +
{
 +
  mxArray *myRes;
 +
  int algo, retCode;
  
Obviously the goal is to provide every available function in the ApCoCoALib to users of Matlab. Due to our own needs at the moment the first functions to work will be:
+
  if (nrhs != 3)
* PreProcessing
+
    {mexErrMsgTxt("3 input arguments required.");}
* Approximate Buchberger-M&ouml;ller
+
  algo = mxGetScalar(prhs[2]);
* Syzygy computation for ideals
+
  myRes = mxCreateDoubleMatrix(0, 0, mxREAL);
 +
  // Run calculation
 +
  retCode = LibPreprocess(prhs[0], prhs[1], algo, myRes);
 +
  if (retCode==-1){
 +
    mexErrMsgTxt("Error in Preprocess.c: Reallocation failed. Out of memory.");
 +
  }
 +
  // Assign to output
 +
  plhs[0] = myRes;
 +
}</c>
  
==PreProcessing==
+
We use '''mex.bat''' to compile the second file into a mex plugin (as '''C''' code) while we use '''cl.exe''' to compile the first file into a DLL.
Due to the current implementation of PreProcessing.c the data needs to be a vector but most of the data we work with in Matlab is in matrix form. Thus the following code might be usefull to use the PreProcessing function in your Matlab codes:
 
  
PrepPreProcessing.m
+
=Functions provided=
<matlab> function result = PrepPreProcessing(tolerance, data, algtype)
 
    [nRows, nCols] = size(data);
 
    transferedData = reshape(data',1,nRows*nCols);
 
    resultPP =  
 
  
PreProcessing(tolerance,nRows,nCols,transferedData,algtype);
+
The available functions are listed on [http://www.apcocoa.org/wiki/ApCoCoA:MatlabToolbox Matlab Toolbox]
    nRows2 = length(resultPP)/nCols;
 
    result = reshape(resultPP,nCols,nRows2)';</matlab>
 
  
 
[[Category:MatlabToolbox]]
 
[[Category:MatlabToolbox]]

Latest revision as of 09:13, 29 October 2020

MatlabToolbox Interface

The ApCoCoALib is written in C++ and therefore the potential number of users is limited to people who are comfortable writing C++ code. But many users of Computer Algebra systems or other software might benefit from the functionality provided by the CoCoALib. One such piece of software is Matlab which among other things allows the user to integrate C, Fortran and C++ libraries. The integration is not too difficult for libraries written in C or Fortran but there are severe restrictions for libraries written in C++. Due to that fact we are currently working on the necessary bits to provide the functionality of the CoCoALib in MatLab.

We want to provide the MatLabToolbox as binary blob as well as in source. Since the CoCoALib runs on a wide number of 32 and 64 bit platforms we expect to provide binaries for

  • x86 & x86-64 Linux
  • x86 & x86-64 Windows
  • 32bit PPC MacOSX
  • Sparc Solaris

This obviously depends on access to appropriate hardware and MatLab binaries.

Downloads

The current version of the toolbox is compiled with MSVC 2003 Express with MS Platform SDK. In case you experience problems you can always ask questions in the ApCoCoA forum.

The process of building the MatlabInterface is described at Compile on Windows. Links for downloads are also offered there.

Design

C++ with exceptions and RTTI vs. MatLab

The design is quite complex due to the fact that integrating C++ code into a mex file has severe restrictions, most significantly:

  • Limitation to g++ 3.2.2 on Linux. Using g++ 3.2.1 or 3.2.3 might lead to crashes or unexpected behaviour in general. While this might have been ok two years ago most current systems now ship with g++ 4.0 or 4.1.
  • The Microsoft compiler does disable exception handling or RTTI per default. Mex also explicitly disables exceptions in C++ code in the mexopts.bat file. While one obviously is free to change that we have been unable to create a mex plugin compiled with exceptions and RTTI. Since those two features are essential to the CoCoALib a different way had to be found.

It has also been reported that migrating C++ code from R13 to R14 has usually not been as easy as one could hope. This is obviously only anecdotal evidence, as each of the google groups on the other hands provides plenty of people seeking help.

Using C wrapper around the ApCoCoALib

The solution is to use extern "C" functions inside a second DLL. That second DLL can be compiled with exceptions and RTTI. For a demonstration look at the following two code snippets demonstrating the integration of the PreProcessing function:

ApCoCoALib.cpp: <cpp>#include "CoCoA/library.H"

  1. include "ApCoCoA/Library.H"
  2. include "mex.h"
  3. include <vector>

using std::vector;

extern "C" __declspec(dllexport) int LibPreprocess(mxArray *Tolerance, mxArray *OrigArray,

                                               int aType, mxArray *PreProcessedArray){
 
 double *tolerance = mxGetPr(Tolerance);
 double *OrigData = mxGetPr(OrigArray);
 int rows = (int) mxGetM(OrigArray);
 int cols = (int) mxGetN(OrigArray);
 CoCoA::GlobalManager CoCoAFoundations;
 
 std::vector<double> toler(cols);
 std::vector<CoCoA::ApproxPts::ApproxPt> OrigPts(rows, CoCoA::ApproxPts::ApproxPt(cols));
 std::vector<CoCoA::ApproxPts::ApproxPt> PreprocessedPts;
 // Build tolerance parameter
 for (int i=0; i < cols; i++)
   {toler[i]=tolerance[i];}
 // Copy original data to vector
 for (int i=0; i < rows; ++i) {
   for (int j=0; j < cols; ++j){
     OrigPts[i][j]=OrigData[j*rows+i];
   }
 }
 // Call Preprocess function in ApCoCoALib
 switch ( aType ) {
   case 1 : 

CoCoA::ApproxPts::PreprocessGridAlgm(PreprocessedPts, OrigPts, toler); break;

   case 2 : 

CoCoA::ApproxPts::PreprocessAggrAlgm(PreprocessedPts, OrigPts, toler); break;

   case 3:

CoCoA::ApproxPts::PreprocessSubdivAlgm(PreprocessedPts, OrigPts, toler); break;

 }
 // Rearrange preprocessed points
 int rowsRes = PreprocessedPts.size();
 double *content;
 size_t noBytes = cols * rowsRes * sizeof(double);
 if ((content = (double*)mxRealloc(mxGetPr(PreProcessedArray), noBytes))==NULL){
   return -1;
 }
 mxSetPr(PreProcessedArray, content);
 mxSetM(PreProcessedArray, rowsRes);
 mxSetN(PreProcessedArray, cols);
 
 for (int i=0; i < rowsRes; i++) {
   for (int j=0; j < cols; j++) {

content[j*rowsRes+i] = PreprocessedPts[i][j];

   }
 }
 return 0;

}</cpp>

and Preprocess.c <c> #include "mex.h"

 #include "matrix.h"
 __declspec(dllimport) int LibPreprocess(mxArray *Tolerance, mxArray *OrigArray, int aType, mxArray *PreProcessedArray);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])

{

 mxArray *myRes;
 int algo, retCode;
 if (nrhs != 3) 
   {mexErrMsgTxt("3 input arguments required.");}
 algo = mxGetScalar(prhs[2]);
 myRes = mxCreateDoubleMatrix(0, 0, mxREAL);
 // Run calculation
 retCode = LibPreprocess(prhs[0], prhs[1], algo, myRes);
 if (retCode==-1){
   mexErrMsgTxt("Error in Preprocess.c: Reallocation failed. Out of memory.");
 }
 // Assign to output
 plhs[0] = myRes;

}</c>

We use mex.bat to compile the second file into a mex plugin (as C code) while we use cl.exe to compile the first file into a DLL.

Functions provided

The available functions are listed on Matlab Toolbox