Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 49 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,19 @@ 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)

# Link this 'library' to set the c++ standard / compile-time options requested
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")
option(ENABLE_BUILD_WITH_TIME_TRACE "Enable -ftime-trace to generate time tracing .json files on clang" OFF)
Expand All @@ -35,8 +30,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)
Expand All @@ -52,3 +52,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")


string(REPLACE "\\" "/" GRB_HOME $ENV{GUROBI_HOME})

file(GLOB GRB_SRC_FILES
${GRB_HOME}/src/cpp/*.h
${GRB_HOME}/src/cpp/*.cpp
)

foreach(header ${GRB_SRC_FILES})
# here replace / for linux and \ for windows
message(STATUS ${header})
endforeach(header)

add_executable(dtwc++
dtwc/main.cpp
${GRB_SRC_FILES}
)

target_link_libraries(dtwc++
PRIVATE
project_warnings
project_options
${GUROBI_LIBRARY}
)

target_compile_definitions(dtwc++ PRIVATE ROOT_FOLDER="${PROJECT_SOURCE_DIR}")
45 changes: 45 additions & 0 deletions cmake/CMakeLists_forGurobi.txt
Original file line number Diff line number Diff line change
@@ -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()
55 changes: 55 additions & 0 deletions cmake/FindGUROBI.cmake
Original file line number Diff line number Diff line change
@@ -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)
1 change: 1 addition & 0 deletions dtwc/dataTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Tdata> &&vec) : m(m_), n(n_), data(std::move(vec)) {}

inline void resize(VarType m_, VarType n_, Tdata x = 0)
{
Expand Down
91 changes: 87 additions & 4 deletions dtwc/main.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
#include "dtwc.hpp"
#include "gurobi_c++.h"

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cmath>
#include <random>
#include <string>
#include <vector>


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<Tdata, true>(settings::path, Ndata_max);

Expand All @@ -38,6 +41,86 @@ 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";
}


auto Nb = p_vec.size();
int Nc = 4;

try {
GRBEnv env = GRBEnv();

GRBModel model = GRBModel(env);

// Create variables

GRBVar *isCluster = model.addVars(Nb, GRB_BINARY);
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 * Nb];
}
model.addConstr(lhs, '=', 1.0);
}
std::cout << "Finished Only one cluster can be assigned " << clk << "\n";


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;
for (size_t i{ 0 }; i < Nb; i++)
lhs += isCluster[i];

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 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);

// First optimize() call will fail - need to set NonConvex to 2
std::cout << "Finished setting up the MILP problem " << clk << "\n";
model.optimize();

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;


delete[] isCluster;
delete[] w;


} 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;
}

std::cout << "Finished all tasks " << clk << "\n";


} //
10 changes: 7 additions & 3 deletions matlab/findBestMedoids.m
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
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');

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.

Expand All @@ -14,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;
Expand Down
14 changes: 14 additions & 0 deletions matlab/test_MIP.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
% 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

tic;
sol = findBestMedoids(distanceMat, 4, 2);

toc

fprintf('Cost: %4.6f\n',sol.cost);