Merge branch 'develop' into feature/cameraTemplateForAllSmartFactors

release/4.3a0
lcarlone 2021-09-23 09:42:03 -04:00
commit c4b64877eb
51 changed files with 734 additions and 195 deletions

View File

@ -85,4 +85,4 @@ make -j2 install
cd $GITHUB_WORKSPACE/build/python cd $GITHUB_WORKSPACE/build/python
$PYTHON setup.py install --user --prefix= $PYTHON setup.py install --user --prefix=
cd $GITHUB_WORKSPACE/python/gtsam/tests cd $GITHUB_WORKSPACE/python/gtsam/tests
$PYTHON -m unittest discover $PYTHON -m unittest discover -v

View File

@ -68,6 +68,8 @@ function configure()
-DGTSAM_USE_QUATERNIONS=${GTSAM_USE_QUATERNIONS:-OFF} \ -DGTSAM_USE_QUATERNIONS=${GTSAM_USE_QUATERNIONS:-OFF} \
-DGTSAM_ROT3_EXPMAP=${GTSAM_ROT3_EXPMAP:-ON} \ -DGTSAM_ROT3_EXPMAP=${GTSAM_ROT3_EXPMAP:-ON} \
-DGTSAM_POSE3_EXPMAP=${GTSAM_POSE3_EXPMAP:-ON} \ -DGTSAM_POSE3_EXPMAP=${GTSAM_POSE3_EXPMAP:-ON} \
-DGTSAM_USE_SYSTEM_EIGEN=${GTSAM_USE_SYSTEM_EIGEN:-OFF} \
-DGTSAM_USE_SYSTEM_METIS=${GTSAM_USE_SYSTEM_METIS:-OFF} \
-DGTSAM_BUILD_WITH_MARCH_NATIVE=OFF \ -DGTSAM_BUILD_WITH_MARCH_NATIVE=OFF \
-DBOOST_ROOT=$BOOST_ROOT \ -DBOOST_ROOT=$BOOST_ROOT \
-DBoost_NO_SYSTEM_PATHS=ON \ -DBoost_NO_SYSTEM_PATHS=ON \

View File

@ -55,6 +55,12 @@ jobs:
version: "9" version: "9"
flag: cayley flag: cayley
- name: ubuntu-system-libs
os: ubuntu-18.04
compiler: gcc
version: "9"
flag: system-libs
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -126,6 +132,12 @@ jobs:
echo "GTSAM_ROT3_EXPMAP=OFF" >> $GITHUB_ENV echo "GTSAM_ROT3_EXPMAP=OFF" >> $GITHUB_ENV
echo "GTSAM Uses Cayley map for Rot3" echo "GTSAM Uses Cayley map for Rot3"
- name: Use system versions of 3rd party libraries
if: matrix.flag == 'system'
run: |
echo "GTSAM_USE_SYSTEM_EIGEN=ON" >> $GITHUB_ENV
echo "GTSAM_USE_SYSTEM_METIS=ON" >> $GITHUB_ENV
- name: Build & Test - name: Build & Test
run: | run: |
bash .github/scripts/unix.sh -t bash .github/scripts/unix.sh -t

View File

@ -38,11 +38,14 @@ if(${GTSAM_SOURCE_DIR} STREQUAL ${GTSAM_BINARY_DIR})
message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ") message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ")
endif() endif()
include(cmake/HandleGeneralOptions.cmake) # CMake build options
# Libraries:
include(cmake/HandleBoost.cmake) # Boost include(cmake/HandleBoost.cmake) # Boost
include(cmake/HandleCCache.cmake) # ccache include(cmake/HandleCCache.cmake) # ccache
include(cmake/HandleCPack.cmake) # CPack include(cmake/HandleCPack.cmake) # CPack
include(cmake/HandleEigen.cmake) # Eigen3 include(cmake/HandleEigen.cmake) # Eigen3
include(cmake/HandleGeneralOptions.cmake) # CMake build options include(cmake/HandleMetis.cmake) # metis
include(cmake/HandleMKL.cmake) # MKL include(cmake/HandleMKL.cmake) # MKL
include(cmake/HandleOpenMP.cmake) # OpenMP include(cmake/HandleOpenMP.cmake) # OpenMP
include(cmake/HandlePerfTools.cmake) # Google perftools include(cmake/HandlePerfTools.cmake) # Google perftools

View File

@ -13,7 +13,8 @@ $ make install
## Important Installation Notes ## Important Installation Notes
1. GTSAM requires the following libraries to be installed on your system: 1. GTSAM requires the following libraries to be installed on your system:
- BOOST version 1.65 or greater (install through Linux repositories or MacPorts) - BOOST version 1.65 or greater (install through Linux repositories or MacPorts). Please see [Boost Notes](#boost-notes).
- Cmake version 3.0 or higher - Cmake version 3.0 or higher
- Support for XCode 4.3 command line tools on Mac requires CMake 2.8.8 or higher - Support for XCode 4.3 command line tools on Mac requires CMake 2.8.8 or higher
@ -66,11 +67,15 @@ execute commands as follows for an out-of-source build:
This will build the library and unit tests, run all of the unit tests, This will build the library and unit tests, run all of the unit tests,
and then install the library itself. and then install the library itself.
## Boost Notes
Versions of Boost prior to 1.65 have a known bug that prevents proper "deep" serialization of objects, which means that objects encapsulated inside other objects don't get serialized.
This is particularly seen when using `clang` as the C++ compiler.
For this reason we require Boost>=1.65, and recommend installing it through alternative channels when it is not available through your operating system's primary package manager.
## Known Issues ## Known Issues
- When using `GTSAM_BUILD_WITH_MARCH_NATIVE=ON`, you may encounter issues in running tests which we are still investigating:
- Use of a version of GCC < 7.5 results in an "Indeterminant Linear System" error for `testSmartProjectionFactor`.
- Use of Boost version < 1.65 with clang will give a segfault for mulitple test cases.
- MSVC 2013 is not yet supported because it cannot build the serialization module of Boost 1.55 (or earlier). - MSVC 2013 is not yet supported because it cannot build the serialization module of Boost 1.55 (or earlier).
# Windows Installation # Windows Installation

View File

@ -144,7 +144,8 @@ if(NOT TBB_FOUND)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
# OS X # OS X
set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb"
"/usr/local/opt/tbb")
# TODO: Check to see which C++ library is being used by the compiler. # TODO: Check to see which C++ library is being used by the compiler.
if(NOT ${CMAKE_SYSTEM_VERSION} VERSION_LESS 13.0) if(NOT ${CMAKE_SYSTEM_VERSION} VERSION_LESS 13.0)
@ -181,7 +182,18 @@ if(NOT TBB_FOUND)
################################## ##################################
if(TBB_INCLUDE_DIRS) if(TBB_INCLUDE_DIRS)
file(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _tbb_version_file) set(_tbb_version_file_prior_to_tbb_2021_1 "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h")
set(_tbb_version_file_after_tbb_2021_1 "${TBB_INCLUDE_DIRS}/oneapi/tbb/version.h")
if (EXISTS "${_tbb_version_file_prior_to_tbb_2021_1}")
file(READ "${_tbb_version_file_prior_to_tbb_2021_1}" _tbb_version_file )
elseif (EXISTS "${_tbb_version_file_after_tbb_2021_1}")
file(READ "${_tbb_version_file_after_tbb_2021_1}" _tbb_version_file )
else()
message(FATAL_ERROR "Found TBB installation: ${TBB_INCLUDE_DIRS} "
"missing version header.")
endif()
string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1"
TBB_VERSION_MAJOR "${_tbb_version_file}") TBB_VERSION_MAJOR "${_tbb_version_file}")
string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1"

44
cmake/HandleMetis.cmake Normal file
View File

@ -0,0 +1,44 @@
###############################################################################
# Metis library
# For both system or bundle version, a cmake target "metis-gtsam-if" is defined (interface library)
# Dont try to use metis if GTSAM_SUPPORT_NESTED_DISSECTION is disabled:
if (NOT GTSAM_SUPPORT_NESTED_DISSECTION)
return()
endif()
option(GTSAM_USE_SYSTEM_METIS "Find and use system-installed libmetis. If 'off', use the one bundled with GTSAM" OFF)
if(GTSAM_USE_SYSTEM_METIS)
# Debian package: libmetis-dev
find_path(METIS_INCLUDE_DIR metis.h REQUIRED)
find_library(METIS_LIBRARY metis REQUIRED)
if(METIS_INCLUDE_DIR AND METIS_LIBRARY)
mark_as_advanced(METIS_INCLUDE_DIR)
mark_as_advanced(METIS_LIBRARY)
add_library(metis-gtsam-if INTERFACE)
target_include_directories(metis-gtsam-if BEFORE INTERFACE ${METIS_INCLUDE_DIR})
target_link_libraries(metis-gtsam-if INTERFACE ${METIS_LIBRARY})
endif()
else()
# Bundled version:
option(GTSAM_BUILD_METIS_EXECUTABLES "Build metis library executables" OFF)
add_subdirectory(${GTSAM_SOURCE_DIR}/gtsam/3rdparty/metis)
target_include_directories(metis-gtsam BEFORE PUBLIC
$<BUILD_INTERFACE:${GTSAM_SOURCE_DIR}/gtsam/3rdparty/metis/include>
$<BUILD_INTERFACE:${GTSAM_SOURCE_DIR}/gtsam/3rdparty/metis/libmetis>
$<BUILD_INTERFACE:${GTSAM_SOURCE_DIR}/gtsam/3rdparty/metis/GKlib>
$<INSTALL_INTERFACE:include/gtsam/3rdparty/metis/>
)
add_library(metis-gtsam-if INTERFACE)
target_link_libraries(metis-gtsam-if INTERFACE metis-gtsam)
endif()
list(APPEND GTSAM_EXPORTED_TARGETS metis-gtsam-if)
install(TARGETS metis-gtsam-if EXPORT GTSAM-exports ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})

View File

@ -32,6 +32,7 @@ endif()
print_build_options_for_target(gtsam) print_build_options_for_target(gtsam)
print_config("Use System Eigen" "${GTSAM_USE_SYSTEM_EIGEN} (Using version: ${GTSAM_EIGEN_VERSION})") print_config("Use System Eigen" "${GTSAM_USE_SYSTEM_EIGEN} (Using version: ${GTSAM_EIGEN_VERSION})")
print_config("Use System Metis" "${GTSAM_USE_SYSTEM_METIS}")
if(GTSAM_USE_TBB) if(GTSAM_USE_TBB)
print_config("Use Intel TBB" "Yes (Version: ${TBB_VERSION})") print_config("Use Intel TBB" "Yes (Version: ${TBB_VERSION})")

