Coder Social home page Coder Social logo

rurlus / carma Goto Github PK

View Code? Open in Web Editor NEW
81.0 3.0 24.0 1.97 MB

Converters between Armadillo matrices (C++) and Numpy arrays using Pybind11

License: Apache License 2.0

CMake 11.28% C++ 75.89% Python 11.75% Shell 0.08% Dockerfile 0.42% C 0.57%
python3 pybind11 armadillo c-plus-plus carma rcpparmadillo cpp numpy

carma's Introduction

carma_logo

A C++ header only library providing conversions between Numpy arrays and Armadillo matrices.

| Documentation |

Linux Build Status MacOS Build Status Windows Build Status Coverage Status Documentation Status License Release DOI

Introduction

CARMA provides fast bidirectional conversions between Numpy arrays and Armadillo matrices, vectors and cubes, much like RcppArmadillo does for R and Armadillo.

The library extends the impressive pybind11 library with support for Armadillo. For details on Pybind11 and Armadillo refer to their respective documentation 1, 2.

Installation

CARMA is a header only library that relies on two other header only libraries, Armadillo and Pybind11. It can be integrated in a CMake build using ADD_SUBDIRECTORY(<path_to_carma>) or installation which provides an interface library target carma::carma that has been linked with Python, Numpy, Pybind11 and Armadillo. See build configuration for details.

It can be installed using:

mkdir build
cd build
# optionally with -DCMAKE_INSTALL_PREFIX:PATH=<path/to/desired/location>
cmake -DCARMA_INSTALL_LIB=ON ..
cmake --build . --config Release --target install

You can than include it in a project using:

FIND_PACKAGE(carma CONFIG REQUIRED)
TARGET_LINK_LIBRARIES(<your_target> PRIVATE carma::carma)

CMake subdirectory

Alternatively you can forgo installing CARMA and directly use it as CMake subdirectory. For Pybind11 and or Armadillo we create target(s) based on user settable version, see build configuration, when they are not defined.

To link with CARMA:

ADD_SUBDIRECTORY(extern/carma)
TARGET_LINK_LIBRARIES(<your_target> PRIVATE carma::carma)

CARMA and Armadillo can then be included using:

#include <carma>
#include <armadillo>

CARMA provides a number of configurations that can be set in the carma_config.cmake file at the root of the directory or passed to CMake, see Configuration and Build configuration documentation sections for details.

Requirements

Numpy v2.* is supported by CARMA >= v0.8.0 which requires a compiler with support for C++14 and supports:

  • Python 3.8 -- 3.12
  • Numpy >= 1.14
  • Pybind11 >= v2.12.0
  • Armadillo >= 10.5.2

CARMA <= v0.7 requires a compiler with support for C++14 and supports:

  • Python 3.8 -- 3.12
  • Numpy >= 1.14 < 2.0
  • Pybind11 >= v2.6.0 < v2.12.0
  • Armadillo >= 10.5.2

CARMA makes use of Armadillo's ARMA_ALIEN_MEM_ALLOC and ARMA_ALIEN_MEM_FREE functionality introduced in version 10.5.2 to use Numpy's (de)allocator.

Considerations

In order to achieve fast conversions the default behaviour is avoid copying both from and to Numpy whenever possible and reasonable. This allows very low overhead conversions but it impacts memory safety and requires user vigilance.

If you intend to return the memory of the input array back as another array, you must make sure to either copy or steal the memory on the conversion in or copy the memory out. If you don't the memory will be aliased by the two Numpy arrays and bad things will happen.

A second consideration is memory layout. Armadillo is optimised for column-major (Fortran order) memory whereas Numpy defaults to row-major (C order). The default behaviour is to automatically convert, read copy, C-order arrays to F-order arrays upon conversion to Armadillo. Users should note that the library will not convert back to C-order when returning.

For details see the documentation section Memory Management.

Example

On a high level CARMA provides two ways to work Numpy arrays in Armadillo: Automatic conversion saves a bit on code but provides less flexibility with regards to when to copy and when not. Manual conversion should be used when you need fine grained control.

Combining the two; we use automatic conversion on the conversion in and manual when creating the tuple for the way out.

#include <carma>
#include <armadillo>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <pybind11/pytypes.h>

namespace py = pybind11;

py::tuple ols(arma::mat& X, arma::colvec& y) {
    // We borrow the data underlying the numpy arrays
    int n = X.n_rows, k = X.n_cols;

    arma::colvec coeffs = arma::solve(X, y);
    arma::colvec resid = y - X * coeffs;

    double sig2 = arma::as_scalar(arma::trans(resid) * resid / (n-k));
    arma::colvec std_errs = arma::sqrt(sig2 * arma::diagvec( arma::inv(arma::trans(X)*X)) );

    // We take ownership of the memory from the armadillo objects and
    // return to python as a tuple containing two Numpy arrays.
    return py::make_tuple(
        carma::col_to_arr(coeffs),
        carma::col_to_arr(std_errs)
    );
}

// adapted from https://gallery.rcpp.org/articles/fast-linear-model-with-armadillo/

Which can be called using:

y = np.linspace(1, 100, num=100) + np.random.normal(0, 0.5, 100)
X = np.hstack((np.ones(100)[:, None], np.arange(1, 101)[:, None]))
coeff, std_err = carma.ols(X, y)

The repository contains tests, examples and CMake build instructions that can be used as an reference.

About

This project was created by Ralph Urlus. Significant improvements to the project have been contributed by Pascal H.

License

CARMA is provided under a Apache 2.0 license that can be found in the LICENSE file. By using, distributing, or contributing to this project, you agree to the terms and conditions of this license.

carma's People

Contributors

avilchess avatar conradsnicta avatar hpwxf avatar rurlus avatar yaqwsx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

carma's Issues

Windows bug

To reproduce it:

  • enable Windows support in .travis-ci.yml and run CI test

When test_mat_to_arr.py is reduced to

print("Test armadillo matrix to  numpy array functions.")
import numpy as np

import test_carma as carma

print("Before")

print("Test mat_to_arr with c++ addition.")
sample = np.asarray(
    np.random.normal(size=(10, 2)),
    dtype=np.float,
    order='F'
)
mat = carma.mat_to_arr_plus_one(sample, False)
assert np.allclose(mat, sample + 1)


print("Test mat_to_arr with c++ addition.")
sample = np.asarray(
    np.random.normal(size=(10, 2)),
    dtype=np.float,
    order='F'
)
mat = carma.mat_to_arr_plus_one(sample, True)
assert np.allclose(mat, sample + 1)

print("After")

It is still failing. But if we remove first sub-test or second sub-test, it is OK.
NB: when it fails, there is no output even for the first prints.

  • By removing all other test, we get:
$ ctest -C Release
Test project C:/Users/AzureUser/carma/build
    Start 1: pytest
