Permalink
Browse files

Merge from branch 'dev'

  • Loading branch information...
m13253 committed Dec 9, 2016
1 parent 70acbfe commit 6488d94c52331e002eadeb4855277d0cca35a53f
Showing with 4,910 additions and 526 deletions.
  1. +5 −4 .gitignore
  2. +51 −4 CMakeLists.txt
  3. +1 −1 build.sh
  4. +54 −10 include/ParTI.h
  5. +35 −0 matlab/@sptMatrix/cap.c
  6. +35 −0 matlab/@sptMatrix/ncols.c
  7. +35 −0 matlab/@sptMatrix/nrows.c
  8. +32 −0 matlab/@sptMatrix/setcap.c
  9. +32 −0 matlab/@sptMatrix/setnrows.c
  10. +63 −0 matlab/@sptMatrix/setvalues.c
  11. +23 −0 matlab/@sptMatrix/sptMatrix.m
  12. +35 −0 matlab/@sptMatrix/stride.c
  13. +61 −0 matlab/@sptMatrix/values.c
  14. +23 −0 matlab/@sptSemiSparseTensor/sptSemiSparseTensor.m
  15. +35 −0 matlab/@sptSizeVector/cap.c
  16. +57 −0 matlab/@sptSizeVector/data.c
  17. +35 −0 matlab/@sptSizeVector/len.c
  18. +32 −0 matlab/@sptSizeVector/setcap.c
  19. +58 −0 matlab/@sptSizeVector/setdata.c
  20. +32 −0 matlab/@sptSizeVector/setlen.c
  21. +23 −0 matlab/@sptSizeVector/sptSizeVector.m
  22. +23 −0 matlab/@sptSparseMatrix/sptSparseMatrix.m
  23. +60 −0 matlab/@sptSparseTensor/inds.c
  24. +34 −0 matlab/@sptSparseTensor/ldivide.m
  25. +21 −0 matlab/@sptSparseTensor/minus.m
  26. +34 −0 matlab/@sptSparseTensor/mldivide.m
  27. +34 −0 matlab/@sptSparseTensor/mrdivide.m
  28. +35 −0 matlab/@sptSparseTensor/mtimes.m
  29. +38 −0 matlab/@sptSparseTensor/ndims.c
  30. +35 −0 matlab/@sptSparseTensor/nmodes.c
  31. +35 −0 matlab/@sptSparseTensor/nnz.c
  32. +21 −0 matlab/@sptSparseTensor/plus.m
  33. +34 −0 matlab/@sptSparseTensor/rdivide.m
  34. +32 −0 matlab/@sptSparseTensor/setnnz.c
  35. +35 −0 matlab/@sptSparseTensor/sortkey.c
  36. +23 −0 matlab/@sptSparseTensor/sptSparseTensor.m
  37. +35 −0 matlab/@sptSparseTensor/times.m
  38. +32 −0 matlab/@sptSparseTensor/values.c
  39. +35 −0 matlab/@sptVector/cap.c
  40. +57 −0 matlab/@sptVector/data.c
  41. +35 −0 matlab/@sptVector/len.c
  42. +32 −0 matlab/@sptVector/setcap.c
  43. +58 −0 matlab/@sptVector/setdata.c
  44. +32 −0 matlab/@sptVector/setlen.c
  45. +23 −0 matlab/@sptVector/sptVector.m
  46. +24 −0 matlab/Makefile
  47. +82 −0 matlab/README.md
  48. +36 −0 matlab/sptAppendMatrix.c
  49. +34 −0 matlab/sptAppendSizeVector.c
  50. +34 −0 matlab/sptAppendVector.c
  51. +32 −0 matlab/sptConstantMatrix.c
  52. +32 −0 matlab/sptConstantVector.c
  53. +39 −0 matlab/sptCopyMatrix.c
  54. +39 −0 matlab/sptCopySemiSparseTensor.c
  55. +39 −0 matlab/sptCopySizeVector.c
  56. +39 −0 matlab/sptCopySparseTensor.c
  57. +39 −0 matlab/sptCopyVector.c
  58. +49 −0 matlab/sptCudaMTTKRP.c
  59. +40 −0 matlab/sptCudaSparseTensorDotMulEq.c
  60. +41 −0 matlab/sptCudaSparseTensorMulMatrix.c
  61. +39 −0 matlab/sptDumpMatrix.c
  62. +39 −0 matlab/sptDumpSizeVector.c
  63. +40 −0 matlab/sptDumpSparseTensor.c
  64. +39 −0 matlab/sptDumpVector.c
  65. +31 −0 matlab/sptFreeMatrix.c
  66. +31 −0 matlab/sptFreeSemiSparseTensor.c
  67. +31 −0 matlab/sptFreeSizeVector.c
  68. +31 −0 matlab/sptFreeSparseTensor.c
  69. +31 −0 matlab/sptFreeVector.c
  70. +47 −0 matlab/sptLoadSparseTensor.c
  71. +49 −0 matlab/sptMTTKRP.c
  72. +42 −0 matlab/sptNewMatrix.c
  73. +47 −0 matlab/sptNewSemiSparseTensor.c
  74. +42 −0 matlab/sptNewSizeVector.c
  75. +46 −0 matlab/sptNewSparseTensor.c
  76. +42 −0 matlab/sptNewVector.c
  77. +50 −0 matlab/sptOmpMTTKRP.c
  78. +40 −0 matlab/sptOmpSparseTensorDotMulEq.c
  79. +41 −0 matlab/sptOmpSparseTensorMulMatrix.c
  80. +33 −0 matlab/sptRandomizeMatrix.c
  81. +34 −0 matlab/sptResizeSizeVector.c
  82. +34 −0 matlab/sptResizeVector.c
  83. +31 −0 matlab/sptSemiSparseTensorSortIndex.c
  84. +40 −0 matlab/sptSemiSparseTensorToSparseTensor.c
  85. +40 −0 matlab/sptSparseTensorAdd.c
  86. +32 −0 matlab/sptSparseTensorDivScalar.c
  87. +40 −0 matlab/sptSparseTensorDotDiv.c
  88. +40 −0 matlab/sptSparseTensorDotMul.c
  89. +40 −0 matlab/sptSparseTensorDotMulEq.c
  90. +41 −0 matlab/sptSparseTensorMulMatrix.c
  91. +32 −0 matlab/sptSparseTensorMulScalar.c
  92. +31 −0 matlab/sptSparseTensorSortIndex.c
  93. +32 −0 matlab/sptSparseTensorSortIndexAtMode.c
  94. +40 −0 matlab/sptSparseTensorSub.c
  95. +39 −0 matlab/sptSparseTensorToMatrix.c
  96. +40 −0 matlab/sptSparseTensorToSemiSparseTensor.c
  97. +175 −0 matlab/sptmx.h
  98. +2 −1 src/matrix/dump.c
  99. +196 −2 src/matrix/matrix.c
  100. +142 −0 src/matrix/matrix_cuda.cu
  101. +17 −9 src/sptensor/add.c
  102. +0 −153 src/sptensor/add_omp.c
  103. +1 −0 src/sptensor/compare.c
  104. +2 −5 src/sptensor/ddiv.c
  105. +2 −3 src/sptensor/dmul.c
  106. +3 −0 src/sptensor/khatri-rao.c
  107. +13 −4 src/sptensor/kronecker.c
  108. +66 −66 src/sptensor/matricize.c
  109. +3 −1 src/sptensor/mmul.c
  110. +5 −20 src/sptensor/mmul_cuda.cu
  111. +3 −1 src/sptensor/mmul_omp.c
  112. +113 −0 src/sptensor/mttkrp.c
  113. +324 −0 src/sptensor/mttkrp_cuda.cu
  114. +108 −0 src/sptensor/mttkrp_omp.c
  115. +58 −0 src/sptensor/slice.c
  116. +0 −71 src/sptensor/sptensor.c
  117. +0 −10 src/sptensor/sptensor.h
  118. +17 −8 src/sptensor/sub.c
  119. +0 −149 src/sptensor/sub_omp.c
  120. +90 −0 src/timer.c
  121. +1 −1 src/{timer.cu → timer_cuda.cu}
  122. +3 −3 src/vector/dump.c
