Commit 11c1a153 authored by Pavel Smirnov's avatar Pavel Smirnov

added multithreading

parent 9652a5f7
......@@ -3,7 +3,6 @@ MINPSC_PATH=tools/minpsc
all:
make build
make test
rebuild:
rm -rf $(GRID_BUILDER_PATH)/CMakeCache.txt
......@@ -16,7 +15,7 @@ rebuild:
make build
build: grid_builder minpsc
build: minpsc
grid_builder:
cmake -B'$(GRID_BUILDER_PATH)' -H'$(GRID_BUILDER_PATH)'
......
......@@ -4,9 +4,6 @@
#include <unordered_map>
#include <omp.h>
#include <ilcplex/ilocplex.h>
using namespace std;
static wval CalcSolutionUBound(const Graph& g) {
......@@ -17,7 +14,7 @@ static wval CalcSolutionUBound(const Graph& g) {
return solution_ubound;
}
static Graph BuildReducedGraph(const Graph& g) {
static void BuildReducedGraph(Graph& g) {
wval solution_ubound = CalcSolutionUBound(g);
vector<wval> lbounds = CalcLB(g);
wval solution_lbound = 0;
......@@ -37,19 +34,18 @@ static Graph BuildReducedGraph(const Graph& g) {
cout << "(" << edges_in_graph << "/" << n*(n-1)/2 << " edges left) " << endl;
for (size_t v = 0; v < n; ++v)
rg.SortEdges(v);
return rg;
g = rg;
}
static pair<Graph, Graph> BuildLBGraph(const Graph& rg) {
size_t n = rg.Size();
Graph ga(n);
Graph gainv(n);
for (size_t v = 0; v < n; ++v) {
const Edge & e = rg.GetEdges(v)[0];
ga.AddOrientedEdge(v, e.to, wval(0));
gainv.AddOrientedEdge(e.to, v, wval(0));
static pair<Graph, Graph> BuildLBGraph(const Graph& reduced_graph) {
Graph graph_a(reduced_graph.Size());
Graph graph_a_inv(reduced_graph.Size());
for (size_t v = 0; v < reduced_graph.Size(); ++v) {
const Edge& e = reduced_graph.GetEdges(v)[0];
graph_a.AddOrientedEdge(v, e.to, wval(0));
graph_a_inv.AddOrientedEdge(e.to, v, wval(0));
}
return {ga, gainv};
return {graph_a, graph_a_inv};
}
static unordered_map<size_t, IloNumVar> AddObjectiveAndVariablesY(
......@@ -246,40 +242,29 @@ static void AddAllOptimizations(
AddOptimization25(env, model, rg, yMapping);
}
wval CplexEx1Connect(const Graph& g, size_t s, unordered_map<string, size_t>& info) {
if (g.Size() <= 1) {
return 0;
}
Graph rg = BuildReducedGraph(g);
size_t edgesLeft = 0;
for (size_t v = 0; v < rg.Size(); ++v) {
edgesLeft += rg.GetEdges(v).size();
}
edgesLeft /= 2;
info["EdgesLeft"] = edgesLeft;
void CplexEx1Solver::Transform(bool optimize) {
BuildReducedGraph(_graph);
pair<Graph, Graph> lb_graphs = BuildLBGraph(rg); // for opt 23, 24
const auto& ga = lb_graphs.first;
const auto& gainv = lb_graphs.second;
auto lb_graphs = BuildLBGraph(_graph); // for opt 23, 24
const auto& graph_a = lb_graphs.first;
const auto& graph_a_inv = lb_graphs.second;
IloEnv env;
IloModel model(env);
auto y_mapping = AddObjectiveAndVariablesY(_env, _model, _graph);
AddAllOptimizations(_env, _model, _graph, graph_a, graph_a_inv, y_mapping);
auto yMapping = AddObjectiveAndVariablesY(env, model, rg);
AddAllOptimizations(env, model, rg, ga, gainv, yMapping);
auto xMapping = AddVariablesX(env, rg);
AddEx1Restrictions(env, model, rg, yMapping, xMapping, s);
auto x_mapping = AddVariablesX(_env, _graph);
AddEx1Restrictions(_env, _model, _graph, y_mapping, x_mapping, _start_vertex);
}
IloCplex cplex(env);
cplex.setOut(env.getNullStream());
wval CplexEx1Solver::Solve() {
IloCplex cplex(_env);
cplex.setOut(_env.getNullStream());
cplex.extract(model);
cplex.extract(_model);
cplex.solve();
wval result = cplex.getObjValue();
env.end();
_env.end();
return result;
}
......@@ -357,48 +342,37 @@ void AddNewEx2Restriction(
}
}
wval CplexEx2Connect(const Graph& g, unordered_map<string, size_t>& info) {
if (g.Size() <= 1) {
return 0;
}
Graph rg = BuildReducedGraph(g);
void CplexEx2Solver::Transform(bool optimize) {
BuildReducedGraph(_graph);
size_t edgesLeft = 0;
for (size_t v = 0; v < rg.Size(); ++v) {
edgesLeft += rg.GetEdges(v).size();
}
edgesLeft /= 2;
info["EdgesLeft"] = edgesLeft;
auto lb_graphs = BuildLBGraph(_graph); // for opt 23, 24
const auto& graph_a = lb_graphs.first;
const auto& graph_a_inv = lb_graphs.second;
pair<Graph, Graph> lb_graphs = BuildLBGraph(rg); // for opt 23, 24
const auto& ga = lb_graphs.first;
const auto& gainv = lb_graphs.second;
_y_mapping = AddObjectiveAndVariablesY(_env, _model, _graph);
AddAllOptimizations(_env, _model, _graph, graph_a, graph_a_inv, _y_mapping);
IloEnv env;
IloModel model(env);
auto yMapping = AddObjectiveAndVariablesY(env, model, rg);
AddAllOptimizations(env, model, rg, ga, gainv, yMapping);
auto zMapping = AddVariablesZ(env, rg);
AddEx2BaseRestrictions(env, model, rg, yMapping, zMapping);
_z_mapping = AddVariablesZ(_env, _graph);
AddEx2BaseRestrictions(_env, _model, _graph, _y_mapping, _z_mapping);
}
IloCplex cplex(env);
cplex.setOut(env.getNullStream());
wval CplexEx2Solver::Solve() {
IloCplex cplex(_env);
cplex.setOut(_env.getNullStream());
for (size_t iterations = 0;; ++iterations) {
cplex.extract(model);
cplex.extract(_model);
cplex.solve();
vector<vector<size_t>> components = FindIsolatedComponents(rg, cplex, yMapping);
vector<vector<size_t>> components = FindIsolatedComponents(_graph, cplex, _y_mapping);
if (components.size() == 1) {
cout << iterations << " restrictions were added" << endl;
break;
}
AddNewEx2Restriction(env, model, rg, components, zMapping);
AddNewEx2Restriction(_env, _model, _graph, components, _z_mapping);
}
wval result = cplex.getObjValue();
env.end();
_env.end();
return result;
}
#ifndef CPLEX_CONNECT_H
#define CPLEX_CONNECT_H
#include "solver.h"
#include "graph.h"
#include "numeric.h"
#include <string>
#include <unordered_map>
#define IL_STD
#include <ilcplex/ilocplex.h>
void ToCplexEx1(const Graph& g, const std::string output_file, size_t s, bool optimize);
wval CplexEx1Connect(const Graph& g, size_t s, std::unordered_map<std::string, size_t>& info);
class CplexSolver : public Solver {
public:
CplexSolver()
: _env()
, _model(_env)
{}
protected:
IloEnv _env;
IloModel _model;
};
class CplexEx1Solver : public CplexSolver {
public:
CplexEx1Solver(size_t start_vertex)
: _start_vertex(start_vertex)
{}
void Transform(bool optimize);
wval Solve();
private:
size_t _start_vertex;
};
class CplexEx2Solver : public CplexSolver {
public:
CplexEx2Solver() {}
wval CplexEx2Connect(const Graph& g, std::unordered_map<std::string, size_t>& info);
void Transform(bool optimize);
wval Solve();
private:
std::unordered_map<size_t, IloNumVar> _y_mapping;
std::unordered_map<size_t, IloNumVar> _z_mapping;
};
#endif
This diff is collapsed.
#ifndef DP_CONNECT_H
#define DP_CONNECT_H
#include "solver.h"
#include "numeric.h"
#include "graph.h"
......@@ -8,13 +9,30 @@
#include <random>
#include <unordered_map>
wval DpConnect(
const Graph& g,
const std::vector<wval>& lbounds,
double eps,
std::default_random_engine& engine,
bool preprocess,
std::unordered_map<std::string, size_t>& info
);
class DpSolver : public Solver {
public:
DpSolver(double eps, size_t seed, size_t threads_num)
: _eps(eps)
, _random_engine(seed)
, _threads_num(threads_num)
, _transformed(false)
, _optimize(false)
{}
void Transform(bool optimize);
wval Solve();
private:
double _eps;
std::default_random_engine _random_engine;
size_t _threads_num;
bool _optimize;
bool _transformed;
std::vector<wval> _lowerbounds;
std::vector<std::vector<size_t>> _comps;
wval _solution_upperbound;
wval _lost_answer;
};
#endif
......@@ -18,6 +18,8 @@ struct Edge {
class Graph {
public:
Graph() : Graph(0) {}
Graph(size_t size);
void AddEdge(size_t u, size_t v, wval w);
......
......@@ -35,9 +35,11 @@ bool NextSubset(vector<size_t> & subset, size_t set_size) {
return true;
}
}
} // anonymous
wval SlowSolver::Solve() {
auto& g = _graph;
wval SlowConnect(const Graph& g) {
size_t n = g.Size();
if (n <= 1) {
......@@ -87,7 +89,14 @@ wval SlowConnect(const Graph& g) {
return best_solution;
}
wval SlowerConnect(const Graph & g, const vector<wval> & lbounds) {
void SlowerSolver::Transform(bool) {
_lowerbounds = CalcLB(_graph);
}
wval SlowerSolver::Solve() {
auto& g = _graph;
auto& lbounds = _lowerbounds;
size_t n = g.Size();
if (n <= 1)
......
#ifndef SLOW_CONNECT_H
#define SLOW_CONNECT_H
#include "solver.h"
#include "numeric.h"
#include "graph.h"
#include <vector>
wval SlowConnect(const Graph& g);
class SlowSolver : public Solver {
public:
SlowSolver() {}
void Transform(bool) {}
wval Solve();
};
wval SlowerConnect(const Graph& g, const std::vector<wval>& lbounds);
class SlowerSolver : public Solver {
public:
SlowerSolver() {}
void Transform(bool optimize);
wval Solve();
private:
std::vector<wval> _lowerbounds;
};
#endif
#ifndef SOLVER_H
#define SOLVER_H
#include "numeric.h"
#include "graph.h"
#include <string>
class Solver {
public:
bool SetGraph(const std::string& file_name) {
Graph graph = ReadGraph(file_name);
_graph = graph;
if (_graph.FindComponents().size() > 1) {
return false;
}
return true;
}
size_t GetEdgesNum() {
size_t edges_num = 0;
for (size_t v = 0; v < _graph.Size(); ++v) {
edges_num += _graph.GetEdges(v).size();
}
edges_num /= 2;
return edges_num;
}
size_t GetVerticesNum() {
return _graph.Size();
}
virtual void Transform(bool optimize) = 0;
virtual wval Solve() = 0;
protected:
Graph _graph;
};
#endif
......@@ -6,6 +6,15 @@ set(LIB_DIR ../../lib)
include_directories(${LIB_DIR})
add_subdirectory(${LIB_DIR} ${LIB_DIR})
set(CPLEXDIR "/opt/ibm/ILOG/CPLEX_Studio128/cplex")
set(CONCERTDIR "/opt/ibm/ILOG/CPLEX_Studio128/concert")
set(CONCERTINCDIR "${CONCERTDIR}/include")
set(CPLEXINCDIR "${CPLEXDIR}/include")
set(CCINCDIRS "-I${CPLEXINCDIR} -I${CONCERTINCDIR}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -O3 ${CCINCDIRS}")
set(MINPSC_SRCS minpsc.cpp)
add_executable(minpsc "${MINPSC_SRCS}")
......
......@@ -5,25 +5,26 @@
#include <dp_connect.h>
#include <slow_connect.h>
#include <cplex_connect.h>
#include <solver.h>
#include <algorithm_exception.h>
#include <iostream>
#include <fstream>
using namespace std;
using random_engine = default_random_engine;
struct SolvingParams {
int Mode;
string LogFile;
string InputFile;
string OutputFile;
double Eps;
int Seed;
int mode;
string log_file;
string input_file;
string output_file;
double eps;
int seed;
int threads_num;
};
void PrintHelpMessageAndExit(int argc, char** argv) {
cout << "To solve with DP:\n";
cout << "\t" << argv[0] << " 0 <logfile> <input file> <output file> <eps> <seed>\n";
cout << "\t" << argv[0] << " 0 <logfile> <input file> <output file> <eps> <seed> <threads_num>\n";
cout << "To solve with first bruteforce:\n";
cout << "\t" << argv[0] << " 1 <logfile> <input file> <output file>\n";
cout << "To solve with second bruteforce:\n";
......@@ -41,122 +42,84 @@ SolvingParams ParseCommandLine(int argc, char** argv) {
if (argc < 3) {
PrintHelpMessageAndExit(argc, argv);
}
params.Mode = atoi(argv[1]);
params.LogFile = argv[2];
if (params.Mode == 0 || params.Mode == 5) {
if (argc != 7) {
params.mode = atoi(argv[1]);
params.log_file = argv[2];
if (params.mode == 0 || params.mode == 5) {
if (argc != 8) {
PrintHelpMessageAndExit(argc, argv);
}
params.InputFile = argv[3];
params.OutputFile = argv[4];
params.Eps = atof(argv[5]);
params.Seed = atoi(argv[6]);
} else if (params.Mode <= 4) {
params.input_file = argv[3];
params.output_file = argv[4];
params.eps = atof(argv[5]);
params.seed = atoi(argv[6]);
params.threads_num = atoi(argv[7]);
} else if (params.mode <= 4) {
if (argc != 5) {
PrintHelpMessageAndExit(argc, argv);
}
params.InputFile = argv[3];
params.OutputFile = argv[4];
params.input_file = argv[3];
params.output_file = argv[4];
} else {
PrintHelpMessageAndExit(argc, argv);
}
return params;
}
void OutputSolution(wval solution, const Graph& graph, string outputFile) {
cout << "Minimal sum = " << solution << endl;
ofstream output(outputFile);
output << solution << endl;
output.close();
}
int main(int argc, char ** argv) {
SolvingParams params = ParseCommandLine(argc, argv);
Timer globalTimer, localTimer;
Graph graph = ReadGraph(params.InputFile);
size_t edgesCount = 0;
for (size_t v = 0; v < graph.Size(); ++v) {
edgesCount += graph.GetEdges(v).size();
Solver* solver;
string solver_token;
if (params.mode == 0 || params.mode == 5) {
solver = new DpSolver(params.eps, params.seed, params.threads_num);
solver_token = ((params.mode == 5) ? "dp_no_opt" : "dp");
} else if (params.mode == 1) {
solver = new SlowerSolver();
solver_token = "slower";
} else if (params.mode == 2) {
solver = new SlowSolver();
solver_token = "slow";
} else if (params.mode == 3) {
solver = new CplexEx1Solver(0);
solver_token = "ex1";
} else if (params.mode == 4) {
solver = new CplexEx2Solver();
solver_token = "ex2";
}
edgesCount /= 2;
if (graph.FindComponents().size() > 1) {
cout << "Graph is not connected." << endl;
return 0;
}
cout << "Graph read in " << localTimer.Check() << " sec" << endl;
localTimer.Zero();
wval solution;
ofstream log(params.LogFile, std::ios_base::app);
unordered_map<string, size_t> info;
if (params.Mode == 0) {
vector<wval> lbounds = CalcLB(graph);
cout << "Lowerbounds found in " << localTimer.Check() << " sec" << endl;
localTimer.Zero();
random_engine engine = random_engine(params.Seed);
solution = DpConnect(graph, lbounds, params.Eps, engine, true, info);
cout << "Answer found in " << localTimer.Check() << " sec" << endl;
localTimer.Zero();
log << "DP ";
} else if (params.Mode == 1) {
vector<wval> lbounds = CalcLB(graph);
cout << "Lowerbounds found in " << localTimer.Check() << " sec" << endl;
localTimer.Zero();
solution = SlowerConnect(graph, lbounds);
cout << "Answer found in " << localTimer.Check() << " sec" << endl;
localTimer.Zero();
log << "Slow ";
} else if (params.Mode == 2) {
solution = SlowConnect(graph);
cout << "Answer found in " << localTimer.Check() << " sec" << endl;
localTimer.Zero();
log << "Slowest ";
} else if (params.Mode == 3) {
solution = CplexEx1Connect(graph, 0, info);
cout << "Answer found in " << localTimer.Check() << " sec" << endl;
localTimer.Zero();
log << "CPLEX_EX1 ";
} else if (params.Mode == 4) {
solution = CplexEx2Connect(graph, info);
cout << "Answer found in " << localTimer.Check() << " sec" << endl;
localTimer.Zero();
log << "CPLEX_EX2 ";
} else if (params.Mode == 5) {
vector<wval> lbounds = CalcLB(graph);
cout << "Lowerbounds found in " << localTimer.Check() << " sec" << endl;
localTimer.Zero();
random_engine engine = random_engine(params.Seed);
solution = DpConnect(graph, lbounds, params.Eps, engine, false, info);
cout << "Answer found in " << localTimer.Check() << " sec" << endl;
localTimer.Zero();
log << "DP_no_preprocess ";
if (!solver->SetGraph(params.input_file)) {
throw new AlgorithmException("Graph is incorrect.");
}
OutputSolution(solution, graph, params.OutputFile);
cout << "Problem solved in " << globalTimer.Check() << " sec" << endl;
cout << endl;
log << "N = " << graph.Size() <<
" Time = " << globalTimer.Check() <<
" Ans = " << solution <<
" Edges = " << edgesCount;
for (const auto& infoEntity : info) {
log << " " << infoEntity.first << " = " << infoEntity.second;
}
log << endl;
size_t initial_vert = solver->GetVerticesNum();
size_t initial_edges = solver->GetEdgesNum();
Timer transform_timer;
solver->Transform(/*optimize*/ ((params.mode == 5) ? false : true));
double transform_time = transform_timer.Check();
size_t transformed_vert = solver->GetVerticesNum();
size_t transformed_edges = solver->GetEdgesNum();
Timer solve_timer;
wval answer = solver->Solve();
double solve_time = solve_timer.Check();
delete solver;
ofstream log(params.log_file, std::ios_base::app);
std::stringstream log_info;
log_info << solver_token
<< " initial_vert=" << initial_vert
<< " initial_edges=" << initial_edges
<< " transformed_vert=" << transformed_vert
<< " transformed_edges=" << transformed_edges
<< " transform_time=" << transform_time
<< " solve_time=" << solve_time
<< " answer=" << answer
<< "\n";
(log << log_info.str()).flush();
(std::cout << log_info.str()).flush();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment