From 3a12104356b297ac49d9f7db293477bf90718d22 Mon Sep 17 00:00:00 2001 From: Volkan Kumtepeli Date: Tue, 18 Oct 2022 17:52:05 +0100 Subject: [PATCH 1/7] C++ gurobi is trying to be added. --- CMakeLists.txt | 59 +++++++++++++--- cmake/CMakeLists_forGurobi.txt | 45 +++++++++++++ cmake/FindGUROBI.cmake | 55 +++++++++++++++ dtwc/main.cpp | 120 ++++++++++++++++++++++++++------- 4 files changed, 244 insertions(+), 35 deletions(-) create mode 100644 cmake/CMakeLists_forGurobi.txt create mode 100644 cmake/FindGUROBI.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index a3177b2..3ccce51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,12 @@ project(DTWC++ VERSION "2.0.0" HOMEPAGE_URL https://battery-intelligence-lab.github.io/dtw-cpp/ LANGUAGES CXX) +option(CXX "enable C++ compilation" ON) + +if(CXX) + enable_language(CXX) +endif() + # Link this 'library' to use the warnings specified in CompilerWarnings.cmake add_library(project_warnings INTERFACE) @@ -15,16 +21,6 @@ add_library(project_warnings INTERFACE) add_library(project_options INTERFACE) target_compile_features(project_options INTERFACE cxx_std_20) -add_executable(dtwc++ - dtwc/main.cpp -) - -target_link_libraries(dtwc++ - PRIVATE - project_warnings - project_options -) - target_compile_definitions(dtwc++ PRIVATE ROOT_FOLDER="${PROJECT_SOURCE_DIR}") if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") @@ -35,8 +31,13 @@ if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") endif() endif() +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + # # enable cache system # include(cmake/Cache.cmake) +# include(cmake/FindGUROBI.cmake) +find_package(GUROBI REQUIRED) +include_directories(${GUROBI_INCLUDE_DIRS}) # standard compiler warnings include(cmake/CompilerWarnings.cmake) @@ -52,3 +53,41 @@ set_project_warnings(project_warnings) # # allow for static analysis options # include(cmake/StaticAnalyzers.cmake) +message(STATUS "GUROBI CXX LIBRARY START") +message(STATUS ${GUROBI_CXX_LIBRARY}) +message(STATUS "GUROBI CXX LIBRARY END") + +message(STATUS "GUROBI CXX DEBUG LIBRARY START") +message(STATUS ${GUROBI_CXX_DEBUG_LIBRARY}) +message(STATUS "GUROBI CXX DEBUG LIBRARY END") + +message(STATUS "GUROBI LIBRARY START") +message(STATUS ${GUROBI_LIBRARY}) +message(STATUS "GUROBI LIBRARY END") + +file(GLOB SRC_FILES + $ENV{GUROBI_HOME}/src/cpp/*.h + $ENV{GUROBI_HOME}/src/cpp/*.cpp +) + +foreach(header ${HEADERS_FILES}) + # here replace / for linux and \ for windows + string(REPLACE "/" "_" header_path header) + string(TOUPPER header_path final_header_path) + file(APPEND headers_defines_file define + PATH_${final_header_path} ${CMAKE_CURRENT_SOURCE_DIR}/header) +endforeach(header) + +add_executable(dtwc++ + dtwc/main.cpp + ${SRC_FILES} +) + +target_link_libraries(dtwc++ + PRIVATE + project_warnings + project_options + PUBLIC + ${GUROBI_CXX_LIBRARY} + ${GUROBI_LIBRARY} +) diff --git a/cmake/CMakeLists_forGurobi.txt b/cmake/CMakeLists_forGurobi.txt new file mode 100644 index 0000000..2ca29c4 --- /dev/null +++ b/cmake/CMakeLists_forGurobi.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.3) + +project(gurobi-template C) + +option(CXX "enable C++ compilation" ON) + +if(CXX) + enable_language(CXX) +endif() + +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif() +message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") + +# Visual Studio compiler with static runtime libraries +if(MSVC AND MT) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") +endif() + +find_package(GUROBI REQUIRED) + +include_directories(${GUROBI_INCLUDE_DIRS}) + +# list source files here +set(sources mip1_c++.cpp) + +add_executable(${CMAKE_PROJECT_NAME} ${sources}) + +if(CXX) + set(CMAKE_CXX_STANDARD 11) + target_link_libraries(${CMAKE_PROJECT_NAME} optimized ${GUROBI_CXX_LIBRARY} + debug ${GUROBI_CXX_DEBUG_LIBRARY}) +endif() + +target_link_libraries(${CMAKE_PROJECT_NAME} ${GUROBI_LIBRARY}) + +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + include(FeatureSummary) + feature_summary(WHAT ALL) +endif() diff --git a/cmake/FindGUROBI.cmake b/cmake/FindGUROBI.cmake new file mode 100644 index 0000000..0629fd5 --- /dev/null +++ b/cmake/FindGUROBI.cmake @@ -0,0 +1,55 @@ +find_path( + GUROBI_INCLUDE_DIRS + NAMES gurobi_c.h + HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} + PATH_SUFFIXES include) + +find_library( + GUROBI_LIBRARY + NAMES gurobi gurobi81 gurobi90 gurobi95 + HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} + PATH_SUFFIXES lib) + +if(CXX) + if(MSVC) + # determine Visual Studio year + if(MSVC_TOOLSET_VERSION EQUAL 142) + set(MSVC_YEAR "2019") + elseif(MSVC_TOOLSET_VERSION EQUAL 141) + set(MSVC_YEAR "2017") + elseif(MSVC_TOOLSET_VERSION EQUAL 140) + set(MSVC_YEAR "2015") + endif() + + if(MT) + set(M_FLAG "mt") + else() + set(M_FLAG "md") + endif() + + message(STATUS "CXX START") + message(STATUS gurobi_c++${M_FLAG}${MSVC_YEAR}) + + find_library( + GUROBI_CXX_LIBRARY + NAMES gurobi_c++${M_FLAG}${MSVC_YEAR} + HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} + PATH_SUFFIXES lib) + find_library( + GUROBI_CXX_DEBUG_LIBRARY + NAMES gurobi_c++${M_FLAG}d${MSVC_YEAR} + HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} + PATH_SUFFIXES lib) + else() + find_library( + GUROBI_CXX_LIBRARY + NAMES gurobi_c++ + HINTS ${GUROBI_DIR} $ENV{GUROBI_HOME} + PATH_SUFFIXES lib) + set(GUROBI_CXX_DEBUG_LIBRARY ${GUROBI_CXX_LIBRARY}) + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GUROBI DEFAULT_MSG GUROBI_LIBRARY + GUROBI_INCLUDE_DIRS) diff --git a/dtwc/main.cpp b/dtwc/main.cpp index 6483a6d..56c98d7 100644 --- a/dtwc/main.cpp +++ b/dtwc/main.cpp @@ -1,4 +1,5 @@ #include "dtwc.hpp" +#include #include #include @@ -7,37 +8,106 @@ #include #include -int main() -{ - using namespace dtwc; - dtwc::Clock clk; - int Ndata_max = 10; // Load 10 data maximum. +int main(){ - auto [p_vec, p_names] = load_data(settings::path, Ndata_max); + try { + GRBEnv env = GRBEnv(); - std::cout << "Data loading finished at " << clk << "\n"; + GRBModel model = GRBModel(env); - dtwc::VecMatrix DTWdist(p_vec.size(), p_vec.size(), -1); // For distance memoization. + // Create variables - // readMatrix(DTWdist, "../matlab/DTWdist_band_all.csv"); // Comment out if recalculating + GRBVar x = model.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "x"); + GRBVar y = model.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "y"); + GRBVar z = model.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "z"); - auto DTWdistByInd = [&DTWdist, p_vec = p_vec](int i, int j) { - if (DTWdist(i, j) < 0) { - if constexpr (settings::band == 0) { - DTWdist(j, i) = DTWdist(i, j) = dtwFun_L(p_vec[i], p_vec[j]); - } else { - DTWdist(j, i) = DTWdist(i, j) = dtwFunBanded_Act(p_vec[i], p_vec[j], settings::band); // dtwFunBanded_Act_L faster and more accurate. - } + // Set objective + + GRBLinExpr obj = x; + model.setObjective(obj, GRB_MAXIMIZE); + + // Add linear constraint: x + y + z <= 10 + + model.addConstr(x + y + z <= 10, "c0"); + + // Add bilinear inequality constraint: x * y <= 2 + + model.addQConstr(x * y <= 2, "bilinear0"); + + // Add bilinear equality constraint: y * z == 1 + + model.addQConstr(x * z + y * z == 1, "bilinear1"); + + // First optimize() call will fail - need to set NonConvex to 2 + + try { + model.optimize(); + assert(0); + } catch (GRBException e) { + std::cout << "Failed (as expected)" << std::endl; } - return DTWdist(i, j); - }; - fillDistanceMatrix(DTWdistByInd, p_vec.size()); // Otherwise takes time. + model.set(GRB_IntParam_NonConvex, 2); + model.optimize(); + + std::cout << x.get(GRB_StringAttr_VarName) << " " + << x.get(GRB_DoubleAttr_X) << std::endl; + std::cout << y.get(GRB_StringAttr_VarName) << " " + << y.get(GRB_DoubleAttr_X) << std::endl; + std::cout << z.get(GRB_StringAttr_VarName) << " " + << z.get(GRB_DoubleAttr_X) << std::endl; + + // Constrain x to be integral and solve again + x.set(GRB_CharAttr_VType, GRB_INTEGER); + model.optimize(); + + std::cout << x.get(GRB_StringAttr_VarName) << " " + << x.get(GRB_DoubleAttr_X) << std::endl; + std::cout << y.get(GRB_StringAttr_VarName) << " " + << y.get(GRB_DoubleAttr_X) << std::endl; + std::cout << z.get(GRB_StringAttr_VarName) << " " + << z.get(GRB_DoubleAttr_X) << std::endl; + + std::cout << "Obj: " << model.get(GRB_DoubleAttr_ObjVal) << std::endl; + + } catch (GRBException e) { + std::cout << "Error code = " << e.getErrorCode() << std::endl; + std::cout << e.getMessage() << std::endl; + } catch (...) { + std::cout << "Exception during optimization" << std::endl; + } + + + + // using namespace dtwc; + // dtwc::Clock clk; + // int Ndata_max = 10; // Load 10 data maximum. + + // auto [p_vec, p_names] = load_data(settings::path, Ndata_max); + + // std::cout << "Data loading finished at " << clk << "\n"; + + // dtwc::VecMatrix DTWdist(p_vec.size(), p_vec.size(), -1); // For distance memoization. + + // // readMatrix(DTWdist, "../matlab/DTWdist_band_all.csv"); // Comment out if recalculating + + // auto DTWdistByInd = [&DTWdist, p_vec = p_vec](int i, int j) { + // if (DTWdist(i, j) < 0) { + // if constexpr (settings::band == 0) { + // DTWdist(j, i) = DTWdist(i, j) = dtwFun_L(p_vec[i], p_vec[j]); + // } else { + // DTWdist(j, i) = DTWdist(i, j) = dtwFunBanded_Act(p_vec[i], p_vec[j], settings::band); // dtwFunBanded_Act_L faster and more accurate. + // } + // } + // return DTWdist(i, j); + // }; + + // fillDistanceMatrix(DTWdistByInd, p_vec.size()); // Otherwise takes time. - std::string DistMatrixName = "DTW_matrix.csv"; - writeMatrix(DTWdist, DistMatrixName); - // DTWdist.print(); - std::cout << "Finished all tasks in " << clk << "\n"; - std::cout << "Band used " << settings::band << "\n\n\n"; -} + // std::string DistMatrixName = "DTW_matrix.csv"; + // writeMatrix(DTWdist, DistMatrixName); + // // DTWdist.print(); + // std::cout << "Finished all tasks in " << clk << "\n"; + // std::cout << "Band used " << settings::band << "\n\n\n"; +} // From 9a878dd21f6b388173e3b5ee87f35648a024b03e Mon Sep 17 00:00:00 2001 From: Volkan Kumtepeli Date: Tue, 18 Oct 2022 17:54:27 +0100 Subject: [PATCH 2/7] Gurobi C++ --- CMakeLists.txt | 4 ++-- headers_defines_file | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 headers_defines_file diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ccce51..0b06eb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,12 +65,12 @@ message(STATUS "GUROBI LIBRARY START") message(STATUS ${GUROBI_LIBRARY}) message(STATUS "GUROBI LIBRARY END") -file(GLOB SRC_FILES +file(GLOB GRB_SRC_FILES $ENV{GUROBI_HOME}/src/cpp/*.h $ENV{GUROBI_HOME}/src/cpp/*.cpp ) -foreach(header ${HEADERS_FILES}) +foreach(header ${GRB_SRC_FILES}) # here replace / for linux and \ for windows string(REPLACE "/" "_" header_path header) string(TOUPPER header_path final_header_path) diff --git a/headers_defines_file b/headers_defines_file new file mode 100644 index 0000000..f68a0db --- /dev/null +++ b/headers_defines_file @@ -0,0 +1 @@ +definePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/header \ No newline at end of file From 8abcdaaa4709f9cfac5d061c79dbc16e9f805315 Mon Sep 17 00:00:00 2001 From: Volkan Kumtepeli Date: Wed, 19 Oct 2022 00:14:47 +0100 Subject: [PATCH 3/7] Gurobi in C++ is working now! --- CMakeLists.txt | 19 +++--- dtwc/dataTypes.hpp | 1 + dtwc/main.cpp | 143 +++++++++++++++++++++------------------ headers_defines_file | 1 - matlab/findBestMedoids.m | 1 - matlab/test_MIP.m | 11 +++ 6 files changed, 97 insertions(+), 79 deletions(-) delete mode 100644 headers_defines_file create mode 100644 matlab/test_MIP.m diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b06eb6..8fc16d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,6 @@ add_library(project_warnings INTERFACE) add_library(project_options INTERFACE) target_compile_features(project_options INTERFACE cxx_std_20) -target_compile_definitions(dtwc++ PRIVATE ROOT_FOLDER="${PROJECT_SOURCE_DIR}") if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") option(ENABLE_BUILD_WITH_TIME_TRACE "Enable -ftime-trace to generate time tracing .json files on clang" OFF) @@ -65,29 +64,29 @@ message(STATUS "GUROBI LIBRARY START") message(STATUS ${GUROBI_LIBRARY}) message(STATUS "GUROBI LIBRARY END") + +string(REPLACE "\\" "/" GRB_HOME $ENV{GUROBI_HOME}) + file(GLOB GRB_SRC_FILES - $ENV{GUROBI_HOME}/src/cpp/*.h - $ENV{GUROBI_HOME}/src/cpp/*.cpp + ${GRB_HOME}/src/cpp/*.h + ${GRB_HOME}/src/cpp/*.cpp ) foreach(header ${GRB_SRC_FILES}) # here replace / for linux and \ for windows - string(REPLACE "/" "_" header_path header) - string(TOUPPER header_path final_header_path) - file(APPEND headers_defines_file define - PATH_${final_header_path} ${CMAKE_CURRENT_SOURCE_DIR}/header) + message(STATUS ${header}) endforeach(header) add_executable(dtwc++ dtwc/main.cpp - ${SRC_FILES} + ${GRB_SRC_FILES} ) target_link_libraries(dtwc++ PRIVATE project_warnings project_options - PUBLIC - ${GUROBI_CXX_LIBRARY} ${GUROBI_LIBRARY} ) + +target_compile_definitions(dtwc++ PRIVATE ROOT_FOLDER="${PROJECT_SOURCE_DIR}") diff --git a/dtwc/dataTypes.hpp b/dtwc/dataTypes.hpp index f95e7a7..fa01e7c 100644 --- a/dtwc/dataTypes.hpp +++ b/dtwc/dataTypes.hpp @@ -22,6 +22,7 @@ class VecMatrix VecMatrix(VarType m_) : m(m_), n(m_), data(m_ * m_) {} // Sequare matrix VecMatrix(VarType m_, VarType n_) : m(m_), n(n_), data(m_ * n_) {} VecMatrix(VarType m_, VarType n_, Tdata x) : m(m_), n(n_), data(m_ * n_, x) {} + VecMatrix(VarType m_, VarType n_, std::vector &&vec) : m(m_), n(n_), data(std::move(vec)) {} inline void resize(VarType m_, VarType n_, Tdata x = 0) { diff --git a/dtwc/main.cpp b/dtwc/main.cpp index 56c98d7..5a4df78 100644 --- a/dtwc/main.cpp +++ b/dtwc/main.cpp @@ -1,5 +1,5 @@ #include "dtwc.hpp" -#include +#include "gurobi_c++.h" #include #include @@ -7,9 +7,46 @@ #include #include #include +#include -int main(){ +int main() +{ + + using namespace dtwc; + dtwc::Clock clk; + int Ndata_max = 10; // Load 10 data maximum. + + auto [p_vec, p_names] = load_data(settings::path, Ndata_max); + + std::cout << "Data loading finished at " << clk << "\n"; + + dtwc::VecMatrix DTWdist(p_vec.size(), p_vec.size(), -1); // For distance memoization. + + // readMatrix(DTWdist, "../matlab/DTWdist_band_all.csv"); // Comment out if recalculating + + auto DTWdistByInd = [&DTWdist, p_vec = p_vec](int i, int j) { + if (DTWdist(i, j) < 0) { + if constexpr (settings::band == 0) { + DTWdist(j, i) = DTWdist(i, j) = dtwFun_L(p_vec[i], p_vec[j]); + } else { + DTWdist(j, i) = DTWdist(i, j) = dtwFunBanded_Act(p_vec[i], p_vec[j], settings::band); // dtwFunBanded_Act_L faster and more accurate. + } + } + return DTWdist(i, j); + }; + + fillDistanceMatrix(DTWdistByInd, p_vec.size()); // Otherwise takes time. + + std::string DistMatrixName = "DTW_matrix.csv"; + writeMatrix(DTWdist, DistMatrixName); + // DTWdist.print(); + std::cout << "Finished all tasks in " << clk << "\n"; + std::cout << "Band used " << settings::band << "\n\n\n"; + + + auto Nb = p_vec.size(); + int Nc = 4; try { GRBEnv env = GRBEnv(); @@ -18,56 +55,59 @@ int main(){ // Create variables - GRBVar x = model.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "x"); - GRBVar y = model.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "y"); - GRBVar z = model.addVar(0.0, GRB_INFINITY, 0.0, GRB_CONTINUOUS, "z"); + std::vector w_vec, isCluster; + w_vec.reserve(Nb * Nb); + isCluster.reserve(Nb); - // Set objective + for (size_t i{ 0 }; i < (Nb * Nb); i++) + w_vec.push_back(model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "")); - GRBLinExpr obj = x; - model.setObjective(obj, GRB_MAXIMIZE); + for (size_t i{ 0 }; i < Nb; i++) + isCluster.push_back(model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "")); - // Add linear constraint: x + y + z <= 10 - model.addConstr(x + y + z <= 10, "c0"); + dtwc::VecMatrix w(Nb, Nb, std::move(w_vec)); - // Add bilinear inequality constraint: x * y <= 2 - model.addQConstr(x * y <= 2, "bilinear0"); + for (size_t i{ 0 }; i < Nb; i++) { + GRBLinExpr lhs = 0; + for (size_t j{ 0 }; j < Nb; j++) { + lhs += w(j, i); + } + model.addConstr(lhs, '=', 1.0); + } - // Add bilinear equality constraint: y * z == 1 + for (size_t i{ 0 }; i < Nb; i++) + for (size_t j{ 0 }; j < Nb; j++) + model.addConstr(w(i, j) <= isCluster[i]); - model.addQConstr(x * z + y * z == 1, "bilinear1"); - // First optimize() call will fail - need to set NonConvex to 2 + { + GRBLinExpr lhs = 0; + for (size_t i{ 0 }; i < Nb; i++) + lhs += isCluster[i]; - try { - model.optimize(); - assert(0); - } catch (GRBException e) { - std::cout << "Failed (as expected)" << std::endl; + model.addConstr(lhs == Nc); // There should be Nc clusters. } - model.set(GRB_IntParam_NonConvex, 2); - model.optimize(); - std::cout << x.get(GRB_StringAttr_VarName) << " " - << x.get(GRB_DoubleAttr_X) << std::endl; - std::cout << y.get(GRB_StringAttr_VarName) << " " - << y.get(GRB_DoubleAttr_X) << std::endl; - std::cout << z.get(GRB_StringAttr_VarName) << " " - << z.get(GRB_DoubleAttr_X) << std::endl; + // Set objective + + GRBLinExpr obj = 0; + for (size_t i{ 0 }; i < Nb; i++) + for (size_t j{ 0 }; j < Nb; j++) + obj += w(i, j) * DTWdistByInd(i, j); + + model.setObjective(obj, GRB_MINIMIZE); + + // First optimize() call will fail - need to set NonConvex to 2 - // Constrain x to be integral and solve again - x.set(GRB_CharAttr_VType, GRB_INTEGER); model.optimize(); - std::cout << x.get(GRB_StringAttr_VarName) << " " - << x.get(GRB_DoubleAttr_X) << std::endl; - std::cout << y.get(GRB_StringAttr_VarName) << " " - << y.get(GRB_DoubleAttr_X) << std::endl; - std::cout << z.get(GRB_StringAttr_VarName) << " " - << z.get(GRB_DoubleAttr_X) << std::endl; + for (auto &v_i : isCluster) + std::cout << v_i.get(GRB_StringAttr_VarName) << " " + << v_i.get(GRB_DoubleAttr_X) << '\n'; + std::cout << "Obj: " << model.get(GRB_DoubleAttr_ObjVal) << std::endl; @@ -79,35 +119,4 @@ int main(){ } - - // using namespace dtwc; - // dtwc::Clock clk; - // int Ndata_max = 10; // Load 10 data maximum. - - // auto [p_vec, p_names] = load_data(settings::path, Ndata_max); - - // std::cout << "Data loading finished at " << clk << "\n"; - - // dtwc::VecMatrix DTWdist(p_vec.size(), p_vec.size(), -1); // For distance memoization. - - // // readMatrix(DTWdist, "../matlab/DTWdist_band_all.csv"); // Comment out if recalculating - - // auto DTWdistByInd = [&DTWdist, p_vec = p_vec](int i, int j) { - // if (DTWdist(i, j) < 0) { - // if constexpr (settings::band == 0) { - // DTWdist(j, i) = DTWdist(i, j) = dtwFun_L(p_vec[i], p_vec[j]); - // } else { - // DTWdist(j, i) = DTWdist(i, j) = dtwFunBanded_Act(p_vec[i], p_vec[j], settings::band); // dtwFunBanded_Act_L faster and more accurate. - // } - // } - // return DTWdist(i, j); - // }; - - // fillDistanceMatrix(DTWdistByInd, p_vec.size()); // Otherwise takes time. - - // std::string DistMatrixName = "DTW_matrix.csv"; - // writeMatrix(DTWdist, DistMatrixName); - // // DTWdist.print(); - // std::cout << "Finished all tasks in " << clk << "\n"; - // std::cout << "Band used " << settings::band << "\n\n\n"; } // diff --git a/headers_defines_file b/headers_defines_file deleted file mode 100644 index f68a0db..0000000 --- a/headers_defines_file +++ /dev/null @@ -1 +0,0 @@ -definePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/headerdefinePATH_HEADER_PATHC:/Users/laengs2321/Documents/git/dtw-cpp/header \ No newline at end of file diff --git a/matlab/findBestMedoids.m b/matlab/findBestMedoids.m index b109ca3..1c5fd15 100644 --- a/matlab/findBestMedoids.m +++ b/matlab/findBestMedoids.m @@ -5,7 +5,6 @@ isCluster = binvar(Nb,1); F = []; % Constraints -%F = [F, 0 <= w <= 1]; F = [F, sum(w,1) == 1]; % Only one cluster can be assigned. F = [F, w <= repmat(isCluster,1,Nb)]; % if w of ith data is activated then it is a cluster. diff --git a/matlab/test_MIP.m b/matlab/test_MIP.m new file mode 100644 index 0000000..564dea4 --- /dev/null +++ b/matlab/test_MIP.m @@ -0,0 +1,11 @@ +% This is a test function. Please do not use it. + +clear variables; close all; clc; + + +distanceMat = readmatrix('../results/DTW_matrix.csv'); +assert(size(distanceMat,1) == size(distanceMat,2)); % See if it is square + +sol = findBestMedoids(distanceMat, 4); + +fprintf('Cost: %4.6f\n',sol.cost); \ No newline at end of file From e6398f80d78023b13f4afb8ac3ac5fbb49a42b21 Mon Sep 17 00:00:00 2001 From: Volkan Kumtepeli Date: Wed, 19 Oct 2022 00:23:56 +0100 Subject: [PATCH 4/7] DTW in C++ works however parsing takes very very long time (39 sec - 50 vars) --- dtwc/main.cpp | 8 +++++--- matlab/findBestMedoids.m | 9 +++++++-- matlab/test_MIP.m | 5 ++++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/dtwc/main.cpp b/dtwc/main.cpp index 5a4df78..cffc592 100644 --- a/dtwc/main.cpp +++ b/dtwc/main.cpp @@ -15,7 +15,7 @@ int main() using namespace dtwc; dtwc::Clock clk; - int Ndata_max = 10; // Load 10 data maximum. + int Ndata_max = 100; // Load 10 data maximum. auto [p_vec, p_names] = load_data(settings::path, Ndata_max); @@ -41,7 +41,7 @@ int main() std::string DistMatrixName = "DTW_matrix.csv"; writeMatrix(DTWdist, DistMatrixName); // DTWdist.print(); - std::cout << "Finished all tasks in " << clk << "\n"; + std::cout << "Finished calculating distances " << clk << "\n"; std::cout << "Band used " << settings::band << "\n\n\n"; @@ -101,7 +101,7 @@ int main() model.setObjective(obj, GRB_MINIMIZE); // First optimize() call will fail - need to set NonConvex to 2 - + std::cout << "Finished setting up the MILP problem " << clk << "\n"; model.optimize(); for (auto &v_i : isCluster) @@ -118,5 +118,7 @@ int main() std::cout << "Exception during optimization" << std::endl; } + std::cout << "Finished all tasks " << clk << "\n"; + } // diff --git a/matlab/findBestMedoids.m b/matlab/findBestMedoids.m index 1c5fd15..af7d37e 100644 --- a/matlab/findBestMedoids.m +++ b/matlab/findBestMedoids.m @@ -1,4 +1,9 @@ -function sol = findBestMedoids(distanceMat, Nc) +function sol = findBestMedoids(distanceMat, Nc, verbosity) + +if(nargin<3) + verbosity = 0; +end + Nb = length(distanceMat); % Number of batteries. w = binvar(Nb, Nb, 'full'); @@ -13,7 +18,7 @@ cost = sum(w.*distanceMat,'all'); -yalmipStr = optimize(F,cost,sdpsettings('verbose',0,'gurobi.MIPGap',1e-6)); +yalmipStr = optimize(F,cost,sdpsettings('verbose',verbosity,'gurobi.MIPGap',1e-6)); %% sol.yalmipStr = yalmipStr; diff --git a/matlab/test_MIP.m b/matlab/test_MIP.m index 564dea4..e662485 100644 --- a/matlab/test_MIP.m +++ b/matlab/test_MIP.m @@ -6,6 +6,9 @@ distanceMat = readmatrix('../results/DTW_matrix.csv'); assert(size(distanceMat,1) == size(distanceMat,2)); % See if it is square -sol = findBestMedoids(distanceMat, 4); +tic; +sol = findBestMedoids(distanceMat, 4, 2); + +toc fprintf('Cost: %4.6f\n',sol.cost); \ No newline at end of file From cd32be87153fd83e50dfc5d648f45b80072de0b7 Mon Sep 17 00:00:00 2001 From: Volkan Kumtepeli Date: Wed, 19 Oct 2022 00:32:12 +0100 Subject: [PATCH 5/7] Using GRBVar pointer to allocate variables instead of vectors. --- dtwc/main.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/dtwc/main.cpp b/dtwc/main.cpp index cffc592..d3e035c 100644 --- a/dtwc/main.cpp +++ b/dtwc/main.cpp @@ -55,17 +55,14 @@ int main() // Create variables - std::vector w_vec, isCluster; + GRBVar *isCluster = model.addVars(Nb, GRB_BINARY); + + std::vector w_vec; w_vec.reserve(Nb * Nb); - isCluster.reserve(Nb); for (size_t i{ 0 }; i < (Nb * Nb); i++) w_vec.push_back(model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "")); - for (size_t i{ 0 }; i < Nb; i++) - isCluster.push_back(model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "")); - - dtwc::VecMatrix w(Nb, Nb, std::move(w_vec)); @@ -104,9 +101,9 @@ int main() std::cout << "Finished setting up the MILP problem " << clk << "\n"; model.optimize(); - for (auto &v_i : isCluster) - std::cout << v_i.get(GRB_StringAttr_VarName) << " " - << v_i.get(GRB_DoubleAttr_X) << '\n'; + for (size_t i{ 0 }; i < Nb; i++) + std::cout << isCluster[i].get(GRB_StringAttr_VarName) << " " + << isCluster[i].get(GRB_DoubleAttr_X) << '\n'; std::cout << "Obj: " << model.get(GRB_DoubleAttr_ObjVal) << std::endl; From 79c44d153ad4b9341025ad63311a9cc99485c15a Mon Sep 17 00:00:00 2001 From: Volkan Kumtepeli Date: Wed, 19 Oct 2022 00:54:00 +0100 Subject: [PATCH 6/7] okay it is not parsing but DTW takes time :)) --- dtwc/main.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dtwc/main.cpp b/dtwc/main.cpp index d3e035c..a02ce73 100644 --- a/dtwc/main.cpp +++ b/dtwc/main.cpp @@ -56,28 +56,25 @@ int main() // Create variables GRBVar *isCluster = model.addVars(Nb, GRB_BINARY); - - std::vector w_vec; - w_vec.reserve(Nb * Nb); - - for (size_t i{ 0 }; i < (Nb * Nb); i++) - w_vec.push_back(model.addVar(0.0, 1.0, 0.0, GRB_BINARY, "")); - - dtwc::VecMatrix w(Nb, Nb, std::move(w_vec)); + GRBVar *w = model.addVars(Nb * Nb, GRB_BINARY); + std::cout << "Finished creating w and is Cluster " << clk << "\n"; for (size_t i{ 0 }; i < Nb; i++) { GRBLinExpr lhs = 0; for (size_t j{ 0 }; j < Nb; j++) { - lhs += w(j, i); + lhs += w[j + i * Nb]; } model.addConstr(lhs, '=', 1.0); } + std::cout << "Finished Only one cluster can be assigned " << clk << "\n"; - for (size_t i{ 0 }; i < Nb; i++) - for (size_t j{ 0 }; j < Nb; j++) - model.addConstr(w(i, j) <= isCluster[i]); + for (size_t j{ 0 }; j < Nb; j++) + for (size_t i{ 0 }; i < Nb; i++) + model.addConstr(w[i + j * Nb] <= isCluster[i]); + + std::cout << "Finished if w of ith data is activated then it is a cluster. " << clk << "\n"; { GRBLinExpr lhs = 0; @@ -86,14 +83,17 @@ int main() model.addConstr(lhs == Nc); // There should be Nc clusters. } + std::cout << "Finished There should be Nc clusters. " << clk << "\n"; // Set objective GRBLinExpr obj = 0; - for (size_t i{ 0 }; i < Nb; i++) - for (size_t j{ 0 }; j < Nb; j++) - obj += w(i, j) * DTWdistByInd(i, j); + for (size_t j{ 0 }; j < Nb; j++) + for (size_t i{ 0 }; i < Nb; i++) + obj += w[i + j * Nb] * DTWdistByInd(i, j); + + std::cout << "Finished OBJ. " << clk << "\n"; model.setObjective(obj, GRB_MINIMIZE); From 0c9c83061cdb934ca04b4bec0482b8c4682d61c5 Mon Sep 17 00:00:00 2001 From: Volkan Kumtepeli Date: Wed, 19 Oct 2022 01:16:10 +0100 Subject: [PATCH 7/7] added delete --- dtwc/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dtwc/main.cpp b/dtwc/main.cpp index a02ce73..8f22231 100644 --- a/dtwc/main.cpp +++ b/dtwc/main.cpp @@ -108,6 +108,11 @@ int main() std::cout << "Obj: " << model.get(GRB_DoubleAttr_ObjVal) << std::endl; + + delete[] isCluster; + delete[] w; + + } catch (GRBException e) { std::cout << "Error code = " << e.getErrorCode() << std::endl; std::cout << e.getMessage() << std::endl;