View
@@ -1,7 +1,8 @@
*.ptx
*.swp
.DS_Store
sftp-config.json
*.DS_Store
.tags*
build
build.config
sftp-config.json
*.ptx
*.mex*
docs/latex
View
@@ -1,15 +1,62 @@
cmake_minimum_required(VERSION 3.0)
project(ParTI)
find_package(CUDA)
option(USE_CUDA "Use NVIDIA CUDA library" ON)
option(USE_OpenBLAS "Use OpenBLAS library" ON)
option(USE_MAGMA "Use MAGMA library" ON)
option(USE_MKL "Use Intel MKL library" OFF)
if(USE_CUDA)
find_package(CUDA REQUIRED)
add_definitions(-DPARTI_USE_CUDA)
endif()
# A bug in FindCUDA module forces us to put "link_libraries" before "cuda_add_library".
# So we cannot use "target_link_libraries" for target-wise library tracking.
if(USE_OpenBLAS)
find_package(OpenBLAS REQUIRED)
add_definitions(-DPARTI_USE_OpenBLAS)
include_directories(${OpenBLAS_INCLUDE_DIRS})
link_libraries(${OpenBLAS_LIBRARIES})
endif()
if(USE_MAGMA)
find_library(
MAGMA_LIBRARIES
NAMES magma
PATHS ${MAGMA_DIR}
NO_DEFAULT_PATH
)
add_definitions(-DPARTI_USE_MAGMA)
get_filename_component(MAGMA_LIBDIR "${MAGMA_LIBRARIES}" DIRECTORY)
include_directories("${MAGMA_LIBDIR}/../include")
link_libraries(${MAGMA_LIBRARIES})
endif()
if(USE_MKL)
find_package(MKL REQUIRED)
add_definitions(-DPARTI_USE_MKL)
include_directories(${MKL_INCLUDE_DIRS})
link_libraries(${MKL_LIBRARIES})
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fopenmp")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fopenmp")
file(GLOB_RECURSE PARTI_SRC RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "src/*.c" "src/*.cu" "src/*.h" "include/*.h")
# A bug in FindCUDA module forces us to put "include_directories" before "cuda_add_library".
# So we cannot use "target_include_directories" for target-wise include tracking.
include_directories("include")
cuda_add_library(ParTI SHARED ${PARTI_SRC})
cuda_add_library(ParTI_s STATIC ${PARTI_SRC})
link_libraries("m")
if(USE_CUDA)
file(GLOB_RECURSE PARTI_SRC RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "src/*.c" "src/*.cu" "src/*.h" "include/*.h")
cuda_add_library(ParTI SHARED ${PARTI_SRC})
cuda_add_library(ParTI_s STATIC ${PARTI_SRC})
cuda_add_cublas_to_target(ParTI)
cuda_add_cublas_to_target(ParTI_s)
else()
file(GLOB_RECURSE PARTI_SRC RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "src/*.c" "src/*.h" "include/*.h")
add_library(ParTI SHARED ${PARTI_SRC})
add_library(ParTI_s STATIC ${PARTI_SRC})
endif()
set_target_properties(ParTI PROPERTIES C_STANDARD 99)
set_target_properties(ParTI_s PROPERTIES C_STANDARD 99)
View
@@ -5,7 +5,7 @@ set -e
echo "This script will do an out-of-tree build of ParTI into the 'build' directory."
# If you have GCC >= 6.0 and CUDA <= 8.0,
# write this into 'build.config': -DCMAKE_C_COMPILER=gcc-5
# write this into 'build.config': -DCUDA_HOST_COMPILER=gcc-5
# You can also write other configuation flags into 'build.config'
declare -a CMAKE_FLAGS
[ -e build.config ] && CMAKE_FLAGS=("${CMAKE_FLAGS[@]}" $(<build.config))
View
@@ -21,8 +21,6 @@
#include <stddef.h>
#include <stdio.h>
#include <math.h>
#ifdef __cplusplus
extern "C" {
@@ -105,6 +103,7 @@ typedef struct {
sptMatrix values; /// dense fibers, size nnz*ndims[mode]
} sptSemiSparseTensor;
/**
* An opaque data type to store a specific time point, using either CPU or GPU clock.
*/
@@ -116,6 +115,7 @@ typedef enum {
SPTERR_SHAPE_MISMATCH = 2,
SPTERR_VALUE_ERROR = 3,
SPTERR_ZERO_DIVISION = 4,
SPTERR_NO_MORE = 99,
SPTERR_OS_ERROR = 0x10000,
SPTERR_CUDA_ERROR = 0x20000,
} SptError;
@@ -135,6 +135,7 @@ double sptElapsedTime(const sptTimer timer);
double sptPrintElapsedTime(const sptTimer timer, const char *name);
int sptFreeTimer(sptTimer timer);
/* Dense vector, aka variable length array */
int sptNewVector(sptVector *vec, size_t len, size_t cap);
int sptConstantVector(sptVector * const vec, sptScalar const val);
@@ -158,13 +159,31 @@ int sptDumpSizeVector(sptSizeVector *vec, FILE *fp);
/* Dense matrix */
int sptNewMatrix(sptMatrix *mtx, size_t nrows, size_t ncols);
int sptRandomizeMatrix(sptMatrix *mtx, size_t nrows, size_t ncols);
int sptIdentityMatrix(sptMatrix *mtx);
int sptConstantMatrix(sptMatrix * const mtx, sptScalar const val);
int sptCopyMatrix(sptMatrix *dest, const sptMatrix *src);
void sptFreeMatrix(sptMatrix *mtx);
int sptAppendMatrix(sptMatrix *mtx, const sptScalar values[]);
int sptResizeMatrix(sptMatrix *mtx, size_t newsize);
int sptSparseTensorToMatrix(sptMatrix *dest, const sptSparseTensor *src);
int sptDumpMatrix(sptMatrix *mtx, FILE *fp);
int sptMatrixDotMul(sptMatrix const * A, sptMatrix const * B, sptMatrix const * C);
int sptMatrixDotMulSeq(size_t const mode, size_t const nmodes, sptMatrix ** mats);
int sptOmpMatrixDotMulSeq(size_t const mode, size_t const nmodes, sptMatrix ** mats);
int sptCudaMatrixDotMulSeq(
size_t const mode,
size_t const nmodes,
const size_t rank,
const size_t stride,
sptScalar ** dev_ata);
int sptMatrix2Norm(sptMatrix * const A, sptScalar * const lambda);
int sptOmpMatrix2Norm(sptMatrix * const A, sptScalar * const lambda);
int sptCudaMatrix2Norm(
size_t const nrows,
size_t const ncols,
size_t const stride,
sptScalar * const dev_vals,
sptScalar * const dev_lambda);
/* Sparse matrix */
int sptNewSparseMatrix(sptSparseMatrix *mtx, size_t nrows, size_t ncols);
@@ -179,6 +198,7 @@ int sptLoadSparseTensor(sptSparseTensor *tsr, size_t start_index, FILE *fp);
int sptDumpSparseTensor(const sptSparseTensor *tsr, size_t start_index, FILE *fp);
void sptSparseTensorSortIndex(sptSparseTensor *tsr);
void sptSparseTensorSortIndexAtMode(sptSparseTensor *tsr, size_t mode);
/**
* epsilon is a small positive value, every -epsilon < x < x would be considered as zero
*/
@@ -195,6 +215,7 @@ int sptSemiSparseTensorSortIndex(sptSemiSparseTensor *tsr);
*/
int sptSemiSparseTensorSetIndices(sptSemiSparseTensor *dest, sptSizeVector *fiberidx, sptSparseTensor *ref);
/* Sparse tensor unary operations */
int sptSparseTensorMulScalar(sptSparseTensor *X, sptScalar a);
int sptSparseTensorDivScalar(sptSparseTensor *X, sptScalar a);
@@ -207,11 +228,6 @@ int sptOmpSparseTensorDotMulEq(sptSparseTensor *Z, const sptSparseTensor *X, con
int sptCudaSparseTensorDotMulEq(sptSparseTensor *Z, const sptSparseTensor *X, const sptSparseTensor *Y);
int sptSparseTensorDotDiv(sptSparseTensor *Z, const sptSparseTensor *X, const sptSparseTensor *Y);
/**
* Sparse tensor times a dense matrix (TTM)
* Input: sparse tensor X[I][J][K], dense matrix U[I][R}, mode n={0, 1, 2}
* Output: sparse tensor Y[I][J][R] (e.g. n=2)
*/
int sptSparseTensorMulMatrix(sptSemiSparseTensor *Y, sptSparseTensor *X, const sptMatrix *U, size_t mode);
int sptOmpSparseTensorMulMatrix(sptSemiSparseTensor *Y, sptSparseTensor *X, const sptMatrix *U, size_t mode);
int sptCudaSparseTensorMulMatrix(sptSemiSparseTensor *Y, sptSparseTensor *X, const sptMatrix *U, size_t mode);
@@ -226,9 +242,37 @@ int sptSparseTensorKroneckerMul(sptSparseTensor *Y, const sptSparseTensor *A, co
*/
int sptSparseTensorKhatriRaoMul(sptSparseTensor *Y, const sptSparseTensor *A, const sptSparseTensor *B);
/* OMP functions */
int sptSparseTensorAddOMP(sptSparseTensor *Y, sptSparseTensor *X, size_t const nthreads);
int sptSparseTensorSubOMP(sptSparseTensor *Y, sptSparseTensor *X, size_t const nthreads);
/**
* Matricized tensor times Khatri-Rao product.
*/
int sptMTTKRP(sptSparseTensor const * const X,
sptMatrix ** const mats, // mats[nmodes] as temporary space.
sptSizeVector const * const mats_order, // Correspond to the mode order of X.
size_t const mode,
sptVector * scratch);
int sptOmpMTTKRP(sptSparseTensor const * const X,
sptMatrix ** const mats, // mats[nmodes] as temporary space.
sptSizeVector const * const mats_order, // Correspond to the mode order of X.
size_t const mode,
sptVector * scratch);
int sptCudaMTTKRP(sptSparseTensor const * const X,
sptMatrix ** const mats, // mats[nmodes] as temporary space.
sptSizeVector const * const mats_order, // Correspond to the mode order of X.
size_t const mode,
sptVector * scratch);
int sptCudaMTTKRPDevice(
const size_t mode,
const size_t nmodes,
const size_t nnz,
const size_t rank,
const size_t stride,
const size_t * Xndims,
size_t ** const Xinds,
const sptScalar * Xvals,
const size_t * dev_mats_order,
sptScalar ** dev_mats,
sptScalar * dev_scratch);
#ifdef __cplusplus
}
View
@@ -0,0 +1,35 @@
/*
This file is part of ParTI!.
ParTI! is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
ParTI! 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 Lesser General Public
License along with ParTI!.
If not, see <http://www.gnu.org/licenses/>.
*/
#include <ParTI.h>
#include <stdlib.h>
#include "matrix.h"
#include "mex.h"
#include "../sptmx.h"
spt_DefineSetScalar(spt_mxSetSize, size_t)
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
spt_mxCheckArgs("sptMatrix:cap", 1, "One", 1, "One");
sptMatrix *mtx = spt_mxGetPointer(prhs[0], 0);
mxDestroyArray(plhs[0]);
plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
spt_mxSetSize(plhs[0], 0, mtx->cap);
}
View
@@ -0,0 +1,35 @@
/*
This file is part of ParTI!.
ParTI! is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
ParTI! 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 Lesser General Public
License along with ParTI!.
If not, see <http://www.gnu.org/licenses/>.
*/
#include <ParTI.h>
#include <stdlib.h>
#include "matrix.h"
#include "mex.h"
#include "../sptmx.h"
spt_DefineSetScalar(spt_mxSetSize, size_t)
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
spt_mxCheckArgs("sptMatrix:ncols", 1, "One", 1, "One");
sptMatrix *mtx = spt_mxGetPointer(prhs[0], 0);
mxDestroyArray(plhs[0]);
plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
spt_mxSetSize(plhs[0], 0, mtx->ncols);
}
View
@@ -0,0 +1,35 @@
/*
This file is part of ParTI!.
ParTI! is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
ParTI! 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 Lesser General Public
License along with ParTI!.
If not, see <http://www.gnu.org/licenses/>.
*/
#include <ParTI.h>
#include <stdlib.h>
#include "matrix.h"
#include "mex.h"
#include "../sptmx.h"
spt_DefineSetScalar(spt_mxSetSize, size_t)
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
spt_mxCheckArgs("sptMatrix:nrows", 1, "One", 1, "One");
sptMatrix *mtx = spt_mxGetPointer(prhs[0], 0);
mxDestroyArray(plhs[0]);
plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
spt_mxSetSize(plhs[0], 0, mtx->nrows);
}
View
@@ -0,0 +1,32 @@
/*
This file is part of ParTI!.
ParTI! is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
ParTI! 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 Lesser General Public
License along with ParTI!.
If not, see <http://www.gnu.org/licenses/>.
*/
#include <ParTI.h>
#include <stdlib.h>
#include "matrix.h"
#include "mex.h"
#include "../sptmx.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
spt_mxCheckArgs("sptMatrix:setcap", 0, "No", 2, "Two");
sptMatrix *mtx = spt_mxGetPointer(prhs[0], 0);
size_t cap = mxGetScalar(prhs[1]);
mtx->cap = cap;
}
@@ -0,0 +1,32 @@
/*
This file is part of ParTI!.
ParTI! is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
ParTI! 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 Lesser General Public
License along with ParTI!.
If not, see <http://www.gnu.org/licenses/>.
*/
#include <ParTI.h>
#include <stdlib.h>
#include "matrix.h"
#include "mex.h"
#include "../sptmx.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
spt_mxCheckArgs("sptMatrix:setnrows", 0, "No", 2, "Two");
sptMatrix *mtx = spt_mxGetPointer(prhs[0], 0);
size_t nrows = mxGetScalar(prhs[1]);
mtx->nrows = nrows;
}
Oops, something went wrong.

0 comments on commit 6488d94

Please sign in to comment.