diff --git a/.gitmodules b/.gitmodules
index 4d3f6e99e3d9d4295085c1d11476978ae75f67e7..8c38c8a99db1173117058b2633fc1babc00c0800 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,24 +1,24 @@
 [submodule "dep/lapack"]
 	path = dep/lapack
-	url = https://git.rwth-aachen.de/avt.svt/public/thirdparty/lapack.git
+	url = https://git.rwth-aachen.de/avt-svt/public/thirdparty/lapack.git
 [submodule "dep/blas"]
 	path = dep/blas
-	url = https://git.rwth-aachen.de/avt.svt/public/thirdparty/blas.git
+	url = https://git.rwth-aachen.de/avt-svt/public/thirdparty/blas.git
 [submodule "dep/cpplapack"]
 	path = dep/cpplapack
-	url = https://git.rwth-aachen.de/avt.svt/public/thirdparty/cpplapack.git
+	url = https://git.rwth-aachen.de/avt-svt/public/thirdparty/cpplapack.git
 [submodule "dep/filib"]
 	path = dep/filib
-	url = https://git.rwth-aachen.de/avt.svt/public/thirdparty/filib.git
+	url = https://git.rwth-aachen.de/avt-svt/public/thirdparty/filib.git
 [submodule "dep/fadbad"]
 	path = dep/fadbad
-	url = https://git.rwth-aachen.de/avt.svt/public/thirdparty/fadbad.git
+	url = https://git.rwth-aachen.de/avt-svt/public/thirdparty/fadbad.git
 [submodule "dep/json"]
 	path = dep/json
-	url = https://git.rwth-aachen.de/avt.svt/public/thirdparty/json.git
+	url = https://git.rwth-aachen.de/avt-svt/public/thirdparty/json.git
 [submodule "dep/pybind11"]
 	path = dep/pybind11
 	url = https://github.com/pybind/pybind11
 [submodule "dep/mcpp"]
 	path = dep/mcpp
-	url = https://git.rwth-aachen.de/avt.svt/public/thirdparty/mcpp
+	url = https://git.rwth-aachen.de/avt-svt/public/thirdparty/mcpp.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 12a09499daeb52684f21abe5a07a49502c52352a..70c91bf2202a512ad26bc057d88f5f19e579b79d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,10 @@ cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
 
 project(melon CXX)
 
-set(MeLOn_build_python_interface FALSE CACHE BOOL "Build a dll and Python module called pymaingo for calling MAiNGO from Python.")
+set(MeLOn_build_python_interface FALSE CACHE BOOL "Build the Python extension module 'melonpy' that allows to call MeLOn from Python.")
+if(MeLOn_build_python_interface)
+	set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+endif()
 
 add_library(melon INTERFACE)
 target_link_libraries(melon INTERFACE gp ffnet svm)
@@ -42,6 +45,13 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
 
 	# Add python interface
 	if(MeLOn_build_python_interface)
+        set(PYBIND11_FINDPYTHON FALSE CACHE BOOL "Whether to have pybind11 use FindPython")
+        if(SKBUILD)
+            set(Python_EXECUTABLE ${PYTHON_EXECUTABLE})
+            set(Python_VERSION ${PYTHON_VERSION_STRING})
+            set(Python_INCLUDE_DIRS ${PYTHON_INCLUDE_DIR})
+            set(Python_LIBRARIES ${PYTHON_LIBRARY})
+        endif()
 		add_dependency_subdir(pybind11)
 	endif()
 
@@ -80,9 +90,13 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
 endif()
 
 
-# Add python interface
+# --------------- Python interface ---------------------------
 if(MeLOn_build_python_interface)