View File

@ -1,10 +1,16 @@
############################################################################### ###############################################################################
# Find TBB if (GTSAM_WITH_TBB)
find_package(TBB 4.4 COMPONENTS tbb tbbmalloc) # Find TBB
find_package(TBB 4.4 COMPONENTS tbb tbbmalloc)
# Set up variables if we're using TBB # Set up variables if we're using TBB
if(TBB_FOUND AND GTSAM_WITH_TBB) if(TBB_FOUND)
set(GTSAM_USE_TBB 1) # This will go into config.h set(GTSAM_USE_TBB 1) # This will go into config.h
if ((${TBB_VERSION} VERSION_GREATER "2021.1") OR (${TBB_VERSION} VERSION_EQUAL "2021.1"))
message(FATAL_ERROR "TBB version greater than 2021.1 (oneTBB API) is not yet supported. Use an older version instead.")
endif()
if ((${TBB_VERSION_MAJOR} GREATER 2020) OR (${TBB_VERSION_MAJOR} EQUAL 2020)) if ((${TBB_VERSION_MAJOR} GREATER 2020) OR (${TBB_VERSION_MAJOR} EQUAL 2020))
set(TBB_GREATER_EQUAL_2020 1) set(TBB_GREATER_EQUAL_2020 1)
else() else()
@ -13,12 +19,14 @@ if(TBB_FOUND AND GTSAM_WITH_TBB)
# all definitions and link requisites will go via imported targets: # all definitions and link requisites will go via imported targets:
# tbb & tbbmalloc # tbb & tbbmalloc
list(APPEND GTSAM_ADDITIONAL_LIBRARIES tbb tbbmalloc) list(APPEND GTSAM_ADDITIONAL_LIBRARIES tbb tbbmalloc)
else() else()
set(GTSAM_USE_TBB 0) # This will go into config.h set(GTSAM_USE_TBB 0) # This will go into config.h
endif() endif()
############################################################################### ###############################################################################
# Prohibit Timing build mode in combination with TBB # Prohibit Timing build mode in combination with TBB
if(GTSAM_USE_TBB AND (CMAKE_BUILD_TYPE STREQUAL "Timing")) if(GTSAM_USE_TBB AND (CMAKE_BUILD_TYPE STREQUAL "Timing"))
message(FATAL_ERROR "Timing build mode cannot be used together with TBB. Use a sampling profiler such as Instruments or Intel VTune Amplifier instead.") message(FATAL_ERROR "Timing build mode cannot be used together with TBB. Use a sampling profiler such as Instruments or Intel VTune Amplifier instead.")
endif()
endif() endif()

View File

@ -1,6 +1,57 @@
# Instructions # Instructions
Build all docker images, in order: # Images on Docker Hub
There are 4 images available on https://hub.docker.com/orgs/borglab/repositories:
- `borglab/ubuntu-boost-tbb`: 18.06 Linux (nicknamed `bionic`) base image, with Boost and TBB installed.
- `borglab/ubuntu-gtsam`: GTSAM Release version installed in `/usr/local`.
- `borglab/ubuntu-gtsam-python`: installed GTSAM with python wrapper.
- `borglab/ubuntu-gtsam-python-vnc`: image with GTSAM+python wrapper that will run a VNC server to connect to.
# Using the images
## Just GTSAM
To start the Docker image, execute
```bash
docker run -it borglab/ubuntu-gtsam:bionic
```
after you will find yourself in a bash shell, in the directory `/usr/src/gtsam/build`.
## GTSAM with Python wrapper
To use GTSAM via the python wrapper, similarly execute
```bash
docker run -it borglab/ubuntu-gtsam-python:bionic
```
and then launch `python3`:
```bash
python3
>>> import gtsam
>>> gtsam.Pose2(1,2,3)
(1, 2, 3)
```
## GTSAM with Python wrapper and VNC
First, start the docker image, which will run a VNC server on port 5900:
```bash
docker run -p 5900:5900 borglab/ubuntu-gtsam-python-vnc:bionic
```
Then open a remote VNC X client, for example:
### Linux
```bash
sudo apt-get install tigervnc-viewer
xtigervncviewer :5900
```
### Mac
The Finder's "Connect to Server..." with `vnc://127.0.0.1` does not work, for some reason. Using the free [VNC Viewer](https://www.realvnc.com/en/connect/download/viewer/), enter `0.0.0.0:5900` as the server.
# Re-building the images locally
To build all docker images, in order:
```bash ```bash
(cd ubuntu-boost-tbb && ./build.sh) (cd ubuntu-boost-tbb && ./build.sh)
@ -9,13 +60,4 @@ Build all docker images, in order:
(cd ubuntu-gtsam-python-vnc && ./build.sh) (cd ubuntu-gtsam-python-vnc && ./build.sh)
``` ```
Then launch with: Note: building GTSAM can take a lot of memory because of the heavy templating. It is advisable to give Docker enough resources, e.g., 8GB, to avoid OOM errors while compiling.
docker run -p 5900:5900 dellaert/ubuntu-gtsam-python-vnc:bionic
Then open a remote VNC X client, for example:
sudo apt-get install tigervnc-viewer
xtigervncviewer :5900

View File

@ -1,3 +1,3 @@
# Build command for Docker image # Build command for Docker image
# TODO(dellaert): use docker compose and/or cmake # TODO(dellaert): use docker compose and/or cmake
docker build --no-cache -t dellaert/ubuntu-boost-tbb:bionic . docker build --no-cache -t borglab/ubuntu-boost-tbb:bionic .

View File

@ -1,7 +1,7 @@
# This GTSAM image connects to the host X-server via VNC to provide a Graphical User Interface for interaction. # This GTSAM image connects to the host X-server via VNC to provide a Graphical User Interface for interaction.
# Get the base Ubuntu/GTSAM image from Docker Hub # Get the base Ubuntu/GTSAM image from Docker Hub
FROM dellaert/ubuntu-gtsam-python:bionic FROM borglab/ubuntu-gtsam-python:bionic
# Things needed to get a python GUI # Things needed to get a python GUI
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND noninteractive

View File

@ -1,4 +1,4 @@
# Build command for Docker image # Build command for Docker image
# TODO(dellaert): use docker compose and/or cmake # TODO(dellaert): use docker compose and/or cmake
# Needs to be run in docker/ubuntu-gtsam-python-vnc directory # Needs to be run in docker/ubuntu-gtsam-python-vnc directory
docker build -t dellaert/ubuntu-gtsam-python-vnc:bionic . docker build -t borglab/ubuntu-gtsam-python-vnc:bionic .

View File

@ -2,4 +2,4 @@
docker run -it \ docker run -it \
--workdir="/usr/src/gtsam" \ --workdir="/usr/src/gtsam" \
-p 5900:5900 \ -p 5900:5900 \
dellaert/ubuntu-gtsam-python-vnc:bionic borglab/ubuntu-gtsam-python-vnc:bionic

View File

@ -1,7 +1,7 @@
# GTSAM Ubuntu image with Python wrapper support. # GTSAM Ubuntu image with Python wrapper support.
# Get the base Ubuntu/GTSAM image from Docker Hub # Get the base Ubuntu/GTSAM image from Docker Hub
FROM dellaert/ubuntu-gtsam:bionic FROM borglab/ubuntu-gtsam:bionic
# Install pip # Install pip
RUN apt-get install -y python3-pip python3-dev RUN apt-get install -y python3-pip python3-dev
@ -22,7 +22,9 @@ RUN cmake \
.. ..
# Build again, as ubuntu-gtsam image cleaned # Build again, as ubuntu-gtsam image cleaned
RUN make -j4 install && make clean RUN make -j4 install
RUN make python-install
RUN make clean
# Needed to run python wrapper: # Needed to run python wrapper:
RUN echo 'export PYTHONPATH=/usr/local/python/:$PYTHONPATH' >> /root/.bashrc RUN echo 'export PYTHONPATH=/usr/local/python/:$PYTHONPATH' >> /root/.bashrc

View File

@ -1,3 +1,3 @@
# Build command for Docker image # Build command for Docker image
# TODO(dellaert): use docker compose and/or cmake # TODO(dellaert): use docker compose and/or cmake
docker build --no-cache -t dellaert/ubuntu-gtsam-python:bionic . docker build --no-cache -t borglab/ubuntu-gtsam-python:bionic .

View File

@ -1,7 +1,7 @@
# Ubuntu image with GTSAM installed. Configured with Boost and TBB support. # Ubuntu image with GTSAM installed. Configured with Boost and TBB support.
# Get the base Ubuntu image from Docker Hub # Get the base Ubuntu image from Docker Hub
FROM dellaert/ubuntu-boost-tbb:bionic FROM borglab/ubuntu-boost-tbb:bionic
# Install git # Install git
RUN apt-get update && \ RUN apt-get update && \

View File

@ -1,3 +1,3 @@
# Build command for Docker image # Build command for Docker image
# TODO(dellaert): use docker compose and/or cmake # TODO(dellaert): use docker compose and/or cmake
docker build --no-cache -t dellaert/ubuntu-gtsam:bionic . docker build --no-cache -t borglab/ubuntu-gtsam:bionic .

View File

@ -49,10 +49,7 @@ if(NOT GTSAM_USE_SYSTEM_EIGEN)
endif() endif()
option(GTSAM_BUILD_METIS_EXECUTABLES "Build metis library executables" OFF) # metis: already handled in ROOT/cmake/HandleMetis.cmake
if(GTSAM_SUPPORT_NESTED_DISSECTION)
add_subdirectory(metis)
endif()
add_subdirectory(ceres) add_subdirectory(ceres)

View File

@ -89,7 +89,8 @@ list(APPEND gtsam_srcs "${PROJECT_BINARY_DIR}/config.h" "${PROJECT_BINARY_DIR}/d
install(FILES "${PROJECT_BINARY_DIR}/config.h" "${PROJECT_BINARY_DIR}/dllexport.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gtsam) install(FILES "${PROJECT_BINARY_DIR}/config.h" "${PROJECT_BINARY_DIR}/dllexport.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gtsam)
if(GTSAM_SUPPORT_NESTED_DISSECTION) if(GTSAM_SUPPORT_NESTED_DISSECTION)
list(APPEND GTSAM_ADDITIONAL_LIBRARIES metis-gtsam) # target metis-gtsam-if is defined in both cases: embedded metis or system version:
list(APPEND GTSAM_ADDITIONAL_LIBRARIES metis-gtsam-if)
endif() endif()
# Versions # Versions
@ -155,16 +156,6 @@ target_include_directories(gtsam SYSTEM BEFORE PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/CCOLAMD/Include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/CCOLAMD/Include>
$<INSTALL_INTERFACE:include/gtsam/3rdparty/CCOLAMD> $<INSTALL_INTERFACE:include/gtsam/3rdparty/CCOLAMD>
) )
if(GTSAM_SUPPORT_NESTED_DISSECTION)
target_include_directories(gtsam BEFORE PUBLIC
$<BUILD_INTERFACE:${GTSAM_SOURCE_DIR}/gtsam/3rdparty/metis/include>
$<BUILD_INTERFACE:${GTSAM_SOURCE_DIR}/gtsam/3rdparty/metis/libmetis>
$<BUILD_INTERFACE:${GTSAM_SOURCE_DIR}/gtsam/3rdparty/metis/GKlib>
$<INSTALL_INTERFACE:include/gtsam/3rdparty/metis/>
)
endif()
if(WIN32) # Add 'lib' prefix to static library to avoid filename collision with shared library if(WIN32) # Add 'lib' prefix to static library to avoid filename collision with shared library
if (NOT BUILD_SHARED_LIBS) if (NOT BUILD_SHARED_LIBS)

View File