1/1 Test #1: pytest ...........................Exit code 0xc0000374
***Exception:   0.90 sec

0% tests passed, 1 tests failed out of 1

Total Test time (real) =   0.92 sec

or by hand:

 PYTHONPATH=../build/tests/Release python test_mat_to_arr.py

PS:

  • test_arr_to_mat.py is OK.
  • test_arraystore.py, test_nparray.py, test_type_caster.py are KO like test_mat_to_arr.py

Error in converting large array using

For the following code

SectionPolygon::SectionPolygon(const int &npt, const py::array_t<double> &mat) {

// Following Code Works:
//     auto r = mat.unchecked<2>(); // mat must have ndim = 2; 
//    points = arma::mat(r.shape(0), r.shape(1));
//        for (ssize_t i = 0; i < r.shape(0); i++)
//            for (ssize_t j = 0; j < r.shape(1); j++)
//                points(i,j) = r(i,j);




    nPoints = npt;
    points = carma::arr_to_mat<double>(mat);  // Causes Error

}

Inputs : pts shape is (535,2)

 pts =np.array([
	[-121.15449157, 7.08765441],
	[-118.16564981, 6.51760372],
	[-115.14766845, 5.98635615],
	[-112.10806889, 5.49655813],
	[-109.05437256, 5.05085610],
	[-105.99410086, 4.65189652], .....])

pol = SectionPolygon(pts.shape[0], pts)

res = pol.AreaCentroid()
pol.PrintPoints()

Output

Polygon Points:
  1.2513e-311   7.0877e+00
  1.2513e-311   6.5176e+00
  -1.1515e+02   5.9864e+00
   ....

there are error in first element of first and second row.

There are no issues for smaller numpy arrays.

Compiler used is Visual Studio 2019

Can't modify matrix as a side effect (but don't know if this is supposed to be possible)

First, a clarifying question: is it supposed to be possible to modify a matrix in-place (after borrowing from NumPy) and have those changes reflected in NumPy without returning, that is, as a function side effect? This is what I understood from the "Well behaved" section of the docs:

This is done to ensure the design that pattern that borrowed arrays don’t require a return to reflect the changes.

I'm not totally sure though since the "borrow" section of the "Design Patterns" section mentions that with borrowing you always need to copy out.

I've been unsuccessfully trying to do this (i.e., I make changes to a Mat& after converting to Armadillo and I don't see them back in NumPy) and if this is supposed to be possible I can set up an MRE.

Installation issues

While compiling carma from source and installing into my system library works fine, upon trying to include the interface target in a header file I receive this error:

In file included from ../src/tallem/carma_svd.cpp:2:
/usr/local/carma/include/carma:18:12: fatal error: 'cnalloc.hpp' file not found
  #include <cnalloc.hpp>
           ^~~~~~~~~~~~~

Upon inspection, the interface target file carma looks like:

#ifndef INCLUDE_CARMA_H_
#define INCLUDE_CARMA_H_
...
#ifndef CARMA_ARMA_ALIEN_MEM_FUNCTIONS_SET
  #if defined(ARMA_VERSION_MAJOR)
    #error "carma: please include the armadillo header after the carma header or use the CARMA CMake build"
  #endif
  #include <cnalloc.hpp>
#endif
...
#include "carma_bits/nparray.h"
#include "carma_bits/arraystore.h"
#include "carma_bits/converters.h"
#endif  // INCLUDE_CARMA_H_

Shouldn't the include with cnalloc.hpp use the relative-path include pattern, like the headers at the bottom? Or is this a build configuration problem?

Undefined symbols during packaging

Hi, I am packaging my first library using carma and CMakeLists.txt, and I am continually running into issues where certain LAPACK symbols are undefined.

The two most common issues are:

ImportError: /opt/hostedtoolcache/Python/3.9.10/x64/lib/python3.9/site-packages/gl0learn/_gl0learn.cpython-39-x86_64-linux-gnu.so: undefined symbol: dgemm_
ImportError: dlopen(/Users/tnonet/opt/anaconda3/envs/gl0learn_pypkg/lib/python3.9/site-packages/gl0learn/_gl0learn.cpython-39-darwin.so, 2): Symbol not found: _ddot

Currently, my build process (which seems successful after running pip install .) goes roughly as follows:

Using the setup.py file from pybind's CMakeList example (https://github.com/pybind/cmake_example) and a CMakeLists.txt file as follows

cmake_minimum_required(VERSION 3.4...3.18)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS "-O3")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")

project({NAME})

ADD_SUBDIRECTORY(external/pybind11)
ADD_SUBDIRECTORY(external/carma)

pybind11_add_module({NAME} MODULE
    ...
)
target_include_directories({NAME} PRIVATE ...)

TARGET_LINK_LIBRARIES({NAME} PRIVATE carma::carma)

I have attempted to "pattern" match from the following two examples:

  1. https://github.com/smrfeld/speed-up-python-with-carma/blob/master/gibbs_sampler_library/CMakeLists.txt
  2. https://github.com/RUrlus/carma/blob/stable/examples/CMakeLists.txt

I have also added the following two lines, but this still gives me the dgemm_ symbol error, but it does resolve the ddot_ error.
However, I was under the impression that carma would obtain Armadillo without the need to link the library.

FIND_LIBRARY(ARMADILLO_LIB armadillo HINTS /usr/local/lib/ REQUIRED)
TARGET_LINK_LIBRARIES(_gl0learn PRIVATE ${ARMADILLO_LIB})

Any help would be greatly appreciated! I believe I am close and missing something obvious. I would be happy to help create another carma + pybind example package if it seems other people might fall into a similar issue.

Best,
Tim

Add support for sparse matrices

This is something I'm missing a bit: a way to convert scipy.sparse's csc_matrix into an equivalent arma::sp_mat matrix (and back). I plan to write a converter myself as I need this, but I can imagine it makes a nice addition to the project. If you want, I can open a PR for this soon.

Using ctest for launching tests

It could be convenient to run tests using ctest.
To do that, it requires to keep generated library in build directory (and not to copy them into tests directory).
By that way, it would be possible to have in parallel several build directories for several configurations (e.g. Debug, StaticAnalysis, Release...)

Again, if it could be a good idea, I can do it.

is `cmake v3.16` necessary?

In c991fb0, it looks like the required cmake was bumped to 3.16.

Unfortunately, cmake 3.16 is incompatible with our build process; we are using carma to build a linux wheels out of a python package to ship to PyPI. It is required to build on an old manylinux Docker image on which building cmake 3.16 fails with the following error:

.... long output...
uv-src-unix-fs.c.o: In function `uv__fs_futime':
fs.c:(.text+0x22b): undefined reference to `futimens'
uv-src-unix-fs.c.o: In function `uv__fs_utime':
fs.c:(.text+0xebb): undefined reference to `utimensat'
collect2: error: ld returned 1 exit status
gmake: *** [cmake] Error 1
---------------------------------------------
Error when bootstrapping CMake:
Problem while running gmake
---------------------------------------------
Log of errors: /home/cmake-3.16.0/Bootstrap.cmk/cmake_bootstrap.log

Is it possible to build the stable version of carma with cmake v3.12? Or will this create bugs / is cmake v3.16 absolutely necessary?

How to install carma

I went through the steps here: https://carma.readthedocs.io/en/latest/basic_usage.html to build the system but the last step: To installation carma, you have to define -DCMAKE_INSTALL_PREFIX=/installation/path/directory
is not working. Could someone explain a bit more thoroughly what this step entails? I'm just getting:

zsh: no such file or directory: -DCMAKE_INSTALL_PREFIX=/usr/local

Carma versions not set in `include`

Relevant code:

carma/include/carma

Lines 39 to 41 in 7e4c54f

static constexpr unsigned int major = CARMA_VERSION_MAJOR;
static constexpr unsigned int minor = CARMA_VERSION_MINOR;
static constexpr unsigned int patch = CARMA_VERSION_PATCH;

If including the carma libraries, these lines throw an error because these variables are only set via cmake:

carma/CMakeLists.txt

Lines 3 to 5 in 7e4c54f

SET(CARMA_VERSION_MAJOR 0)
SET(CARMA_VERSION_MINOR 5)
SET(CARMA_VERSION_PATCH 0)

The error is the standard use of undefined identifier CARMA_VERSION_MAJOR etc.

Could you provide guidance on how to fix this? Running cmake does not fix the issue

Remove unused variables

Hi, thanks for making this code. We are using it in https://github.com/ThrunGroup/BanditPAM.

When compiling the code we get the following warnings:

headers/carma/include/carma_bits/cnumpy.h:277:9: warning: unused variable 'ret_code' [-Wunused-variable]
      int ret_code = api.PyArray_CopyInto_(tmp, src);
          ^
  In file included from src/banditpam.cpp:8:
  In file included from headers/kmedoids_algorithm.hpp:4:
  In file included from headers/log_helper.hpp:4:
  In file included from headers/carma/include/carma:59:
  In file included from headers/carma/include/carma_bits/arraystore.h:25:
  In file included from headers/carma/include/carma_bits/converters.h:29:
  headers/carma/include/carma_bits/numpytoarma.h:93:13: warning: unused variable 'dims' [-Wunused-variable]
      ssize_t dims = src.ndim;
              ^
  headers/carma/include/carma_bits/numpytoarma.h:168:13: warning: unused variable 'dims' [-Wunused-variable]
      ssize_t dims = src.ndim;
              ^
  headers/carma/include/carma_bits/numpytoarma.h:224:13: warning: unused variable 'dims' [-Wunused-variable]
      ssize_t dims = src.ndim;
              ^
  headers/carma/include/carma_bits/numpytoarma.h:281:13: warning: unused variable 'dims' [-Wunused-variable]
      ssize_t dims = src.ndim;
              ^
  5 warnings generated.

Crash when assigning one matrix to another

Believe it or not, I actually ran into another, separate heap corruption error when copy-assigning one matrix to another, e.g.,

mre.cpp:

#include "mre.h"

namespace py = pybind11;

class MatrixHolder {
public:
  MatrixHolder(size_t d) {
    A = arma::Mat<double>(d, d, arma::fill::eye);
    std::cerr << "filled arma matrix\n";
  };
  arma::Mat<double> A;
};

PYBIND11_MODULE(pymod, m) {
  py::class_<MatrixHolder>(m, "MH").def(py::init<size_t>())
      .def_readwrite("A", &MatrixHolder::A);
};

pymod_test.py:

print('testing matrix copy assignment')
d = 30
mh1 = MH(d)
mh2 = MH(d)
mh1.A = mh2.A  # <- fails here
print('successfully copied mh2.A to mh1.A')

The matrices have to be large enough to use dynamically allocated memory.
And this bug has shown up for me on Windows with Clang 11/12 and MSVC, as well as WSL Ubuntu using GCC.

Add coverage report

Usually, I use https://coveralls.io (coupled with lcov).
It is easy to do from Travis.

To do that, I have to add new BUILD_MODE. In that case, I will change DEBUG config variable with a BUILD_MODE config variable to support values: Debug, Release, Coverage.

`cibuildwheel` manylinux build issue

Hi,

I am a big fan of carma!

I am transitioning some of my cython bindings that based off https://github.com/andrewcron/cy_armadillo to carma/pybind11 bindings. However, I can't seem to get it to build on AppVeyor using cibuildwheel.

It seems that carma's CMakeList is somewhat incompatible with manylinux which does not have python development libraries installed.

FIND_PACKAGE(Python3 COMPONENTS Interpreter Development NumPy REQUIRED)

This is resulting in the following errors.

Building cp38-manylinux_x86_64 wheel
CPython 3.8 manylinux x86_64
Setting up build environment...
    + /opt/python/cp38-cp38/bin/python -c 'import sys, json, os; json.dump(os.environ.copy(), sys.stdout)'
    + which python
    + which pip
                                                              ✓ 0.12s
