I'm trying to return a nested STL container from a member function.
My function signature is: State reset();
My using statements look like this:
using Action = std::vector<int>;
using ID = std::vector<Action>;
using Point = std::array<long, 2>;
using NewDiagonals = std::set<Point>;
using Board = xt::pytensor<int, 3>;
// Meta contains ID, list of all Actions (for all players), list of all NewDiagonals (for all players) and the set of index of remaining pieces for each player
using Meta = std::tuple<ID, std::vector<std::set<Action>>, std::vector<NewDiagonals>, std::vector<std::set<int>>>;
using State = std::tuple<Board, Meta>;
So basically the State reset(); function that I'm concerned with is returning a State, which is a tuple of Board and Meta.
Board is simply a pytensor (from xtensor-python) and can be converted to a numpy array with no problem.
Meta on the other hand, is a tuple of ID, vector<set<Action>>, vector<NewDiagonals>, and vector<set<int>>, where ID is a history (list) of actions taken, vector<set<Action>> is supposed to be the set of actions available for each player (it's a multiplayer board game). I think you get the idea.
The thing is, at the root level, there shouldn't be anything that should not be able to be converted to python, given that I have included #include "pybind11/stl.h".
But when I compile the library and try to call it in python, I get this error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Unable to convert function return value to a Python type! The signature was
(self: Environment.Blokus) -> Tuple[numpy.ndarray[int32], Tuple[List[List[int]], List[Set[List[int]]], List[Set[List[int[2]]]], List[Set[int]]]]
Reproducible example code
#include <vector>
#include <tuple>
#include <map>
#include <array>
#include <set>
#include "pybind11/pybind11.h" // Pybind11 import to define Python bindings
#include "pybind11/stl.h"
#define FORCE_IMPORT_ARRAY // numpy C api loading
#include "xtensor-python/pytensor.hpp" // Numpy bindings
namespace py = pybind11;
using Action = std::vector<int>;
using ID = std::vector<Action>;
using Point = std::array<long, 2>;
using NewDiagonals = std::set<Point>;
// State == {Board, Meta}
using Board = xt::pytensor<int, 3>;
// Meta contains ID, list of all Actions (for all players), list of all NewDiagonals (for all players)
using Meta = std::tuple<ID, std::vector<std::set<Action>>, std::vector<NewDiagonals>, std::vector<std::set<int>>>;
// for env.step()
using State = std::tuple<Board, Meta>;
struct Foo
{
Foo(){}
State foo() {
Board board = xt::zeros<int>({2,3,4});
ID root_id{{0}};
std::vector<std::set<Action>> actions_all(2);
std::vector<NewDiagonals> first_pos{
NewDiagonals{Point{0,0}},
};
std::vector<std::set<int>> remaining(2);
Meta meta = std::tie(root_id, actions_all, first_pos, remaining);
return std::tie(board, meta);
}
};
PYBIND11_MODULE(example, m)
{
xt::import_numpy();
py::class_<Foo>(m, "Foo")
.def(py::init<>())
.def("foo", &Foo::foo);
}
The problem was that c++ set (implemented as a tree) is converted to python set (hash set). And I was putting vectors into sets, which in python is inserting lists into sets -- which is not possible
Issue description
I'm trying to return a nested STL container from a member function.
My function signature is:
State reset();
My
using
statements look like this:So basically the
State reset();
function that I'm concerned with is returning aState
, which is atuple
ofBoard
andMeta
.Board
is simply a pytensor (from xtensor-python) and can be converted to a numpy array with no problem.Meta
on the other hand, is a tuple ofID
,vector<set<Action>>
,vector<NewDiagonals>
, andvector<set<int>>
, whereID
is a history (list) of actions taken,vector<set<Action>>
is supposed to be the set of actions available for each player (it's a multiplayer board game). I think you get the idea.The thing is, at the root level, there shouldn't be anything that should not be able to be converted to python, given that I have included
#include "pybind11/stl.h"
.But when I compile the library and try to call it in python, I get this error:
Reproducible example code