@ -40,9 +40,13 @@ class GTSAM_EXPORT FourierBasis : public Basis<FourierBasis> {
static Weights CalculateWeights(size_t N, double x) { static Weights CalculateWeights(size_t N, double x) {
Weights b(N); Weights b(N);
b[0] = 1; b[0] = 1;
for (size_t i = 1, n = 1; i < N; i += 2, n++) { for (size_t i = 1, n = 1; i < N; i++) {
if (i % 2 == 1) {
b[i] = cos(n * x); b[i] = cos(n * x);
b[i + 1] = sin(n * x); } else {
b[i] = sin(n * x);
n++;
}
} }
return b; return b;
} }

View File

@ -77,3 +77,6 @@
// Support Metis-based nested dissection // Support Metis-based nested dissection
#cmakedefine GTSAM_TANGENT_PREINTEGRATION #cmakedefine GTSAM_TANGENT_PREINTEGRATION
// Whether to use the system installed Metis instead of the provided one
#cmakedefine GTSAM_USE_SYSTEM_METIS

View File

@ -26,6 +26,12 @@ namespace gtsam {
/// it is now possible to just typedef Point2 to Vector2 /// it is now possible to just typedef Point2 to Vector2
typedef Vector2 Point2; typedef Vector2 Point2;
// Convenience typedef
using Point2Pair = std::pair<Point2, Point2>;
GTSAM_EXPORT std::ostream &operator<<(std::ostream &os, const gtsam::Point2Pair &p);
using Point2Pairs = std::vector<Point2Pair>;
/// Distance of the point from the origin, with Jacobian /// Distance of the point from the origin, with Jacobian
GTSAM_EXPORT double norm2(const Point2& p, OptionalJacobian<1, 2> H = boost::none); GTSAM_EXPORT double norm2(const Point2& p, OptionalJacobian<1, 2> H = boost::none);
@ -34,10 +40,6 @@ GTSAM_EXPORT double distance2(const Point2& p1, const Point2& q,
OptionalJacobian<1, 2> H1 = boost::none, OptionalJacobian<1, 2> H1 = boost::none,
OptionalJacobian<1, 2> H2 = boost::none); OptionalJacobian<1, 2> H2 = boost::none);
// Convenience typedef
typedef std::pair<Point2, Point2> Point2Pair;
GTSAM_EXPORT std::ostream &operator<<(std::ostream &os, const gtsam::Point2Pair &p);
// For MATLAB wrapper // For MATLAB wrapper
typedef std::vector<Point2, Eigen::aligned_allocator<Point2> > Point2Vector; typedef std::vector<Point2, Eigen::aligned_allocator<Point2> > Point2Vector;

View File

@ -32,6 +32,14 @@ class Point2 {
void pickle() const; void pickle() const;
}; };
class Point2Pairs {
Point2Pairs();
size_t size() const;
bool empty() const;
gtsam::Point2Pair at(size_t n) const;
void push_back(const gtsam::Point2Pair& point_pair);
};
// std::vector<gtsam::Point2> // std::vector<gtsam::Point2>
class Point2Vector { class Point2Vector {
// Constructors // Constructors
@ -430,6 +438,8 @@ class Pose2 {
void pickle() const; void pickle() const;
}; };
boost::optional<gtsam::Pose2> align(const gtsam::Point2Pairs& pairs);
#include <gtsam/geometry/Pose3.h> #include <gtsam/geometry/Pose3.h>
class Pose3 { class Pose3 {
// Standard Constructors // Standard Constructors

View File

@ -70,16 +70,23 @@ namespace gtsam {
/// @name Standard Constructors /// @name Standard Constructors
/// @{ /// @{
/** Default constructor */ /// Default constructor
BayesTreeCliqueBase() : problemSize_(1) {} BayesTreeCliqueBase() : problemSize_(1) {}
/** Construct from a conditional, leaving parent and child pointers uninitialized */ /// Construct from a conditional, leaving parent and child pointers
BayesTreeCliqueBase(const sharedConditional& conditional) : conditional_(conditional), problemSize_(1) {} /// uninitialized.
BayesTreeCliqueBase(const sharedConditional& conditional)
: conditional_(conditional), problemSize_(1) {}
/** Shallow copy constructor */ /// Shallow copy constructor.
BayesTreeCliqueBase(const BayesTreeCliqueBase& c) : conditional_(c.conditional_), parent_(c.parent_), children(c.children), problemSize_(c.problemSize_), is_root(c.is_root) {} BayesTreeCliqueBase(const BayesTreeCliqueBase& c)
: conditional_(c.conditional_),
parent_(c.parent_),
children(c.children),
problemSize_(c.problemSize_),
is_root(c.is_root) {}
/** Shallow copy assignment constructor */ /// Shallow copy assignment constructor
BayesTreeCliqueBase& operator=(const BayesTreeCliqueBase& c) { BayesTreeCliqueBase& operator=(const BayesTreeCliqueBase& c) {
conditional_ = c.conditional_; conditional_ = c.conditional_;
parent_ = c.parent_; parent_ = c.parent_;
@ -89,6 +96,9 @@ namespace gtsam {
return *this; return *this;
} }
// Virtual destructor.
virtual ~BayesTreeCliqueBase() {}
/// @} /// @}
/// This stores the Cached separator marginal P(S) /// This stores the Cached separator marginal P(S)
@ -119,7 +129,9 @@ namespace gtsam {
bool equals(const DERIVED& other, double tol = 1e-9) const; bool equals(const DERIVED& other, double tol = 1e-9) const;
/** print this node */ /** print this node */
virtual void print(const std::string& s = "", const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; virtual void print(
const std::string& s = "",
const KeyFormatter& keyFormatter = DefaultKeyFormatter) const;
/// @} /// @}
/// @name Standard Interface /// @name Standard Interface

View File

@ -32,7 +32,7 @@
namespace gtsam { namespace gtsam {
/// Typedef for a function to format a key, i.e. to convert it to a string /// Typedef for a function to format a key, i.e. to convert it to a string
typedef std::function<std::string(Key)> KeyFormatter; using KeyFormatter = std::function<std::string(Key)>;
// Helper function for DefaultKeyFormatter // Helper function for DefaultKeyFormatter
GTSAM_EXPORT std::string _defaultKeyFormatter(Key key); GTSAM_EXPORT std::string _defaultKeyFormatter(Key key);
@ -83,28 +83,32 @@ class key_formatter {
}; };
/// Define collection type once and for all - also used in wrappers /// Define collection type once and for all - also used in wrappers
typedef FastVector<Key> KeyVector; using KeyVector = FastVector<Key>;
// TODO(frank): Nothing fast about these :-( // TODO(frank): Nothing fast about these :-(
typedef FastList<Key> KeyList; using KeyList = FastList<Key>;
typedef FastSet<Key> KeySet; using KeySet = FastSet<Key>;
typedef FastMap<Key, int> KeyGroupMap; using KeyGroupMap = FastMap<Key, int>;
/// Utility function to print one key with optional prefix /// Utility function to print one key with optional prefix
GTSAM_EXPORT void PrintKey(Key key, const std::string& s = "", GTSAM_EXPORT void PrintKey(
const KeyFormatter& keyFormatter = DefaultKeyFormatter); Key key, const std::string &s = "",
const KeyFormatter &keyFormatter = DefaultKeyFormatter);
/// Utility function to print sets of keys with optional prefix /// Utility function to print sets of keys with optional prefix
GTSAM_EXPORT void PrintKeyList(const KeyList& keys, const std::string& s = "", GTSAM_EXPORT void PrintKeyList(
const KeyFormatter& keyFormatter = DefaultKeyFormatter); const KeyList &keys, const std::string &s = "",
const KeyFormatter &keyFormatter = DefaultKeyFormatter);
/// Utility function to print sets of keys with optional prefix /// Utility function to print sets of keys with optional prefix
GTSAM_EXPORT void PrintKeyVector(const KeyVector& keys, const std::string& s = GTSAM_EXPORT void PrintKeyVector(
"", const KeyFormatter& keyFormatter = DefaultKeyFormatter); const KeyVector &keys, const std::string &s = "",
const KeyFormatter &keyFormatter = DefaultKeyFormatter);
/// Utility function to print sets of keys with optional prefix /// Utility function to print sets of keys with optional prefix
GTSAM_EXPORT void PrintKeySet(const KeySet& keys, const std::string& s = "", GTSAM_EXPORT void PrintKeySet(
const KeyFormatter& keyFormatter = DefaultKeyFormatter); const KeySet &keys, const std::string &s = "",
const KeyFormatter &keyFormatter = DefaultKeyFormatter);
// Define Key to be Testable by specializing gtsam::traits // Define Key to be Testable by specializing gtsam::traits
template<typename T> struct traits; template<typename T> struct traits;

View File

@ -25,8 +25,12 @@
#include <gtsam/3rdparty/CCOLAMD/Include/ccolamd.h> #include <gtsam/3rdparty/CCOLAMD/Include/ccolamd.h>
#ifdef GTSAM_SUPPORT_NESTED_DISSECTION #ifdef GTSAM_SUPPORT_NESTED_DISSECTION
#ifdef GTSAM_USE_SYSTEM_METIS
#include <metis.h>
#else
#include <gtsam/3rdparty/metis/include/metis.h> #include <gtsam/3rdparty/metis/include/metis.h>
#endif #endif
#endif
using namespace std; using namespace std;

View File

@ -16,9 +16,9 @@ virtual class Base {
}; };
virtual class Gaussian : gtsam::noiseModel::Base { virtual class Gaussian : gtsam::noiseModel::Base {
static gtsam::noiseModel::Gaussian* Information(Matrix R); static gtsam::noiseModel::Gaussian* Information(Matrix R, bool smart = true);
static gtsam::noiseModel::Gaussian* SqrtInformation(Matrix R); static gtsam::noiseModel::Gaussian* SqrtInformation(Matrix R, bool smart = true);
static gtsam::noiseModel::Gaussian* Covariance(Matrix R); static gtsam::noiseModel::Gaussian* Covariance(Matrix R, bool smart = true);
bool equals(gtsam::noiseModel::Base& expected, double tol); bool equals(gtsam::noiseModel::Base& expected, double tol);
@ -37,9 +37,9 @@ virtual class Gaussian : gtsam::noiseModel::Base {
}; };
virtual class Diagonal : gtsam::noiseModel::Gaussian { virtual class Diagonal : gtsam::noiseModel::Gaussian {
static gtsam::noiseModel::Diagonal* Sigmas(Vector sigmas); static gtsam::noiseModel::Diagonal* Sigmas(Vector sigmas, bool smart = true);
static gtsam::noiseModel::Diagonal* Variances(Vector variances); static gtsam::noiseModel::Diagonal* Variances(Vector variances, bool smart = true);
static gtsam::noiseModel::Diagonal* Precisions(Vector precisions); static gtsam::noiseModel::Diagonal* Precisions(Vector precisions, bool smart = true);
Matrix R() const; Matrix R() const;
// access to noise model // access to noise model
@ -69,9 +69,9 @@ virtual class Constrained : gtsam::noiseModel::Diagonal {
}; };
virtual class Isotropic : gtsam::noiseModel::Diagonal { virtual class Isotropic : gtsam::noiseModel::Diagonal {
static gtsam::noiseModel::Isotropic* Sigma(size_t dim, double sigma); static gtsam::noiseModel::Isotropic* Sigma(size_t dim, double sigma, bool smart = true);
static gtsam::noiseModel::Isotropic* Variance(size_t dim, double varianace); static gtsam::noiseModel::Isotropic* Variance(size_t dim, double varianace, bool smart = true);
static gtsam::noiseModel::Isotropic* Precision(size_t dim, double precision); static gtsam::noiseModel::Isotropic* Precision(size_t dim, double precision, bool smart = true);
// access to noise model // access to noise model
double sigma() const; double sigma() const;
@ -289,6 +289,13 @@ virtual class JacobianFactor : gtsam::GaussianFactor {
JacobianFactor(size_t i1, Matrix A1, size_t i2, Matrix A2, size_t i3, Matrix A3, JacobianFactor(size_t i1, Matrix A1, size_t i2, Matrix A2, size_t i3, Matrix A3,
Vector b, const gtsam::noiseModel::Diagonal* model); Vector b, const gtsam::noiseModel::Diagonal* model);
JacobianFactor(const gtsam::GaussianFactorGraph& graph); JacobianFactor(const gtsam::GaussianFactorGraph& graph);
JacobianFactor(const gtsam::GaussianFactorGraph& graph,
const gtsam::VariableSlots& p_variableSlots);
JacobianFactor(const gtsam::GaussianFactorGraph& graph,
const gtsam::Ordering& ordering);
JacobianFactor(const gtsam::GaussianFactorGraph& graph,
const gtsam::Ordering& ordering,
const gtsam::VariableSlots& p_variableSlots);
//Testable //Testable
void print(string s = "", const gtsam::KeyFormatter& keyFormatter = void print(string s = "", const gtsam::KeyFormatter& keyFormatter =

View File

@ -819,7 +819,6 @@ struct ImuFactorMergeTest {
loop_(Vector3(0, -kAngularVelocity, 0), Vector3(kVelocity, 0, 0)) { loop_(Vector3(0, -kAngularVelocity, 0), Vector3(kVelocity, 0, 0)) {
// arbitrary noise values // arbitrary noise values
p_->gyroscopeCovariance = I_3x3 * 0.01; p_->gyroscopeCovariance = I_3x3 * 0.01;
p_->accelerometerCovariance = I_3x3 * 0.02;
p_->accelerometerCovariance = I_3x3 * 0.03; p_->accelerometerCovariance = I_3x3 * 0.03;
} }

View File

@ -75,12 +75,15 @@ size_t Z(size_t j);
} // namespace symbol_shorthand } // namespace symbol_shorthand
// Default keyformatter // Default keyformatter
void PrintKeyList(const gtsam::KeyList& keys); void PrintKeyList(
void PrintKeyList(const gtsam::KeyList& keys, string s); const gtsam::KeyList& keys, const string& s = "",
void PrintKeyVector(const gtsam::KeyVector& keys); const gtsam::KeyFormatter& keyFormatter = gtsam::DefaultKeyFormatter);
void PrintKeyVector(const gtsam::KeyVector& keys, string s); void PrintKeyVector(
void PrintKeySet(const gtsam::KeySet& keys); const gtsam::KeyVector& keys, const string& s = "",
void PrintKeySet(const gtsam::KeySet& keys, string s); const gtsam::KeyFormatter& keyFormatter = gtsam::DefaultKeyFormatter);
void PrintKeySet(
const gtsam::KeySet& keys, const string& s = "",
const gtsam::KeyFormatter& keyFormatter = gtsam::DefaultKeyFormatter);
#include <gtsam/inference/LabeledSymbol.h> #include <gtsam/inference/LabeledSymbol.h>
class LabeledSymbol { class LabeledSymbol {
@ -527,7 +530,14 @@ template<PARAMS>
virtual class GncParams { virtual class GncParams {
GncParams(const PARAMS& baseOptimizerParams); GncParams(const PARAMS& baseOptimizerParams);
GncParams(); GncParams();
void setVerbosityGNC(const This::Verbosity value);
void print(const string& str) const; void print(const string& str) const;
enum Verbosity {
SILENT,
SUMMARY,
VALUES
};
}; };
typedef gtsam::GncParams<gtsam::GaussNewtonParams> GncGaussNewtonParams; typedef gtsam::GncParams<gtsam::GaussNewtonParams> GncGaussNewtonParams;

View File

@ -20,6 +20,8 @@
#include "FindSeparator.h" #include "FindSeparator.h"
#ifndef GTSAM_USE_SYSTEM_METIS
extern "C" { extern "C" {
#include <metis.h> #include <metis.h>
#include "metislib.h" #include "metislib.h"
@ -564,3 +566,5 @@ namespace gtsam { namespace partition {
} }
}} //namespace }} //namespace
#endif

View File

@ -20,6 +20,8 @@ using namespace std;
using namespace gtsam; using namespace gtsam;
using namespace gtsam::partition; using namespace gtsam::partition;
#ifndef GTSAM_USE_SYSTEM_METIS
/* ************************************************************************* */ /* ************************************************************************* */
// x0 - x1 - x2 // x0 - x1 - x2
// l3 l4 // l3 l4
@ -227,6 +229,8 @@ TEST ( Partition, findSeparator3_with_reduced_camera )
LONGS_EQUAL(2, partitionTable[28]); LONGS_EQUAL(2, partitionTable[28]);
} }
#endif
/* ************************************************************************* */ /* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr);} int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
/* ************************************************************************* */ /* ************************************************************************* */

View File

@ -43,6 +43,7 @@ set(ignore
gtsam::BetweenFactorPose2s gtsam::BetweenFactorPose2s
gtsam::BetweenFactorPose3s gtsam::BetweenFactorPose3s
gtsam::Point2Vector gtsam::Point2Vector
gtsam::Point2Pairs
gtsam::Point3Pairs gtsam::Point3Pairs
gtsam::Pose3Pairs gtsam::Pose3Pairs
gtsam::Pose3Vector gtsam::Pose3Vector
@ -166,5 +167,6 @@ add_custom_target(
COMMAND COMMAND
${CMAKE_COMMAND} -E env # add package to python path so no need to install ${CMAKE_COMMAND} -E env # add package to python path so no need to install
"PYTHONPATH=${GTSAM_PYTHON_BUILD_DIRECTORY}/$ENV{PYTHONPATH}" "PYTHONPATH=${GTSAM_PYTHON_BUILD_DIRECTORY}/$ENV{PYTHONPATH}"
${PYTHON_EXECUTABLE} -m unittest discover -s "${GTSAM_PYTHON_BUILD_DIRECTORY}/gtsam/tests" ${PYTHON_EXECUTABLE} -m unittest discover -v -s .
DEPENDS ${GTSAM_PYTHON_DEPENDENCIES}) DEPENDS ${GTSAM_PYTHON_DEPENDENCIES}
WORKING_DIRECTORY "${GTSAM_PYTHON_BUILD_DIRECTORY}/gtsam/tests")

View File

@ -10,28 +10,30 @@ A script validating and demonstrating the ImuFactor inference.
Author: Frank Dellaert, Varun Agrawal Author: Frank Dellaert, Varun Agrawal
""" """
# pylint: disable=no-name-in-module,unused-import,arguments-differ
from __future__ import print_function from __future__ import print_function
import argparse import argparse
import math import math
import gtsam
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import gtsam
from gtsam.symbol_shorthand import B, V, X from gtsam.symbol_shorthand import B, V, X
from gtsam.utils.plot import plot_pose3 from gtsam.utils.plot import plot_pose3
from mpl_toolkits.mplot3d import Axes3D
from PreintegrationExample import POSES_FIG, PreintegrationExample from PreintegrationExample import POSES_FIG, PreintegrationExample
BIAS_KEY = B(0) BIAS_KEY = B(0)
np.set_printoptions(precision=3, suppress=True) np.set_printoptions(precision=3, suppress=True)
class ImuFactorExample(PreintegrationExample): class ImuFactorExample(PreintegrationExample):
"""Class to run example of the Imu Factor."""
def __init__(self, twist_scenario="sick_twist"): def __init__(self, twist_scenario="sick_twist"):
self.velocity = np.array([2, 0, 0]) self.velocity = np.array([2, 0, 0])
self.priorNoise = gtsam.noiseModel.Isotropic.Sigma(6, 0.1) self.priorNoise = gtsam.noiseModel.Isotropic.Sigma(6, 0.1)
@ -42,9 +44,8 @@ class ImuFactorExample(PreintegrationExample):
zero_twist=(np.zeros(3), np.zeros(3)), zero_twist=(np.zeros(3), np.zeros(3)),
forward_twist=(np.zeros(3), self.velocity), forward_twist=(np.zeros(3), self.velocity),
loop_twist=(np.array([0, -math.radians(30), 0]), self.velocity), loop_twist=(np.array([0, -math.radians(30), 0]), self.velocity),
sick_twist=(np.array([math.radians(30), -math.radians(30), 0]), sick_twist=(np.array([math.radians(30), -math.radians(30),
self.velocity) 0]), self.velocity))
)
accBias = np.array([-0.3, 0.1, 0.2]) accBias = np.array([-0.3, 0.1, 0.2])
gyroBias = np.array([0.1, 0.3, -0.1]) gyroBias = np.array([0.1, 0.3, -0.1])
@ -55,19 +56,44 @@ class ImuFactorExample(PreintegrationExample):
bias, dt) bias, dt)
def addPrior(self, i, graph): def addPrior(self, i, graph):
"""Add priors at time step `i`."""
state = self.scenario.navState(i) state = self.scenario.navState(i)
graph.push_back(gtsam.PriorFactorPose3( graph.push_back(
X(i), state.pose(), self.priorNoise)) gtsam.PriorFactorPose3(X(i), state.pose(), self.priorNoise))
graph.push_back(gtsam.PriorFactorVector( graph.push_back(
V(i), state.velocity(), self.velNoise)) gtsam.PriorFactorVector(V(i), state.velocity(), self.velNoise))
def optimize(self, graph, initial):
"""Optimize using Levenberg-Marquardt optimization."""
params = gtsam.LevenbergMarquardtParams()
params.setVerbosityLM("SUMMARY")
optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial, params)
result = optimizer.optimize()
return result
def plot(self, result):
"""Plot resulting poses."""
i = 0
while result.exists(X(i)):
pose_i = result.atPose3(X(i))
plot_pose3(POSES_FIG + 1, pose_i, 1)
i += 1
plt.title("Estimated Trajectory")
gtsam.utils.plot.set_axes_equal(POSES_FIG + 1)
print("Bias Values", result.atConstantBias(BIAS_KEY))
plt.ioff()
plt.show()
def run(self, T=12, compute_covariances=False, verbose=True): def run(self, T=12, compute_covariances=False, verbose=True):
"""Main runner."""
graph = gtsam.NonlinearFactorGraph() graph = gtsam.NonlinearFactorGraph()
# initialize data structure for pre-integrated IMU measurements # initialize data structure for pre-integrated IMU measurements
pim = gtsam.PreintegratedImuMeasurements(self.params, self.actualBias) pim = gtsam.PreintegratedImuMeasurements(self.params, self.actualBias)
T = 12
num_poses = T # assumes 1 factor per second num_poses = T # assumes 1 factor per second
initial = gtsam.Values() initial = gtsam.Values()
initial.insert(BIAS_KEY, self.actualBias) initial.insert(BIAS_KEY, self.actualBias)
@ -91,14 +117,13 @@ class ImuFactorExample(PreintegrationExample):
if k % 10 == 0: if k % 10 == 0:
self.plotImu(t, measuredOmega, measuredAcc) self.plotImu(t, measuredOmega, measuredAcc)
if (k+1) % int(1 / self.dt) == 0: if (k + 1) % int(1 / self.dt) == 0:
# Plot every second # Plot every second
self.plotGroundTruthPose(t, scale=1) self.plotGroundTruthPose(t, scale=1)
plt.title("Ground Truth Trajectory") plt.title("Ground Truth Trajectory")
# create IMU factor every second # create IMU factor every second
factor = gtsam.ImuFactor(X(i), V(i), factor = gtsam.ImuFactor(X(i), V(i), X(i + 1), V(i + 1),
X(i + 1), V(i + 1),
BIAS_KEY, pim) BIAS_KEY, pim)
graph.push_back(factor) graph.push_back(factor)
@ -108,34 +133,34 @@ class ImuFactorExample(PreintegrationExample):
pim.resetIntegration() pim.resetIntegration()
rotationNoise = gtsam.Rot3.Expmap(np.random.randn(3)*0.1) rotationNoise = gtsam.Rot3.Expmap(np.random.randn(3) * 0.1)
translationNoise = gtsam.Point3(*np.random.randn(3)*1) translationNoise = gtsam.Point3(*np.random.randn(3) * 1)
poseNoise = gtsam.Pose3(rotationNoise, translationNoise) poseNoise = gtsam.Pose3(rotationNoise, translationNoise)
actual_state_i = self.scenario.navState(t + self.dt) actual_state_i = self.scenario.navState(t + self.dt)
print("Actual state at {0}:\n{1}".format( print("Actual state at {0}:\n{1}".format(
t+self.dt, actual_state_i)) t + self.dt, actual_state_i))
noisy_state_i = gtsam.NavState( noisy_state_i = gtsam.NavState(
actual_state_i.pose().compose(poseNoise), actual_state_i.pose().compose(poseNoise),
actual_state_i.velocity() + np.random.randn(3)*0.1) actual_state_i.velocity() + np.random.randn(3) * 0.1)
initial.insert(X(i+1), noisy_state_i.pose()) initial.insert(X(i + 1), noisy_state_i.pose())
initial.insert(V(i+1), noisy_state_i.velocity()) initial.insert(V(i + 1), noisy_state_i.velocity())
i += 1 i += 1
# add priors on end # add priors on end
self.addPrior(num_poses - 1, graph) self.addPrior(num_poses - 1, graph)
initial.print_("Initial values:") initial.print("Initial values:")
# optimize using Levenberg-Marquardt optimization result = self.optimize(graph, initial)
params = gtsam.LevenbergMarquardtParams()
params.setVerbosityLM("SUMMARY")
optimizer = gtsam.LevenbergMarquardtOptimizer(graph, initial, params)
result = optimizer.optimize()
result.print_("Optimized values:") result.print("Optimized values:")
print("------------------")
print(graph.error(initial))
print(graph.error(result))
print("------------------")
if compute_covariances: if compute_covariances:
# Calculate and print marginal covariances # Calculate and print marginal covariances
@ -148,33 +173,26 @@ class ImuFactorExample(PreintegrationExample):
print("Covariance on vel {}:\n{}\n".format( print("Covariance on vel {}:\n{}\n".format(
i, marginals.marginalCovariance(V(i)))) i, marginals.marginalCovariance(V(i))))
# Plot resulting poses self.plot(result)
i = 0
while result.exists(X(i)):
pose_i = result.atPose3(X(i))
plot_pose3(POSES_FIG+1, pose_i, 1)
i += 1
plt.title("Estimated Trajectory")
gtsam.utils.plot.set_axes_equal(POSES_FIG+1)
print("Bias Values", result.atConstantBias(BIAS_KEY))
plt.ioff()
plt.show()
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser("ImuFactorExample.py") parser = argparse.ArgumentParser("ImuFactorExample.py")
parser.add_argument("--twist_scenario", parser.add_argument("--twist_scenario",
default="sick_twist", default="sick_twist",
choices=("zero_twist", "forward_twist", "loop_twist", "sick_twist")) choices=("zero_twist", "forward_twist", "loop_twist",
parser.add_argument("--time", "-T", default=12, "sick_twist"))
type=int, help="Total time in seconds") parser.add_argument("--time",
"-T",
default=12,
type=int,
help="Total time in seconds")
parser.add_argument("--compute_covariances", parser.add_argument("--compute_covariances",
default=False, action='store_true') default=False,
action='store_true')
parser.add_argument("--verbose", default=False, action='store_true') parser.add_argument("--verbose", default=False, action='store_true')
args = parser.parse_args() args = parser.parse_args()
ImuFactorExample(args.twist_scenario).run( ImuFactorExample(args.twist_scenario).run(args.time,
args.time, args.compute_covariances, args.verbose) args.compute_covariances,
args.verbose)

View File

@ -1,7 +1,7 @@
/** /**
* @file gtsam.cpp * @file {module_name}.cpp
* @brief The auto-generated wrapper C++ source code. * @brief The auto-generated wrapper C++ source code.
* @author Duy-Nguyen Ta, Fan Jiang, Matthew Sklar * @author Duy-Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal
* @date Aug. 18, 2020 * @date Aug. 18, 2020
* *
* ** THIS FILE IS AUTO-GENERATED, DO NOT MODIFY! ** * ** THIS FILE IS AUTO-GENERATED, DO NOT MODIFY! **

View File

@ -10,3 +10,5 @@
* Without this they will be automatically converted to a Python object, and all * Without this they will be automatically converted to a Python object, and all
* mutations on Python side will not be reflected on C++. * mutations on Python side will not be reflected on C++.
*/ */
#include <pybind11/stl.h>

View File

@ -10,9 +10,18 @@
* Without this they will be automatically converted to a Python object, and all * Without this they will be automatically converted to a Python object, and all
* mutations on Python side will not be reflected on C++. * mutations on Python side will not be reflected on C++.
*/ */
#include <pybind11/stl.h>
// Support for binding boost::optional types in C++11.
// https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
namespace pybind11 { namespace detail {
template <typename T>
struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {};
}}
PYBIND11_MAKE_OPAQUE( PYBIND11_MAKE_OPAQUE(
std::vector<gtsam::Point2, Eigen::aligned_allocator<gtsam::Point2>>); std::vector<gtsam::Point2, Eigen::aligned_allocator<gtsam::Point2>>);
PYBIND11_MAKE_OPAQUE(gtsam::Point2Pairs);
PYBIND11_MAKE_OPAQUE(gtsam::Point3Pairs); PYBIND11_MAKE_OPAQUE(gtsam::Point3Pairs);
PYBIND11_MAKE_OPAQUE(gtsam::Pose3Pairs); PYBIND11_MAKE_OPAQUE(gtsam::Pose3Pairs);
PYBIND11_MAKE_OPAQUE(std::vector<gtsam::Pose3>); PYBIND11_MAKE_OPAQUE(std::vector<gtsam::Pose3>);

View File

@ -14,6 +14,7 @@
py::bind_vector< py::bind_vector<
std::vector<gtsam::Point2, Eigen::aligned_allocator<gtsam::Point2>>>( std::vector<gtsam::Point2, Eigen::aligned_allocator<gtsam::Point2>>>(
m_, "Point2Vector"); m_, "Point2Vector");
py::bind_vector<std::vector<gtsam::Point2Pair>>(m_, "Point2Pairs");
py::bind_vector<std::vector<gtsam::Point3Pair>>(m_, "Point3Pairs"); py::bind_vector<std::vector<gtsam::Point3Pair>>(m_, "Point3Pairs");
py::bind_vector<std::vector<gtsam::Pose3Pair>>(m_, "Pose3Pairs"); py::bind_vector<std::vector<gtsam::Pose3Pair>>(m_, "Pose3Pairs");
py::bind_vector<std::vector<gtsam::Pose3>>(m_, "Pose3Vector"); py::bind_vector<std::vector<gtsam::Pose3>>(m_, "Pose3Vector");

View File

@ -6,27 +6,64 @@ All Rights Reserved
See LICENSE for the license information See LICENSE for the license information
Pose2 unit tests. Pose2 unit tests.
Author: Frank Dellaert & Duy Nguyen Ta (Python) Author: Frank Dellaert & Duy Nguyen Ta & John Lambert
""" """
import unittest import unittest
import numpy as np import numpy as np
import gtsam import gtsam
from gtsam import Pose2 from gtsam import Point2, Point2Pairs, Pose2
from gtsam.utils.test_case import GtsamTestCase from gtsam.utils.test_case import GtsamTestCase
class TestPose2(GtsamTestCase): class TestPose2(GtsamTestCase):
"""Test selected Pose2 methods.""" """Test selected Pose2 methods."""
def test_adjoint(self) -> None:
def test_adjoint(self):
"""Test adjoint method.""" """Test adjoint method."""
xi = np.array([1, 2, 3]) xi = np.array([1, 2, 3])
expected = np.dot(Pose2.adjointMap_(xi), xi) expected = np.dot(Pose2.adjointMap_(xi), xi)
actual = Pose2.adjoint_(xi, xi) actual = Pose2.adjoint_(xi, xi)
np.testing.assert_array_equal(actual, expected) np.testing.assert_array_equal(actual, expected)
def test_align(self) -> None:
"""Ensure estimation of the Pose2 element to align two 2d point clouds succeeds.
Two point clouds represent horseshoe-shapes of the same size, just rotated and translated:
| X---X
| |
| X---X
------------------
|
|
O | O
| | |
O---O
"""
pts_a = [
Point2(3, 1),
Point2(1, 1),
Point2(1, 3),
Point2(3, 3),
]
pts_b = [
Point2(1, -3),
Point2(1, -5),
Point2(-1, -5),
Point2(-1, -3),
]
# fmt: on
ab_pairs = Point2Pairs(list(zip(pts_a, pts_b)))
bTa = gtsam.align(ab_pairs)
aTb = bTa.inverse()
assert aTb is not None
for pt_a, pt_b in zip(pts_a, pts_b):
pt_a_ = aTb.transformFrom(pt_b)
assert np.allclose(pt_a, pt_a_)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -0,0 +1,96 @@
"""
GTSAM Copyright 2010-2019, Georgia Tech Research Corporation,
Atlanta, Georgia 30332-0415
All Rights Reserved
See LICENSE for the license information
Basis unit tests.
Author: Frank Dellaert & Gerry Chen (Python)
"""
import unittest
import numpy as np
import gtsam
from gtsam.utils.test_case import GtsamTestCase
from gtsam.symbol_shorthand import B
class TestBasis(GtsamTestCase):
"""
Tests FitBasis python binding for FourierBasis, Chebyshev1Basis, Chebyshev2Basis, and Chebyshev2.
It tests FitBasis by fitting to a ground-truth function that can be represented exactly in
the basis, then checking that the regression (fit result) matches the function. For the
Chebyshev bases, the line y=x is used to generate the data while for Fourier, 0.7*cos(x) is
used.
"""
def setUp(self):
self.N = 2
self.x = [0., 0.5, 0.75]
self.interpx = np.linspace(0., 1., 10)
self.noise = gtsam.noiseModel.Unit.Create(1)
def evaluate(self, basis, fitparams, x):
"""
Until wrapper for Basis functors are ready,
this is how to evaluate a basis function.
"""
return basis.WeightMatrix(self.N, x) @ fitparams
def fit_basis_helper(self, fitter, basis, f=lambda x: x):
"""Helper method to fit data to a specified fitter using a specified basis."""
data = {x: f(x) for x in self.x}
fit = fitter(data, self.noise, self.N)
coeff = fit.parameters()
interpy = self.evaluate(basis, coeff, self.interpx)
return interpy
def test_fit_basis_fourier(self):
"""Fit a Fourier basis."""
f = lambda x: 0.7 * np.cos(x)
interpy = self.fit_basis_helper(gtsam.FitBasisFourierBasis,
gtsam.FourierBasis, f)
# test a basis by checking that the fit result matches the function at x-values interpx.
np.testing.assert_almost_equal(interpy,
np.array([f(x) for x in self.interpx]),
decimal=7)
def test_fit_basis_chebyshev1basis(self):
"""Fit a Chebyshev1 basis."""
f = lambda x: x
interpy = self.fit_basis_helper(gtsam.FitBasisChebyshev1Basis,
gtsam.Chebyshev1Basis, f)
# test a basis by checking that the fit result matches the function at x-values interpx.
np.testing.assert_almost_equal(interpy,
np.array([f(x) for x in self.interpx]),
decimal=7)
def test_fit_basis_chebyshev2basis(self):
"""Fit a Chebyshev2 basis."""
f = lambda x: x
interpy = self.fit_basis_helper(gtsam.FitBasisChebyshev2Basis,
gtsam.Chebyshev2Basis)
# test a basis by checking that the fit result matches the function at x-values interpx.
np.testing.assert_almost_equal(interpy,
np.array([f(x) for x in self.interpx]),
decimal=7)
def test_fit_basis_chebyshev2(self):
"""Fit a Chebyshev2 pseudospectral basis."""
f = lambda x: x
interpy = self.fit_basis_helper(gtsam.FitBasisChebyshev2,
gtsam.Chebyshev2)
# test a basis by checking that the fit result matches the function at x-values interpx.
np.testing.assert_almost_equal(interpy,
np.array([f(x) for x in self.interpx]),
decimal=7)
if __name__ == "__main__":
unittest.main()

View File

@ -23,7 +23,10 @@ def set_axes_equal(fignum: int) -> None:
fignum: An integer representing the figure number for Matplotlib. fignum: An integer representing the figure number for Matplotlib.
""" """
fig = plt.figure(fignum) fig = plt.figure(fignum)
ax = fig.gca(projection='3d') if not fig.axes:
ax = fig.add_subplot(projection='3d')
else:
ax = fig.axes[0]
limits = np.array([ limits = np.array([
ax.get_xlim3d(), ax.get_xlim3d(),
@ -339,7 +342,11 @@ def plot_pose3(
""" """
# get figure object # get figure object
fig = plt.figure(fignum) fig = plt.figure(fignum)
axes = fig.gca(projection='3d') if not fig.axes:
axes = fig.add_subplot(projection='3d')
else:
axes = fig.axes[0]
plot_pose3_on_axes(axes, pose, P=P, axis_length=axis_length) plot_pose3_on_axes(axes, pose, P=P, axis_length=axis_length)
axes.set_xlabel(axis_labels[0]) axes.set_xlabel(axis_labels[0])

View File

@ -119,24 +119,27 @@ class Constructor:
Can have 0 or more arguments. Can have 0 or more arguments.
""" """
rule = ( rule = (
IDENT("name") # Optional(Template.rule("template")) #
+ IDENT("name") #
+ LPAREN # + LPAREN #
+ ArgumentList.rule("args_list") # + ArgumentList.rule("args_list") #
+ RPAREN # + RPAREN #
+ SEMI_COLON # BR + SEMI_COLON # BR
).setParseAction(lambda t: Constructor(t.name, t.args_list)) ).setParseAction(lambda t: Constructor(t.name, t.args_list, t.template))
def __init__(self, def __init__(self,
name: str, name: str,
args: ArgumentList, args: ArgumentList,
template: Union[Template, Any],
parent: Union["Class", Any] = ''): parent: Union["Class", Any] = ''):
self.name = name self.name = name
self.args = args self.args = args
self.template = template
self.parent = parent self.parent = parent
def __repr__(self) -> str: def __repr__(self) -> str:
return "Constructor: {}".format(self.name) return "Constructor: {}{}".format(self.name, self.args)
class Operator: class Operator:
@ -260,17 +263,9 @@ class Class:
+ RBRACE # + RBRACE #
+ SEMI_COLON # BR + SEMI_COLON # BR
).setParseAction(lambda t: Class( ).setParseAction(lambda t: Class(
t.template, t.template, t.is_virtual, t.name, t.parent_class, t.members.ctors, t.
t.is_virtual, members.methods, t.members.static_methods, t.members.properties, t.
t.name, members.operators, t.members.enums))
t.parent_class,
t.members.ctors,
t.members.methods,
t.members.static_methods,
t.members.properties,
t.members.operators,
t.members.enums
))
def __init__( def __init__(
self, self,

View File

@ -81,7 +81,7 @@ class ArgumentList:
return ArgumentList([]) return ArgumentList([])
def __repr__(self) -> str: def __repr__(self) -> str:
return self.args_list.__repr__() return repr(tuple(self.args_list))
def __len__(self) -> int: def __len__(self) -> int:
return len(self.args_list) return len(self.args_list)

View File

@ -41,6 +41,8 @@ def instantiate_type(ctype: parser.Type,
str_arg_typename = str(ctype.typename) str_arg_typename = str(ctype.typename)
# Instantiate templates which have enumerated instantiations in the template.
# E.g. `template<T={double}>`.
if str_arg_typename in template_typenames: if str_arg_typename in template_typenames:
idx = template_typenames.index(str_arg_typename) idx = template_typenames.index(str_arg_typename)
return parser.Type( return parser.Type(
@ -51,14 +53,15 @@ def instantiate_type(ctype: parser.Type,
is_ref=ctype.is_ref, is_ref=ctype.is_ref,
is_basic=ctype.is_basic, is_basic=ctype.is_basic,
) )
# If a method has the keyword `This`, we replace it with the (instantiated) class.
elif str_arg_typename == 'This': elif str_arg_typename == 'This':
# Check if the class is template instantiated
# so we can replace it with the instantiated version.
if instantiated_class: if instantiated_class:
name = instantiated_class.original.name name = instantiated_class.original.name
namespaces_name = instantiated_class.namespaces() namespaces_name = instantiated_class.namespaces()
namespaces_name.append(name) namespaces_name.append(name)
# print("INST: {}, {}, CPP: {}, CLS: {}".format(
# ctype, instantiations, cpp_typename, instantiated_class.instantiations
# ), file=sys.stderr)
cpp_typename = parser.Typename( cpp_typename = parser.Typename(
namespaces_name, namespaces_name,
instantiations=instantiated_class.instantiations) instantiations=instantiated_class.instantiations)
@ -71,6 +74,14 @@ def instantiate_type(ctype: parser.Type,
is_ref=ctype.is_ref, is_ref=ctype.is_ref,
is_basic=ctype.is_basic, is_basic=ctype.is_basic,
) )
# Case when 'This' is present in the type namespace, e.g `This::Subclass`.
elif 'This' in str_arg_typename:
# Simply get the index of `This` in the namespace and replace it with the instantiated name.
namespace_idx = ctype.typename.namespaces.index('This')
ctype.typename.namespaces[namespace_idx] = cpp_typename.name
return ctype
else: else:
return ctype return ctype
@ -368,21 +379,47 @@ class InstantiatedClass(parser.Class):
""" """
instantiated_ctors = [] instantiated_ctors = []
for ctor in self.original.ctors: def instantiate(instantiated_ctors, ctor, typenames, instantiations):
instantiated_args = instantiate_args_list( instantiated_args = instantiate_args_list(
ctor.args.list(), ctor.args.list(),
typenames, typenames,
self.instantiations, instantiations,
self.cpp_typename(), self.cpp_typename(),
) )
instantiated_ctors.append( instantiated_ctors.append(
parser.Constructor( parser.Constructor(
name=self.name, name=self.name,
args=parser.ArgumentList(instantiated_args), args=parser.ArgumentList(instantiated_args),
template=self.original.template,
parent=self, parent=self,
)) ))
return instantiated_ctors return instantiated_ctors
for ctor in self.original.ctors:
# Add constructor templates to the typenames and instantiations
if isinstance(ctor.template, parser.template.Template):
typenames.extend(ctor.template.typenames)
# Get all combinations of template args
for instantiations in itertools.product(
*ctor.template.instantiations):
instantiations = self.instantiations + list(instantiations)
instantiated_ctors = instantiate(
instantiated_ctors,
ctor,
typenames=typenames,
instantiations=instantiations)
else:
# If no constructor level templates, just use the class templates
instantiated_ctors = instantiate(
instantiated_ctors,
ctor,
typenames=typenames,
instantiations=self.instantiations)
return instantiated_ctors
def instantiate_static_methods(self, typenames): def instantiate_static_methods(self, typenames):
""" """
Instantiate static methods in the class. Instantiate static methods in the class.

View File

@ -15,9 +15,9 @@ classdef MyFactorPosePoint2 < handle
function obj = MyFactorPosePoint2(varargin) function obj = MyFactorPosePoint2(varargin)
if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682) if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682)
my_ptr = varargin{2}; my_ptr = varargin{2};
class_wrapper(56, my_ptr); class_wrapper(62, my_ptr);
elseif nargin == 4 && isa(varargin{1},'numeric') && isa(varargin{2},'numeric') && isa(varargin{3},'double') && isa(varargin{4},'gtsam.noiseModel.Base') elseif nargin == 4 && isa(varargin{1},'numeric') && isa(varargin{2},'numeric') && isa(varargin{3},'double') && isa(varargin{4},'gtsam.noiseModel.Base')
my_ptr = class_wrapper(57, varargin{1}, varargin{2}, varargin{3}, varargin{4}); my_ptr = class_wrapper(63, varargin{1}, varargin{2}, varargin{3}, varargin{4});
else else
error('Arguments do not match any overload of MyFactorPosePoint2 constructor'); error('Arguments do not match any overload of MyFactorPosePoint2 constructor');
end end
@ -25,7 +25,7 @@ classdef MyFactorPosePoint2 < handle
end end
function delete(obj) function delete(obj)
class_wrapper(58, obj.ptr_MyFactorPosePoint2); class_wrapper(64, obj.ptr_MyFactorPosePoint2);
end end
function display(obj), obj.print(''); end function display(obj), obj.print(''); end
@ -36,7 +36,7 @@ classdef MyFactorPosePoint2 < handle
% PRINT usage: print(string s, KeyFormatter keyFormatter) : returns void % PRINT usage: print(string s, KeyFormatter keyFormatter) : returns void
% Doxygen can be found at https://gtsam.org/doxygen/ % Doxygen can be found at https://gtsam.org/doxygen/
if length(varargin) == 2 && isa(varargin{1},'char') && isa(varargin{2},'gtsam.KeyFormatter') if length(varargin) == 2 && isa(varargin{1},'char') && isa(varargin{2},'gtsam.KeyFormatter')
class_wrapper(59, this, varargin{:}); class_wrapper(65, this, varargin{:});
return return
end end
error('Arguments do not match any overload of function MyFactorPosePoint2.print'); error('Arguments do not match any overload of function MyFactorPosePoint2.print');

View File

@ -33,6 +33,8 @@ typedef std::set<boost::shared_ptr<MultipleTemplatesIntFloat>*> Collector_Multip
static Collector_MultipleTemplatesIntFloat collector_MultipleTemplatesIntFloat; static Collector_MultipleTemplatesIntFloat collector_MultipleTemplatesIntFloat;
typedef std::set<boost::shared_ptr<ForwardKinematics>*> Collector_ForwardKinematics; typedef std::set<boost::shared_ptr<ForwardKinematics>*> Collector_ForwardKinematics;
static Collector_ForwardKinematics collector_ForwardKinematics; static Collector_ForwardKinematics collector_ForwardKinematics;
typedef std::set<boost::shared_ptr<TemplatedConstructor>*> Collector_TemplatedConstructor;
static Collector_TemplatedConstructor collector_TemplatedConstructor;
typedef std::set<boost::shared_ptr<MyFactorPosePoint2>*> Collector_MyFactorPosePoint2; typedef std::set<boost::shared_ptr<MyFactorPosePoint2>*> Collector_MyFactorPosePoint2;
static Collector_MyFactorPosePoint2 collector_MyFactorPosePoint2; static Collector_MyFactorPosePoint2 collector_MyFactorPosePoint2;
@ -97,6 +99,12 @@ void _deleteAllObjects()
collector_ForwardKinematics.erase(iter++); collector_ForwardKinematics.erase(iter++);
anyDeleted = true; anyDeleted = true;
} } } }
{ for(Collector_TemplatedConstructor::iterator iter = collector_TemplatedConstructor.begin();
iter != collector_TemplatedConstructor.end(); ) {
delete *iter;
collector_TemplatedConstructor.erase(iter++);
anyDeleted = true;
} }
{ for(Collector_MyFactorPosePoint2::iterator iter = collector_MyFactorPosePoint2.begin(); { for(Collector_MyFactorPosePoint2::iterator iter = collector_MyFactorPosePoint2.begin();
iter != collector_MyFactorPosePoint2.end(); ) { iter != collector_MyFactorPosePoint2.end(); ) {
delete *iter; delete *iter;
@ -682,7 +690,76 @@ void ForwardKinematics_deconstructor_55(int nargout, mxArray *out[], int nargin,
} }
} }
void MyFactorPosePoint2_collectorInsertAndMakeBase_56(int nargout, mxArray *out[], int nargin, const mxArray *in[]) void TemplatedConstructor_collectorInsertAndMakeBase_56(int nargout, mxArray *out[], int nargin, const mxArray *in[])
{
mexAtExit(&_deleteAllObjects);
typedef boost::shared_ptr<TemplatedConstructor> Shared;
Shared *self = *reinterpret_cast<Shared**> (mxGetData(in[0]));
collector_TemplatedConstructor.insert(self);
}
void TemplatedConstructor_constructor_57(int nargout, mxArray *out[], int nargin, const mxArray *in[])
{
mexAtExit(&_deleteAllObjects);
typedef boost::shared_ptr<TemplatedConstructor> Shared;
Shared *self = new Shared(new TemplatedConstructor());
collector_TemplatedConstructor.insert(self);
out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);
*reinterpret_cast<Shared**> (mxGetData(out[0])) = self;
}
void TemplatedConstructor_constructor_58(int nargout, mxArray *out[], int nargin, const mxArray *in[])
{
mexAtExit(&_deleteAllObjects);
typedef boost::shared_ptr<TemplatedConstructor> Shared;
string& arg = *unwrap_shared_ptr< string >(in[0], "ptr_string");
Shared *self = new Shared(new TemplatedConstructor(arg));
collector_TemplatedConstructor.insert(self);
out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);
*reinterpret_cast<Shared**> (mxGetData(out[0])) = self;
}
void TemplatedConstructor_constructor_59(int nargout, mxArray *out[], int nargin, const mxArray *in[])
{
mexAtExit(&_deleteAllObjects);
typedef boost::shared_ptr<TemplatedConstructor> Shared;
int arg = unwrap< int >(in[0]);
Shared *self = new Shared(new TemplatedConstructor(arg));
collector_TemplatedConstructor.insert(self);
out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);
*reinterpret_cast<Shared**> (mxGetData(out[0])) = self;
}
void TemplatedConstructor_constructor_60(int nargout, mxArray *out[], int nargin, const mxArray *in[])
{
mexAtExit(&_deleteAllObjects);
typedef boost::shared_ptr<TemplatedConstructor> Shared;
double arg = unwrap< double >(in[0]);
Shared *self = new Shared(new TemplatedConstructor(arg));
collector_TemplatedConstructor.insert(self);
out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL);
*reinterpret_cast<Shared**> (mxGetData(out[0])) = self;
}
void TemplatedConstructor_deconstructor_61(int nargout, mxArray *out[], int nargin, const mxArray *in[])
{
typedef boost::shared_ptr<TemplatedConstructor> Shared;
checkArguments("delete_TemplatedConstructor",nargout,nargin,1);
Shared *self = *reinterpret_cast<Shared**>(mxGetData(in[0]));
Collector_TemplatedConstructor::iterator item;
item = collector_TemplatedConstructor.find(self);
if(item != collector_TemplatedConstructor.end()) {
delete self;
collector_TemplatedConstructor.erase(item);
}
}
void MyFactorPosePoint2_collectorInsertAndMakeBase_62(int nargout, mxArray *out[], int nargin, const mxArray *in[])
{ {
mexAtExit(&_deleteAllObjects); mexAtExit(&_deleteAllObjects);
typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared; typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared;
@ -691,7 +768,7 @@ void MyFactorPosePoint2_collectorInsertAndMakeBase_56(int nargout, mxArray *out[
collector_MyFactorPosePoint2.insert(self); collector_MyFactorPosePoint2.insert(self);
} }
void MyFactorPosePoint2_constructor_57(int nargout, mxArray *out[], int nargin, const mxArray *in[]) void MyFactorPosePoint2_constructor_63(int nargout, mxArray *out[], int nargin, const mxArray *in[])
{ {
mexAtExit(&_deleteAllObjects); mexAtExit(&_deleteAllObjects);
typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared; typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared;
@ -706,7 +783,7 @@ void MyFactorPosePoint2_constructor_57(int nargout, mxArray *out[], int nargin,
*reinterpret_cast<Shared**> (mxGetData(out[0])) = self; *reinterpret_cast<Shared**> (mxGetData(out[0])) = self;
} }
void MyFactorPosePoint2_deconstructor_58(int nargout, mxArray *out[], int nargin, const mxArray *in[]) void MyFactorPosePoint2_deconstructor_64(int nargout, mxArray *out[], int nargin, const mxArray *in[])
{ {
typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared; typedef boost::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>> Shared;
checkArguments("delete_MyFactorPosePoint2",nargout,nargin,1); checkArguments("delete_MyFactorPosePoint2",nargout,nargin,1);
@ -719,7 +796,7 @@ void MyFactorPosePoint2_deconstructor_58(int nargout, mxArray *out[], int nargin
} }
} }
void MyFactorPosePoint2_print_59(int nargout, mxArray *out[], int nargin, const mxArray *in[]) void MyFactorPosePoint2_print_65(int nargout, mxArray *out[], int nargin, const mxArray *in[])
{ {
checkArguments("print",nargout,nargin-1,2); checkArguments("print",nargout,nargin-1,2);
auto obj = unwrap_shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>>(in[0], "ptr_MyFactorPosePoint2"); auto obj = unwrap_shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>>(in[0], "ptr_MyFactorPosePoint2");
@ -909,16 +986,34 @@ void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[])
ForwardKinematics_deconstructor_55(nargout, out, nargin-1, in+1); ForwardKinematics_deconstructor_55(nargout, out, nargin-1, in+1);
break; break;
case 56: case 56:
MyFactorPosePoint2_collectorInsertAndMakeBase_56(nargout, out, nargin-1, in+1); TemplatedConstructor_collectorInsertAndMakeBase_56(nargout, out, nargin-1, in+1);
break; break;
case 57: case 57:
MyFactorPosePoint2_constructor_57(nargout, out, nargin-1, in+1); TemplatedConstructor_constructor_57(nargout, out, nargin-1, in+1);
break; break;
case 58: case 58:
MyFactorPosePoint2_deconstructor_58(nargout, out, nargin-1, in+1); TemplatedConstructor_constructor_58(nargout, out, nargin-1, in+1);
break; break;
case 59: case 59:
MyFactorPosePoint2_print_59(nargout, out, nargin-1, in+1); TemplatedConstructor_constructor_59(nargout, out, nargin-1, in+1);
break;
case 60:
TemplatedConstructor_constructor_60(nargout, out, nargin-1, in+1);
break;
case 61:
TemplatedConstructor_deconstructor_61(nargout, out, nargin-1, in+1);
break;
case 62:
MyFactorPosePoint2_collectorInsertAndMakeBase_62(nargout, out, nargin-1, in+1);
break;
case 63:
MyFactorPosePoint2_constructor_63(nargout, out, nargin-1, in+1);
break;
case 64:
MyFactorPosePoint2_deconstructor_64(nargout, out, nargin-1, in+1);
break;
case 65:
MyFactorPosePoint2_print_65(nargout, out, nargin-1, in+1);
break; break;
} }
} catch(const std::exception& e) { } catch(const std::exception& e) {

View File

@ -86,6 +86,12 @@ PYBIND11_MODULE(class_py, m_) {
py::class_<ForwardKinematics, std::shared_ptr<ForwardKinematics>>(m_, "ForwardKinematics") py::class_<ForwardKinematics, std::shared_ptr<ForwardKinematics>>(m_, "ForwardKinematics")
.def(py::init<const gtdynamics::Robot&, const string&, const string&, const gtsam::Values&, const gtsam::Pose3&>(), py::arg("robot"), py::arg("start_link_name"), py::arg("end_link_name"), py::arg("joint_angles"), py::arg("l2Tp") = gtsam::Pose3()); .def(py::init<const gtdynamics::Robot&, const string&, const string&, const gtsam::Values&, const gtsam::Pose3&>(), py::arg("robot"), py::arg("start_link_name"), py::arg("end_link_name"), py::arg("joint_angles"), py::arg("l2Tp") = gtsam::Pose3());
py::class_<TemplatedConstructor, std::shared_ptr<TemplatedConstructor>>(m_, "TemplatedConstructor")
.def(py::init<>())
.def(py::init<const string&>(), py::arg("arg"))
.def(py::init<const int&>(), py::arg("arg"))
.def(py::init<const double&>(), py::arg("arg"));
py::class_<MyFactor<gtsam::Pose2, gtsam::Matrix>, std::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>>>(m_, "MyFactorPosePoint2") py::class_<MyFactor<gtsam::Pose2, gtsam::Matrix>, std::shared_ptr<MyFactor<gtsam::Pose2, gtsam::Matrix>>>(m_, "MyFactorPosePoint2")
.def(py::init<size_t, size_t, double, const std::shared_ptr<gtsam::noiseModel::Base>>(), py::arg("key1"), py::arg("key2"), py::arg("measured"), py::arg("noiseModel")) .def(py::init<size_t, size_t, double, const std::shared_ptr<gtsam::noiseModel::Base>>(), py::arg("key1"), py::arg("key2"), py::arg("measured"), py::arg("noiseModel"))
.def("print",[](MyFactor<gtsam::Pose2, gtsam::Matrix>* self, const string& s, const gtsam::KeyFormatter& keyFormatter){ py::scoped_ostream_redirect output; self->print(s, keyFormatter);}, py::arg("s") = "factor: ", py::arg("keyFormatter") = gtsam::DefaultKeyFormatter) .def("print",[](MyFactor<gtsam::Pose2, gtsam::Matrix>* self, const string& s, const gtsam::KeyFormatter& keyFormatter){ py::scoped_ostream_redirect output; self->print(s, keyFormatter);}, py::arg("s") = "factor: ", py::arg("keyFormatter") = gtsam::DefaultKeyFormatter)

View File

@ -69,6 +69,16 @@ PYBIND11_MODULE(enum_py, m_) {
.value("Groot", gtsam::MCU::GotG::Groot); .value("Groot", gtsam::MCU::GotG::Groot);
py::class_<gtsam::Optimizer<gtsam::GaussNewtonParams>, std::shared_ptr<gtsam::Optimizer<gtsam::GaussNewtonParams>>> optimizergaussnewtonparams(m_gtsam, "OptimizerGaussNewtonParams");
optimizergaussnewtonparams
.def("setVerbosity",[](gtsam::Optimizer<gtsam::GaussNewtonParams>* self, const Optimizer<gtsam::GaussNewtonParams>::Verbosity value){ self->setVerbosity(value);}, py::arg("value"));
py::enum_<gtsam::Optimizer<gtsam::GaussNewtonParams>::Verbosity>(optimizergaussnewtonparams, "Verbosity", py::arithmetic())
.value("SILENT", gtsam::Optimizer<gtsam::GaussNewtonParams>::Verbosity::SILENT)
.value("SUMMARY", gtsam::Optimizer<gtsam::GaussNewtonParams>::Verbosity::SUMMARY)
.value("VERBOSE", gtsam::Optimizer<gtsam::GaussNewtonParams>::Verbosity::VERBOSE);
#include "python/specializations.h" #include "python/specializations.h"

View File

@ -7,6 +7,7 @@ class FunRange {
template<M={double}> template<M={double}>
class Fun { class Fun {
static This staticMethodWithThis(); static This staticMethodWithThis();
template<T={string}> template<T={string}>
@ -118,5 +119,14 @@ class ForwardKinematics {
const gtsam::Pose3& l2Tp = gtsam::Pose3()); const gtsam::Pose3& l2Tp = gtsam::Pose3());
}; };
// Test for templated constructor
class TemplatedConstructor {
TemplatedConstructor();
template<T={string, int, double}>
TemplatedConstructor(const T& arg);
};
class SuperCoolFactor; class SuperCoolFactor;
typedef SuperCoolFactor<gtsam::Pose3> SuperCoolFactorPose3; typedef SuperCoolFactor<gtsam::Pose3> SuperCoolFactorPose3;

View File

@ -42,4 +42,17 @@ class MCU {
}; };
template<PARAMS>
class Optimizer {
enum Verbosity {
SILENT,
SUMMARY,
VERBOSE
};
void setVerbosity(const This::Verbosity value);
};
typedef gtsam::Optimizer<gtsam::GaussNewtonParams> OptimizerGaussNewtonParams;
} // namespace gtsam } // namespace gtsam

View File

@ -314,6 +314,25 @@ class TestInterfaceParser(unittest.TestCase):
self.assertEqual(5, len(ret.args)) self.assertEqual(5, len(ret.args))
self.assertEqual("gtsam::Pose3()", ret.args.list()[4].default) self.assertEqual("gtsam::Pose3()", ret.args.list()[4].default)
def test_constructor_templated(self):
"""Test for templated class constructor."""
f = """
template<T = {double, int}>
Class();
"""
ret = Constructor.rule.parseString(f)[0]
self.assertEqual("Class", ret.name)
self.assertEqual(0, len(ret.args))
f = """
template<T = {double, int}>
Class(const T& name);
"""
ret = Constructor.rule.parseString(f)[0]
self.assertEqual("Class", ret.name)
self.assertEqual(1, len(ret.args))
self.assertEqual("const T & name", ret.args.args_list[0].to_cpp())
def test_operator_overload(self): def test_operator_overload(self):
"""Test for operator overloading.""" """Test for operator overloading."""
# Unary operator # Unary operator