Building wheel...
    + rm -rf /tmp/cibuildwheel/built_wheel
    + mkdir -p /tmp/cibuildwheel/built_wheel
    + python -m pip wheel /project --wheel-dir=/tmp/cibuildwheel/built_wheel --no-deps
  error: subprocess-exited-with-error
  
  × Building wheel for l0learn (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [108 lines of output]
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build/lib.linux-x86_64-cpython-38
      creating build/lib.linux-x86_64-cpython-38/l0learn
      copying src/l0learn/models.py -> build/lib.linux-x86_64-cpython-38/l0learn
      copying src/l0learn/interface.py -> build/lib.linux-x86_64-cpython-38/l0learn
      copying src/l0learn/__init__.py -> build/lib.linux-x86_64-cpython-38/l0learn
      running egg_info
      writing src/l0learn.egg-info/PKG-INFO
      writing dependency_links to src/l0learn.egg-info/dependency_links.txt
      writing requirements to src/l0learn.egg-info/requires.txt
      writing top-level names to src/l0learn.egg-info/top_level.txt
      reading manifest file 'src/l0learn.egg-info/SOURCES.txt'
      writing manifest file 'src/l0learn.egg-info/SOURCES.txt'
      running build_ext
      -- The C compiler identification is GNU 10.2.1
      -- The CXX compiler identification is GNU 10.2.1
      -- Detecting C compiler ABI info
      -- Detecting C compiler ABI info - done
      -- Check for working C compiler: /opt/rh/devtoolset-10/root/usr/bin/cc - skipped
      -- Detecting C compile features
      -- Detecting C compile features - done
      -- Detecting CXX compiler ABI info
      -- Detecting CXX compiler ABI info - done
      -- Check for working CXX compiler: /opt/rh/devtoolset-10/root/usr/bin/c++ - skipped
      -- Detecting CXX compile features
      -- Detecting CXX compile features - done
      -- pybind11 v2.9.2
      -- Found PythonInterp: /opt/python/cp38-cp38/bin/python (found version "3.8.13")
      -- Found PythonLibs: /opt/_internal/cpython-3.8.13/lib
      -- Performing Test HAS_FLTO
      -- Performing Test HAS_FLTO - Success
      -- carma: enable arma no debug: OFF
      -- carma: enable extra debug: OFF
      -- carma: enable soft steal: OFF
      -- carma: enable hard steal: OFF
      -- carma: don't require owndata: OFF
      -- carma: don't require f-contiguous: OFF
      CMake Error at /tmp/pip-build-env-qup4s0j5/overlay/lib/python3.8/site-packages/cmake/data/share/cmake-3.22/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
        Could NOT find Python3 (missing: Development NumPy Development.Module
        Development.Embed) (found version "3.8.13")
      Call Stack (most recent call first):
        /tmp/pip-build-env-qup4s0j5/overlay/lib/python3.8/site-packages/cmake/data/share/cmake-3.22/Modules/FindPackageHandleStandardArgs.cmake:594 (_FPHSA_FAILURE_MESSAGE)
        /tmp/pip-build-env-qup4s0j5/overlay/lib/python3.8/site-packages/cmake/data/share/cmake-3.22/Modules/FindPython/Support.cmake:3[181](https://ci.appveyor.com/project/TNonet/l0learn/builds/43544744/job/vf1rpwwab3qkbtn3#L181) (find_package_handle_standard_args)
        /tmp/pip-build-env-qup4s0j5/overlay/lib/python3.8/site-packages/cmake/data/share/cmake-3.22/Modules/FindPython3.cmake:490 (include)
        external/carma/CMakeLists.txt:[187](https://ci.appveyor.com/project/TNonet/l0learn/builds/43544744/job/vf1rpwwab3qkbtn3#L187) (FIND_PACKAGE)

Do you have any advice on how I could work around this? I would also be happy to help with a patch/PR.

Repo does not pass flake8

Hi, thanks again for making this repo.

Running the following command from the top-level directory of the repository:

flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

returns a lot of bugs

Potentially mismatched allocator-deallocator when linking to external shared library

Found in #89, there is an issue with the free from cnalloc.h is used against a plain malloc used by armadillo when a library that includes carma is linked against a library that doesn't.

Say we have shared library A that uses Armadillo but does not use CARMA.
Library A has a function foo that creates a filled matrix and returns it, i.e. allocates memory for matrix using the default Armadillo allocater malloc.

Additionally, we have library B which contains the python bindings for library A and uses CARMA for the conversion to Numpy.
Library B links to lib A.

The issue

If a function in lib B calls foo from lib A the memory of the matrix returned from foo is free'd using the free from cnalloc.h set using ARMA_ALIEN_MEM_FREE_FUNCTION. This triggers a segfault on Windows as there is a mismatch between the allocator and de-allocator.

Work-around

A work-around is to link CARMA using the CMake target with the pre-compiled cnalloc.h header to library A at compilation, for example:

find_package(pybind11 "2.7.1" CONFIG REQUIRED)
find_package(Armadillo "10.6" CONFIG REQUIRED)
find_package(carma "0.6" CONFIG REQUIRED)

add_library(A SHARED a.cpp)
target_link_libraries(A PUBLIC armadillo carma::carma)

pybind11_add_module(B MODULE b.cpp)
target_link_libraries(B PUBLIC A)

However, this does not work when linking against installed shared or static libraries.

Help with Armadillo memory bug in pybind11

Hello, even though this bug doesn't seem to be with Carma itself, I turn to you for help because I'm really stuck and I don't know if the pybind11 or Armadillo communities would be as much help in this.

EDIT: it does appear to be a Carma bug and the MRE is working.

I've been trying to boil it down to an MRE and have been unsuccessful. I will explain what I know here, but since this isn't enough to reproduce the bug, what I need most are some ideas as to where to look. This is basically a very hard-to-reproduce memory corruption error (heap corruption, Windows fatal exception: code 0xc0000374). It seems to happen when I have a matrix A, not initialized, and assign a matrix to it large enough that Armadillo acquires memory. The crash happens when that memory is released.

I'm on Windows 10, using Armadillo 10.6.2 and pybind11 v2.7.1, compiling using Clang 11.

// mat_container.cpp
#include "mat_container.h"

MatrixContainer::MatrixContainer(size_t d) {
    A = arma::Mat<double>(d, d, arma::fill::eye);
    std::cerr << "filled arma matrix\n";
}

Binding code

#include <pybind11/numpy.h>
#include <pybind11/pybind11.h>
#include <armadillo>
#include <carma>
#include "mat_container.h"

PYBIND11_MODULE(example, m) {
  py::class_<MatrixContainer>(m, "MC").def(py::init<size_t, bool>())
       .def_readwrite("A", &MatrixContainer::A);
}

All I need to do to trigger the crash is from Python call example.MC(11) and it crashes upon releasing memory in the matrix destructor of the member variable (not the temporary one assigned to it). Armadillo debug messages right before crash:

@ __cdecl arma::Mat<double>::~Mat(void) [eT = double] [this = 000001569470DBA0]
Mat::destructor: releasing memory

Weird things

  • Only happens when calling from pybind11, not pure C++
  • Only happens when the constructor for the class containing the matrix is in a separately compiled source file. It doesn't happen when the constructor is in the header file.
  • (this part does involve carma) Only happens when assigning a non-identity (e.g., np.ones but not np.eye) matrix to an object's matrix member variable. But this only happens on a class in my source code, not on the smaller test class I created!
  • Only happens when A is large enough for Armadillo to acquire memory instead of use local memory
  • Setting the size of A before assigning to it doesn't solve the issue
  • This appears to be Armadillo-specific, when Armadillo releases memory (confirmed using ARMA_EXTRA_DEBUG), because I don't get a similar error when I use a class with another dynamic memory class like a vector

When A is using acquired memory and is replaced by a matrix using local memory, the crash occurs

mc = MC(11)
mc.A = np.eye(3)

Arma debug messages right before crash, as mc.A is being assigned:

@ void __cdecl arma::Mat<double>::init_warm(arma::uword, arma::uword) [eT = double] [in_n_rows = 3, in_n_cols = 3]
Mat::init(): releasing memory

but not when it's the other way around; this runs successfully. It does not crash as the acquired memory is released as A is destroyed:

mc = MC(3)
mc.A = np.eye(11)

And when an 11x11 A is replaced by another 11x11 matrix from numpy, the crash is again Mat::destructor: releasing memory as in the very first example without assignment from Python. What I deduce from these examples is that the crash is averted when an acquired memory matrix prepared by Carma (not Armadillo) is assigned to a local memory A

Attached files bug1.txt and bug2.txt are the logs from the first example and the failed assignment through Carma

`carma` changes install location based on installation status

Hi @RUrlus,

As a follow-up to this comment, #103 (comment), I believe I have found other questions/issues that I wanted to raise.

I have observed when using scikit build and carma to install a C++ extension library, depending on if I have included carma as a subdirectory vs. have already installed carma, the installation location of the python package changes.

When building wheels for a python package with carma as a subdirectory, the setup process tries to install files outside the project root. An example build can be found here: https://github.com/TNonet/carma-py-example/actions/runs/2367595957.

   [100%] Built target carma_py_example
    Install the project...
    -- Install configuration: "Release"
    -- Installing: /usr/local/./carma_py_example.cpython-36m-darwin.so
    CMake Error at cmake_install.cmake:51 (file):
      file INSTALL cannot copy file
      "/Users/runner/work/carma-py-example/carma-py-example/_skbuild/macosx-10.9-x86_64-3.6/cmake-build/carma_py_example.cpython-36m-darwin.so"
      to "/usr/local/./carma_py_example.cpython-36m-darwin.so": Permission
      denied.

However, when carma is installed directly, this does not happen, and everything installs fine. An example build can be found here https://github.com/TNonet/carma-py-example/actions/runs/2367582605.

The diff between these two commits can be found here: TNonet/carma-py-example@f7abda3

Automatic conversion doesn't work for function references with const& return type

It seems the succinct syntax of simply passing in a reference to the function to be wrapped (see 1 and 2 below) doesn't work for const return types (2). Thankfully it works when using a lambda function without the return type specified (3). Is there a design reason or obstacle to making automatic conversion work for the 2 as in the case of 1?

Here is a minimum example:

#include <carma>
#include <armadillo>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;


class MyClass {
  private:
    arma::Mat<double> A_;

  public:
    MyClass() { A_ = arma::Mat<double>(2, 2); };
    const arma::Mat<double>& A() { return A_; };
    arma::Mat<double>& A_non_const() { return A_; };
};

PYBIND11_MODULE(example, m) {

    py::class_<MyClass>(m, "MyClass")
        .def(py::init<>())

        // 1. this works:
        .def("A_non_const", &MyClass::A_non_const)

        // 2. doesn't work: 
        .def("A", &MyClass::A);

        // 3. this works
        // .def("A", [](const MyClass &self) { return self.A(); });
}

Errors for 2:

[build] ..\python\carma\include/carma_bits/converters.h(763,16): warning: use of identifier 'cast_impl' found via unqualified lookup into dependent bases of class templates is a Microsoft extension [-Wmicrosoft-template]
[build]         return cast_impl(&src, policy, parent);
[build]                ^
[build] ..\python\pybind11\include\pybind11/pybind11.h(213,39): note: in instantiation of member function 'pybind11::detail::type_caster<arma::Mat<double>, void>::cast' requested here
[build]             handle result = cast_out::cast(
[build]                                       ^
[build] ..\python\pybind11\include\pybind11/pybind11.h(108,9): note: in instantiation of function template specialization 'pybind11::cpp_function::initialize<(lambda at ..\python\pybind11\include\pybind11/pybind11.h:108:20), const arma::Mat<double> &, const MyClass *, pybind11::name, pybind11::is_method, pybind11::sibling>' requested here
[build]         initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
[build]         ^
[build] ..\python\pybind11\include\pybind11/pybind11.h(1340,22): note: in instantiation of function template specialization 'pybind11::cpp_function::cpp_function<const arma::Mat<double> &, MyClass, pybind11::name, pybind11::is_method, pybind11::sibling>' requested here
[build]         cpp_function cf(method_adaptor<type>(std::forward<Func>(f)), name(name_), is_method(*this),
[build]                      ^
[build] ..\python\ldsctrlest\example.cpp(27,10): note: in instantiation of function template specialization 'pybind11::class_<MyClass>::def<const arma::Mat<double> &(MyClass::*)() const>' requested here
[build]         .def("A", &MyClass::A);
[build]          ^
[build] ..\python\carma\include/carma_bits/converters.h(716,19): note: must qualify identifier to find this declaration in dependent base class
[build]     static handle cast_impl(armaT&& src, return_value_policy policy, handle) {
[build]                   ^
[build] ..\python\carma\include/carma_bits/converters.h(731,19): note: must qualify identifier to find this declaration in dependent base class
[build]     static handle cast_impl(armaT* src, return_value_policy policy, handle) {
[build]                   ^
[build] ..\python\carma\include/carma_bits/converters.h(763,16): error: no matching function for call to 'cast_impl'
[build]         return cast_impl(&src, policy, parent);
[build]                ^~~~~~~~~
[build] ..\python\carma\include/carma_bits/converters.h(716,19): note: candidate function not viable: no known conversion from 'const arma::Mat<double> *' to 'arma::Mat<double>' for 1st argument; remove &
[build]     static handle cast_impl(armaT&& src, return_value_policy policy, handle) {
[build]                   ^
[build] ..\python\carma\include/carma_bits/converters.h(731,19): note: candidate function not viable: 1st argument ('const arma::Mat<double> *') would lose const qualifier
[build]     static handle cast_impl(armaT* src, return_value_policy policy, handle) {```

Exception handling broken when linking to carma for Windows+Clang

I've got another bug for you! Thankfully it occurred to me this time to test whether carma could be responsible even though it didn't seem like it.

Whereas pybind11 is supposed to turn a C++ exception into a RuntimeError in Python, my program was crashing upon encountering std::runtime_error. Linking to carma turned out to make the difference, even though it isn't used at all, not even included.

Here is an MRE. I only get the bug on Windows; a WSL build works fine for me.

incorrect work of example (as I think)

Hi,

Thank you for the library,

I'm on Windows 10 x64, Qt 5.14.2, MSVC 2017 x64
SeeI just took your example and changed one line of code (I add 1 to armadillo matrix) and I return this matrix. So the code is:

#include <armadillo>
#include <carma/carma.h>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

#include <QtGlobal>

#define EXAMPLE_EXPORT Q_DECL_EXPORT

EXAMPLE_EXPORT py::array_t<double> manual_example(py::array_t<double> & arr) {
    // convert to armadillo matrix without copying.
    arma::Mat<double> mat = carma::arr_to_mat<double>(arr);

    // normally you do something useful here ...
    arma::Mat<double> result = mat + 1;

    // convert to Numpy array and return
    return carma::mat_to_arr(result);
}

PYBIND11_MODULE(example, m) {
    m.def(
        "manual_example",
        &manual_example,
        R"pbdoc(
            Example function for manual conversion.

            Parameters
            ----------
            mat : np.array
                input array
        )pbdoc",
        py::arg("arr")
    );
}

In PyCharm I do:

import numpy as np
a = np.random.rand(3,2)
a
Out[4]: 
array([[0.99094458, 0.56497646],
       [0.78535053, 0.7651588 ],
       [0.77454853, 0.87217206]])
import example
b = example.manual_example(a)
b
Out[8]: 
array([[5.23709585e-322, 1.22078807e-311],
       [1.22078807e-311, 1.22079344e-311],
       [1.22078723e-311, 1.22075786e-311]])

As you can see the output result is incorrect.
What is wrong?

invalid conversion from ‘const arma::Mat<double>*’ to ‘arma::Mat<double>*’

Hi,

I'm trying to use carma (cloned from master today), and I am getting all sorts of errors related to invalid conversions:

invalid conversion from ‘const arma::Mat<double>*’ to ‘arma::Mat<double>*’

In this case the function signature is:

const arma::vec& getQmaxBus( ) const { //some stuff; }

Not sure if it helps, but I have been using this header to do the same that I want to use carma for, and at least this sort of conversions worked flawlessly.

BR,
Santiago

Build issue

I am getting following cmake build out


Microsoft (R) Build Engine version 16.4.0+e901037fe for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

  main.cpp
D:\ws\pybind\carma\include\carma/carma/converters.h(542,25): error C2882: 'pybind11': illegal use of namespace identifi
er in expression [D:\ws\pybind\build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/converters.h(542,25): error C4430: missing type specifier - int assumed. Note: C
++ does not support default-int [D:\ws\pybind\build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/converters.h(543,1): error C2146: syntax error: missing ';' before identifier 'N
AMESPACE_BEGIN' [D:\ws\pybind\build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/converters.h(546,61): error C2065: 'armaT': undeclared identifier [D:\ws\pybind\
build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/converters.h(546,46): error C2923: 'carma::is_convertible': 'armaT' is not a val
id template type argument for parameter 'T' [D:\ws\pybind\build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/converters.h(546,69): error C2955: 'carma::is_convertible': use of class templat
e requires template argument list [D:\ws\pybind\build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/utils.h(34): message : see declaration of 'carma::is_convertible' [D:\ws\pybind\
build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/converters.h(546,77): error C2143: syntax error: missing ';' before '{' [D:\ws\p
ybind\build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/converters.h(546,77): error C2447: '{': missing function header (old-style forma
l list?) [D:\ws\pybind\build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/converters.h(631,15): error C2065: 'detail': undeclared identifier [D:\ws\pybind
\build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/converters.h(631,21): error C4430: missing type specifier - int assumed. Note: C
++ does not support default-int [D:\ws\pybind\build\cmake_example.vcxproj]
D:\ws\pybind\carma\include\carma/carma/converters.h(632,1): error C2146: syntax error: missing ';' before identifier 'N
AMESPACE_END' [D:\ws\pybind\build\cmake_example.vcxproj]`

Cmake setup is as follows


CMAKE_MINIMUM_REQUIRED(VERSION 3.7)
project(cmake_example)


set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_subdirectory(pybind11)
# add_subdirectory(carma)
include_directories(carma/third_party/armadillo-code/include)
include_directories(carma/include)
link_directories("lib")
pybind11_add_module(cmake_example main.cpp)




my lib directories contains blas libs required for armadillo

What's going wrong here?

type

Hello,

Having tried your nice project, I think there is a type in carma.h on line 320.
I guess it should read "T" instead of "double".

Thanks a lot for sharing your project, I had tried to do this on my own, but my knowledge on C++ is too limited.

Best regards,
Roland

Question about library installation + finding carma

On one hand, like arma and pybind11, CARMA is (mostly) header-only. On the other hand, CARMA isn't completely header-only. Compiling any source file after adding the include directory relative to some submodule-or-cloned version of CARMA results in a message like:

...failed to find header file config.h

This isn't surprising, as the file named config.h.in contains cmake-specific installation info that once compiled yields the generated config.h.

However, this makes including carma in another project a little cumbersome. For example, this essentially ties the inclusion of carma in a project to cmake-dependent builds if one assumes carma isn't installed already. For python packages, this may involve invoking cmake via setup.py to explicitly generate to _deps folder with the corresponding includes. In contrast, I found it easier to just configure and install carma to my system library path, then just include it directly using e.g. meson.

I have two questions regarding this:

  1. Is there a way to make carma truly header-only? For example, by using some default configuration for the compile-time variables (e.g. ARMA_ALIEN_MEM_ALLOC) and configuring a "default" config.h? I apologize if it may be more complicated than that.

  2. armadillo can be easily incorporated into other cross-platform build systems, presumably through the use of pkgconfig files, e.g. in meson one can simply do

arma = dependency('armadillo', version : '>=10.5.2', required : true)
executable('foo', 'foo.cc', dependencies : [arma])

or in cmake,

find_package(Armadillo 10.5.2 REQUIRED)
include_directories(${ARMADILLO_INCLUDE_DIRS})
add_executable(foo foo.cc)
target_link_libraries(foo ${ARMADILLO_LIBRARIES})

is there an equivalent for CARMA?

CMake minimal requirement -> 3.7

Using https://github.com/nlohmann/cmake_min_version, it appears that the minimal CMake requirement is CMake 3.9 (if we need DESCRIPTION field in main PROJECT command) or CMake 3.7 if we don't need that description field.

Using the minimal requirement could be useful to be accessible to more users.

PS: this has been tested with CMake config from #35 against all (84) versions of CMake (from 3.1.0 to 3.17.3).

# without DESCRIPTION field, `cmake_minimum_required` defaulted to 3.0,  and clang-format installed
venv/bin/python cmake_min_version.py -- -DBUILD_TESTS=on -DBUILD_EXAMPLES=on -DVALGRIND_TEST_WRAPPER=on -DPYBIND11_PYTHON_VERSION=3.7 -DPYBIND11_CPP_STANDARD=-std=c++14 /data
Found 84 CMake binaries from directory tools

[  0%] CMake 3.11.2 ✔ works
[ 12%] CMake 3.6.2  ✘ error
[ 25%] CMake 3.9.2  ✔ works
[ 38%] CMake 3.8.0  ✔ works
[ 57%] CMake 3.7.0  ✔ works
[ 83%] CMake 3.6.3  ✘ error
[100%] Minimal working version: CMake 3.7.0

cmake_minimum_required(VERSION 3.7.0)

MacOS and Windows support

I'm working to add support for macOS and Windows (code + CI).

By the way, I suggest reorganizing .travis-ci.yml to externalize large part of scripts (with YAML restriction) as external scripts in a .travis-ci directory. My idea is to have the workflow in .travis-ci.yml with implementation detail in the scripts.
By that way, it is easier to verify locally is the scripts are ok (one can run them even without Travis).

As an example, it should be something like:

install:
  # Install dependencies
  - |
    . ${TRAVIS_BUILD_DIR}/.travis-ci/load_env.sh
    ${TRAVIS_BUILD_DIR}/.travis-ci/install.sh
    [[ "$SONAR" = true ]] && ${TRAVIS_BUILD_DIR}/.travis-ci/install_sonar.sh

freeing memory with copy=false

Hi Ralph,

I have a problem when using "col_to_arr" with copy=false, when simply passing an array back and forth between python and C++.
There is py::capsule created which wants to free memory it didn't allocate, resulting into
"
Python(9014,0x111c5edc0) malloc: *** error for object 0x1e4b6e000: pointer being freed was not allocated
"
If I uncomment the delete[] in the base-code, the code goes through without problem, but of coarse this is not what we want. I wonder if the 'delete' shouldn't only be executed if copy=true ?

Best regards,
Roland

arr_to_cube C++ test only fails on Windows with C-contiguous input array

Strangely, the sum check in the arr_to_cube C++ test only fails when:

  • C-contiguous input array
  • copy and strict are false
  • on Windows

To make it stranger the equivalent Python & C++ test does not fail.

The array is aligned and the C-contiguous flag confirms order.
Only difference between this and the Python test is that in the latter the sample generated in python and passed to C++ whereas in the C++ test the sample is generated by Numpy in an embedded interpreter.

Travis logging:

Test arr_to_cube
C-contiguous; no copy; no strict
-------------------------------------------------------------------------------
C:\Users\travis\build\RUrlus\carma\tests\src\test_arr_to_mat_native.cpp(806)

CHECK( std::abs(arr_sum - mat_sum) < 1e-12 )
with expansion:
  2.1004659887 < 0.0
with messages:
  is c-contiguous 1
  is f-contiguous 0
  is aligned 1
  mat_sum is  2.69253
  arr_sum is  4.793
  M [cube slice 0]
    1.2799e-311  -2.0122e+00
    1.2799e-311  -3.9513e-01
    2.3365e-307   1.5593e+00
    3.1152e-307  -2.4754e-01
    4.4504e-307  -2.5511e+00
    1.6132e-307   2.1818e-01
    2.1139e-307  -5.3956e-01
    3.3377e-307  -5.4040e-01
    4.0054e-307  -1.4147e+00
    1.5020e-307  -1.6056e+00
    3.3378e-307   1.4508e+00
    4.0054e-307  -3.0800e-01
    2.1139e-307   1.0647e+00
    6.8980e-307   7.6247e-01
    2.3365e-307  -1.6995e+00
     6.6406e-02  -8.6490e-01
     1.0596e+00  -8.6308e-01
    -3.7244e-01   1.3190e-01
    -2.6103e+00  -4.1815e-01
     9.9660e-02   1.7422e+00
    -4.8554e-01   1.0035e+00
    ...           ...

See https://travis-ci.com/github/RUrlus/carma/jobs/375092339 for full output.

Segfault when accessing large converted matrix

I use the following code to generate a matrix:

import numpy as np
from numpy.random import multivariate_normal

mean = [0] * 5000
sigma = np.eye(5000, 5000)
X = multivariate_normal(mean=mean, cov=sigma, size=5000)

Unfortunately, the following function throws a segfault:

void padmWrapper(py::array_t<double> &X, py::array_t<double> &y) {
    py::print(X);
    arma::mat XA = carma::arr_to_mat<double>(X);
    arma::vec yA = carma::arr_to_col<double>(y);
    std::cout << "Cols: " << XA.n_cols << ", Rows: " << XA.n_rows << "\n";
    for (size_t i=0; i<XA.n_cols; ++i) {
        for (size_t j=0; j<XA.n_rows; ++j) {
             std::cout << XA.at(j, i) << "\n";
        }
    }
    ...
}

py::print(X) works correctly, no error is thrown when the matrix is converted and the number of columns and rows is also printed correctly. But once I access an element in XA a segfault is caused. When I generate a smaller matrix (e.g. 100 times 100) the conversion works correctly and no error occurs.

The code ran on an Ubuntu machine.

Edit:

Generating the matrix as follows does not produce the issue:

import numpy as np
from numpy.random import multivariate_normal

mean = [0] * 5000
sigma = np.eye(5000, 5000)
X = np.asfortranarray(multivariate_normal(mean=mean, cov=sigma, size=5000))

So that gives me a workaround for the moment. I suspect that there is a problem when the underlying data must be copied.

Possible to call `arr_to_mat<float>`?

Is it possible to convert a python numpy array to an Armadillo matrix of floats (not doubles) using CARMA? I'm getting the error below.

I tried looking on the https://carma.readthedocs.io/en/latest/examples.html, but could not find any examples with floats, only with doubles. Strangely it looks from the docs that arr_to_mat is templated to support floats -- do you know what the error might be?

Full error output:

src/python_bindings/fit_python.cpp:39:17: error: no viable conversion from 'Mat<float>' to 'const Mat<double>'
      KMedoids::fit(carma::arr_to_mat<float>(inputData), loss);
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /usr/local/include/armadillo_bits/Mat_bones.hpp:75:31: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const char *' for 1st argument
      inline arma_cold            Mat(const char*        text);
                                  ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:78:31: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const std::string &' (aka 'const basic_string<char, char_traits<char>, allocator<char>> &') for 1st argument
      inline arma_cold            Mat(const std::string& text);
                                  ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:81:21: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const std::vector<double> &' for 1st argument
      inline            Mat(const std::vector<eT>& x);
                        ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:84:21: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const std::initializer_list<double> &' for 1st argument
      inline            Mat(const std::initializer_list<eT>& list);
                        ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:87:21: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const std::initializer_list<std::initializer_list<double>> &' for 1st argument
      inline            Mat(const std::initializer_list< std::initializer_list<eT> >& list);
                        ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:90:21: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'arma::Mat<double> &&' for 1st argument
      inline            Mat(Mat&& m);
                        ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:102:22: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const arma::Mat<double> &' for 1st argument
      inline             Mat(const Mat& m);
                         ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:123:22: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const subview<double> &' for 1st argument
      inline             Mat(const subview<eT>& X);
                         ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:131:10: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const subview_row_strans<double> &' for 1st argument
      inline Mat(const subview_row_strans<eT>& X);  // subview_row_strans can only be generated by the Proxy class
             ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:132:10: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const subview_row_htrans<double> &' for 1st argument
      inline Mat(const subview_row_htrans<eT>& X);  // subview_row_htrans can only be generated by the Proxy class
             ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:133:10: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const xvec_htrans<double> &' for 1st argument
      inline Mat(const        xvec_htrans<eT>& X);  //        xvec_htrans can only be generated by the Proxy class
             ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:138:22: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const subview_cube<double> &' for 1st argument
      inline             Mat(const subview_cube<eT>& X);
                         ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:146:22: note: candidate constructor not viable: no known conversion from 'arma::Mat<float>' to 'const diagview<double> &' for 1st argument
      inline             Mat(const diagview<eT>& X);
                         ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:110:44: note: candidate template ignored: could not match 'BaseCube' against 'Mat'
      template<typename T1> inline             Mat(const BaseCube<eT,T1>& X);
                                               ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:136:10: note: candidate template ignored: could not match 'xtrans_mat' against 'Mat'
      inline Mat(const xtrans_mat<eT,do_conj>& X);  //        xtrans_mat can only be generated by the Proxy class
             ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:154:44: note: candidate template ignored: could not match 'subview_elem1' against 'Mat'
      template<typename T1> inline             Mat(const subview_elem1<eT,T1>& X);
                                               ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:162:57: note: candidate template ignored: could not match 'subview_elem2' against 'Mat'
      template<typename T1, typename T2> inline             Mat(const subview_elem2<eT,T1,T2>& X);
                                                            ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:318:63: note: candidate template ignored: could not match 'Gen' against 'Mat'
      template<typename T1, typename gen_type> inline             Mat(const Gen<T1, gen_type>& X);
                                                                  ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:326:62: note: candidate template ignored: could not match 'Op' against 'Mat'
      template<typename T1, typename op_type> inline             Mat(const Op<T1, op_type>& X);
                                                                 ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:334:63: note: candidate template ignored: could not match 'eOp' against 'Mat'
      template<typename T1, typename eop_type> inline             Mat(const eOp<T1, eop_type>& X);
                                                                  ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:342:62: note: candidate template ignored: could not match 'mtOp' against 'Mat'
      template<typename T1, typename op_type> inline             Mat(const mtOp<eT, T1, op_type>& X);
                                                                 ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:350:62: note: candidate template ignored: could not match 'CubeToMatOp' against 'Mat'
      template<typename T1, typename op_type> inline             Mat(const CubeToMatOp<T1, op_type>& X);
                                                                 ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:358:62: note: candidate template ignored: could not match 'SpToDOp' against 'Mat'
      template<typename T1, typename op_type> inline             Mat(const SpToDOp<T1, op_type>& X);
                                                                 ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:366:77: note: candidate template ignored: could not match 'Glue' against 'Mat'
      template<typename T1, typename T2, typename glue_type> inline             Mat(const Glue<T1, T2, glue_type>& X);
                                                                                ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:377:78: note: candidate template ignored: could not match 'eGlue' against 'Mat'
      template<typename T1, typename T2, typename eglue_type> inline             Mat(const eGlue<T1, T2, eglue_type>& X);
                                                                                 ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:385:77: note: candidate template ignored: could not match 'mtGlue' against 'Mat'
      template<typename T1, typename T2, typename glue_type> inline             Mat(const mtGlue<eT, T1, T2, glue_type>& X);
                                                                                ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:64:19: note: explicit constructor is not a candidate
      inline explicit Mat(const SizeMat& s);
                      ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:171:44: note: explicit constructor is not a candidate
      template<typename T1> inline explicit    Mat(const SpBase<eT, T1>& m);
                                               ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:179:22: note: explicit constructor is not a candidate
      inline explicit    Mat(const SpSubview<eT>& X);
                         ^
    /usr/local/include/armadillo_bits/Mat_bones.hpp:182:22: note: explicit constructor is not a candidate
      inline explicit    Mat(const spdiagview<eT>& X);
                         ^
    headers/algorithms/kmedoids_algorithm.hpp:44:29: note: passing argument to parameter 'inputData' here
      void fit(const arma::mat& inputData, const std::string& loss);
                                ^
    1 error generated.

Refactor of lifetime management Armadillo to Numpy conversion

The current approach has significant drawbacks, for example not all armadillo objects can returned without copying, and is due an overhaul.

The new approach works by moving/copying to a heap allocated object the pointer to which is stored in the capsule.
This allows all dense armadillo types to be returned without copying and the class destructors can be used which improves robustness as well.

  • refactor converters.h
  • refactor capsule functions
  • update arraystore.h
  • write C++ tests
  • update Python tests
  • update documentation

Returning Armadillo cubes as numpy with c-ordering.

Hi Ralph,

I was just wondering for the possibility to return numpy arrays, with a c-ordering, as the result of computations performed with armadillo cubes.

I have been looking at the following function:

  template <typename T> inline py::array_t<T> _cube_to_arr(arma::Cube<T> * src, bool copy) {
        /* Convert armadillo matrix to numpy array */
        ssize_t tsize =  static_cast<ssize_t>(sizeof(T));
        ssize_t nrows = static_cast<ssize_t>(src->n_rows);
        ssize_t ncols = static_cast<ssize_t>(src->n_cols);
        ssize_t nslices = static_cast<ssize_t>(src->n_slices);

        T * data = get_data<arma::Cube<T>>(src, copy);
        py::capsule base = create_capsule(data);

        return py::array_t<T>(
            //{nslices, nrows, ncols}, // shape
            //{tsize * nrows * ncols, tsize, nrows * tsize}, // F-style contiguous strides
            //**********************
	    {nrows, ncols, nslices}, // shape
            {nrows * tsize, tsize, tsize * nrows * ncols}, // F-style contiguous strides
            //**********************
            data, // the data pointer
            base // numpy array references this parent
        );
    } /* _cube_to_arr */

And I have changed the lines between asterisks, but it is still getting errors in the output. Can you imagine what I'm missing here?

Thanks in advance.
Antonio Vilches.

Python.h file not found

I keep getting the error:

In file included from /home/mizkulg/anaconda3/envs/pybind/lib/python3.7/site-packages/pybind11/include/pybind11/buffer_info.h:12,
                 from /usr/local/include/carma/carma/converters.h:22,
                 from /usr/local/include/carma/carma/arraystore.h:1,
                 from /usr/local/include/carma/carma.h:1,
                 from carma.cpp:3:
/home/mizkukg/anaconda3/envs/pybind/lib/python3.7/site-packages/pybind11/include/pybind11/detail/common.h:112:10: fatal error: Python.h: No such file or directory
 #include <Python.h>
          ^~~~~~~~~~
compilation terminated.

Conda 4.8.2
Python 3.7.3

Pybind11 runs fine on other programs that I have. But with carma the example code at examples/example.cpp gives me the error above. I am running:
c++ -O3 -Wall -shared -std=c++14 -fPIC -larmadillo python3 -m pybind11 --includes carma.cpp -o example python3-config --extension-suffix

I've tried all the recommendations on stackoverflow but nothing that I install resolves this problem. Any insight is appreciated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.