-    pybind11_add_module(_pymelon common/src/pymelon.cpp)
-    set_target_properties(_pymelon PROPERTIES CXX_STANDARD 14)
-    target_link_libraries(_pymelon PRIVATE melon)
+
+    # Create target for melonpy extension module
+    pybind11_add_module(melonpy common/src/melonpy.cpp)
+    target_compile_features(melonpy PRIVATE cxx_std_14)
+    target_link_libraries(melonpy PRIVATE melon)
+    target_compile_options(melonpy PRIVATE $<$<CXX_COMPILER_ID:AppleClang>: -fvisibility=default>)
+
 endif()
diff --git a/common/src/melonpy.cpp b/common/src/melonpy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf778778c038df80eb04988e7c3c26bbe9b74e88
--- /dev/null
+++ b/common/src/melonpy.cpp
@@ -0,0 +1,167 @@
+/**********************************************************************************
+ * Copyright (c) 2019 Process Systems Engineering (AVT.SVT), RWTH Aachen University
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ **********************************************************************************/
+
+#include "gp.h"
+#include "gpData.h"
+#include "ffNet.h"
+#include "svm.h"
+#include "modelParser.h"
+#include "ffunc.hpp"
+
+#include <pybind11/pybind11.h>
+#include <pybind11/operators.h>
+#include <pybind11/stl.h>
+
+namespace py = pybind11;
+
+
+// Definition of the actual Python module called melonpy
+PYBIND11_MODULE(melonpy, m) {
+    m.doc() = "MeLOn - Machine-Learning models for Optimization";
+
+	//----------------------------------------------------------------------------------------
+	// MelonModel
+	//----------------------------------------------------------------------------------------
+
+	py::class_< melon::MelonModel<mc::FFVar>>(m, "MelonModel")
+		.def("load_model", py::overload_cast<std::string, std::string, melon::MODEL_FILE_TYPE>(&melon::MelonModel<mc::FFVar>::load_model))
+		.def("load_model", py::overload_cast<std::string, melon::MODEL_FILE_TYPE>(&melon::MelonModel<mc::FFVar>::load_model))
+		.def("load_model", py::overload_cast<std::shared_ptr<const ModelData>>(&melon::MelonModel<mc::FFVar>::load_model));
+
+
+	// enums
+
+	py::enum_<melon::SCALER_TYPE>(m, "SCALER_TYPE")
+		.value("IDENTIY", melon::SCALER_TYPE::IDENTITY)
+		.value("MINMAX", melon::SCALER_TYPE::MINMAX)
+		.value("STANDARD", melon::SCALER_TYPE::STANDARD)
+		.export_values();
+
+	py::enum_<melon::MODEL_FILE_TYPE>(m, "MODEL_FILE_TYPE")
+		.value("CSV", melon::MODEL_FILE_TYPE::CSV)
+		.value("XML", melon::MODEL_FILE_TYPE::XML)
+		.value("JSON", melon::MODEL_FILE_TYPE::JSON)
+		.export_values();
+
+	py::enum_<melon::SCALER_PARAMETER>(m, "SCALER_PARAMETER")
+		.value("LOWER_BOUNDS", melon::SCALER_PARAMETER::LOWER_BOUNDS)
+		.value("UPPER_BOUNDS", melon::SCALER_PARAMETER::UPPER_BOUNDS)
+		.value("STD_DEV", melon::SCALER_PARAMETER::STD_DEV)
+		.value("MEAN", melon::SCALER_PARAMETER::MEAN)
+		.value("SCALED_LOWER_BOUNDS", melon::SCALER_PARAMETER::SCALED_LOWER_BOUNDS)
+		.value("SCALED_UPPER_BOUNDS", melon::SCALER_PARAMETER::SCALED_UPPER_BOUNDS)
+		.export_values();
+
+
+	// data
+
+	py::class_<ModelData, std::shared_ptr<ModelData>>(m, "ModelData");
+
+	py::class_<melon::kernel::KernelData,  std::shared_ptr<melon::kernel::KernelData>>(m, "KernelData")
+		.def(py::init<>())
+		.def_readwrite("sf2", &melon::kernel::KernelData::sf2)
+		.def_readwrite("ell", &melon::kernel::KernelData::ell);
+
+	py::class_<melon::ScalerData, std::shared_ptr<melon::ScalerData>>(m, "ScalerData")
+		.def(py::init<>())
+		.def_readwrite("type", &melon::ScalerData::type)
+		.def_readwrite("parameters", &melon::ScalerData::parameters);
+
+
+
+	//----------------------------------------------------------------------------------------
+	// Gaussian process
+	//----------------------------------------------------------------------------------------
+
+	// model
+
+	py::class_<melon::GaussianProcess<mc::FFVar>, melon::MelonModel<mc::FFVar> >(m, "GaussianProcess")
+		.def(py::init<>())
+		.def(py::init <std::string >())
+		.def(py::init< std::string, std::string >())
+		.def("calculate_prediction_reduced_space", &melon::GaussianProcess<mc::FFVar>::calculate_prediction_reduced_space)
+		.def("calculate_variance_reduced_space", &melon::GaussianProcess<mc::FFVar>::calculate_variance_reduced_space)
+		.def("calculate_prediction_full_space", &melon::GaussianProcess<mc::FFVar>::calculate_prediction_full_space)
+		.def("calculate_variance_full_space", &melon::GaussianProcess<mc::FFVar>::calculate_variance_full_space)
+		.def("calculate_prediction_and_variance_full_space", &melon::GaussianProcess<mc::FFVar>::calculate_prediction_and_variance_full_space)
+		.def("get_input_dimension", &melon::GaussianProcess<mc::FFVar>::get_input_dimension)
+		.def("get_number_of_training_data_points", &melon::GaussianProcess<mc::FFVar>::get_number_of_training_data_points)
+		.def("get_minimum_of_training_data_outputs", &melon::GaussianProcess<mc::FFVar>::get_minimum_of_training_data_outputs)
+		.def("get_maximum_of_training_data_outputs", &melon::GaussianProcess<mc::FFVar>::get_maximum_of_training_data_outputs)
+		.def("get_number_of_full_space_variables_prediction", &melon::GaussianProcess<mc::FFVar>::get_number_of_full_space_variables_prediction)
+		.def("get_full_space_variables_prediction", &melon::GaussianProcess<mc::FFVar>::get_full_space_variables_prediction)
+		.def("get_number_of_full_space_variables_variance", &melon::GaussianProcess<mc::FFVar>::get_number_of_full_space_variables_variance)
+		.def("get_full_space_variables_variance", &melon::GaussianProcess<mc::FFVar>::get_full_space_variables_variance)
+		.def("get_number_of_full_space_variables_prediction_and_variance", &melon::GaussianProcess<mc::FFVar>::get_number_of_full_space_variables_prediction_and_variance)
+		.def("get_full_space_variables_prediction_and_variance", &melon::GaussianProcess<mc::FFVar>::get_full_space_variables_prediction_and_variance)
+		.def("get_observations", &melon::GaussianProcess<mc::FFVar>::get_observations)
+		.def("get_normalized_observations", &melon::GaussianProcess<mc::FFVar>::get_normalized_observations);
+
+
+	// data
+
+	py::class_<melon::GPData, ModelData, std::shared_ptr<melon::GPData>>(m, "GPData")
+		.def(py::init<>())
+		.def_readwrite("kernelData", &melon::GPData::kernelData)
+		.def_readwrite("nX", &melon::GPData::nX)
+		.def_readwrite("DX", &melon::GPData::DX)
+		.def_readwrite("DY", &melon::GPData::DY)
+		.def_readwrite("matern", &melon::GPData::matern)
+		.def_readwrite("inputScalerData", &melon::GPData::inputScalerData)
+		.def_readwrite("predictionScalerData", &melon::GPData::predictionScalerData)
+		.def_readwrite("X", &melon::GPData::X)
+		.def_readwrite("Y", &melon::GPData::Y)
+		.def_readwrite("K", &melon::GPData::K)
+		.def_readwrite("invK", &melon::GPData::invK)
+		.def_readwrite("stdOfOutput", &melon::GPData::stdOfOutput)
+		.def_readwrite("meanFunction", &melon::GPData::meanfunction);
+
+
+	//----------------------------------------------------------------------------------------
+	// Feed forward network
+	//----------------------------------------------------------------------------------------
+	py::class_<melon::FeedForwardNet<mc::FFVar>, melon::MelonModel<mc::FFVar> >(m, "FeedForwardNet")
+		.def(py::init<>())
+		.def(py::init <std::string, melon::MODEL_FILE_TYPE >())
+		.def(py::init< std::string, std::string, melon::MODEL_FILE_TYPE >())
+		.def("calculate_prediction_reduced_space", &melon::FeedForwardNet<mc::FFVar>::calculate_prediction_reduced_space)
+		.def("calculate_prediction_full_space", &melon::FeedForwardNet<mc::FFVar>::calculate_prediction_full_space)
+		.def("set_tanh_formulation", &melon::FeedForwardNet<mc::FFVar>::set_tanh_formulation)
+		.def("get_number_of_full_space_variables", &melon::FeedForwardNet<mc::FFVar>::get_number_of_full_space_variables)
+		.def("get_full_space_variables", &melon::FeedForwardNet<mc::FFVar>::get_full_space_variables);
+
+	py::enum_<melon::TANH_REFORMULATION>(m, "TANH_REFORMULATION")
+		.value("TANH_REF_0", melon::TANH_REFORMULATION::TANH_REF_0)
+		.value("TANH_REF1", melon::TANH_REFORMULATION::TANH_REF1)
+		.value("TANH_REF2", melon::TANH_REFORMULATION::TANH_REF2)
+		.value("TANH_REF3", melon::TANH_REFORMULATION::TANH_REF3)
+		.value("TANH_REF4", melon::TANH_REFORMULATION::TANH_REF4)
+		.export_values();
+
+	//----------------------------------------------------------------------------------------
+	// Support vector machines
+	//----------------------------------------------------------------------------------------
+	py::class_<melon::SupportVectorMachine<mc::FFVar>, melon::MelonModel<mc::FFVar> >(m, "SupportVectorMachine")
+		.def("calculate_prediction_reduced_space", &melon::SupportVectorMachine<mc::FFVar>::calculate_prediction_reduced_space)
+		.def("calculate_prediction_full_space", &melon::SupportVectorMachine<mc::FFVar>::calculate_prediction_full_space)
+		.def("get_number_of_full_space_variables", &melon::SupportVectorMachine<mc::FFVar>::get_number_of_full_space_variables)
+		.def("get_fullspace_variables", &melon::SupportVectorMachine<mc::FFVar>::get_fullspace_variables);
+
+	py::class_<melon::SupportVectorRegression<mc::FFVar>, melon::SupportVectorMachine<mc::FFVar> >(m, "SupportVectorRegression")
+		.def(py::init<>())
+		.def(py::init <std::string >())
+		.def(py::init< std::string, std::string >());
+
+	py::class_<melon::SupportVectorMachineOneClass<mc::FFVar>, melon::SupportVectorMachine<mc::FFVar> >(m, "SupportVectorMachineOneClass")
+		.def(py::init<>())
+		.def(py::init <std::string >())
+		.def(py::init< std::string, std::string >());
+}
diff --git a/dep/mcpp b/dep/mcpp
index da5a2f227ef57f2d88654b30149636a0b1557085..dfbdc830edbd11afe31c4283020ecdb0683c3ee2 160000
--- a/dep/mcpp
+++ b/dep/mcpp
@@ -1 +1 @@
-Subproject commit da5a2f227ef57f2d88654b30149636a0b1557085
+Subproject commit dfbdc830edbd11afe31c4283020ecdb0683c3ee2