提问人:Schrodinger 提问时间:10/27/2023 更新时间:10/27/2023 访问量:51
如何在 C++ 中设置超时并返回结果?[关闭]
How to set a timeout and return the results in C++? [closed]
问:
我是 C++ 的新手,我在 C++ 中遇到了一些需要修改的代码。我有以下脚本如下:
RS.cpp
#include "hypergraph.hpp"
#include "rs.hpp"
#include "mhs-algorithm.hpp"
#include "shd-algorithm.hpp"
#include <cassert>
#include <deque>
#include <omp.h>
#define BOOST_LOG_DYN_LINK 1 // Fix an issue with dynamic library loading
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/dynamic_bitset.hpp>
// TODO: Input specifications with <cassert>
namespace agdmhs {
RSAlgorithm::RSAlgorithm (unsigned num_threads,
unsigned cutoff_size,
bool count_only):
num_threads(num_threads), cutoff_size(cutoff_size), count_only(count_only)
{};
Hypergraph RSAlgorithm::transversal (const Hypergraph& H) const {
// SET UP INTERNAL VARIABLES
// Debugging counters
RSCounters counters;
// Candidate hitting set
Hypergraph::Edge S (H.num_verts());
S.reset(); // Initially empty
// Which edges each vertex is critical for
Hypergraph crit (H.num_edges(), H.num_verts());
// Which edges are uncovered
Hypergraph::Edge uncov (H.num_edges());
uncov.set(); // Initially full
// Which vertices are known to be violating
Hypergraph::Edge violating_vertices (H.num_verts());
// Tranpose of H
Hypergraph T = H.transpose();
// Queue to store hitting sets as they are generated
Hypergraph::EdgeQueue hitting_sets;
// RUN ALGORITHM
{
#pragma omp parallel shared(H, T) num_threads(num_threads) // Don't create thread-local copies of H and T
#pragma omp master // Only spawn the computation once
extend_or_confirm_set(H, T, counters, hitting_sets, S, crit, uncov, violating_vertices);
#pragma omp taskwait // Don't proceed until all the tasks are complete
}
// Gather results
Hypergraph Htrans(H.num_verts());
if (not count_only) {
Hypergraph::Edge result;
while (hitting_sets.try_dequeue(result)) {
Htrans.add_edge(result);
}
}
BOOST_LOG_TRIVIAL(info) << "pRS complete: " << counters.mhses_found << " MHSes found, " << counters.iterations << " iterations, " << counters.violators << " violating verts, " << counters.critical_fails << " critical check failures, " << counters.update_loops << " update loops.";
return Htrans;
};
bool RSAlgorithm::any_edge_critical_after_i(Hypergraph::EdgeIndex i,
const Hypergraph::Edge& S,
const Hypergraph& crit) {
/*
Return true if any vertex in S has its first critical edge
after i.
*/
Hypergraph::EdgeIndex w = S.find_first();
while (w != Hypergraph::Edge::npos) {
Hypergraph::EdgeIndex first_crit_edge = crit[w].find_first();
if (first_crit_edge >= i) {
return true;
}
w = S.find_next(w);
}
return false;
};
void RSAlgorithm::extend_or_confirm_set(const Hypergraph& H,
const Hypergraph& T,
RSCounters& counters,
Hypergraph::EdgeQueue& hitting_sets,
Hypergraph::Edge& S,
Hypergraph& crit,
Hypergraph::Edge& uncov,
const Hypergraph::Edge& violating_vertices) const {
++counters.iterations;
// Input specification
assert(uncov.any()); // uncov cannot be empty
assert(cutoff_size == 0 or S.count() < cutoff_size);
// add my modification
if (hitting_sets.size_approx() > 0) {return;}
// If we're using a cutoff, S must not be too large
// Otherwise, get an uncovered edge
Hypergraph::EdgeIndex search_edge = uncov.find_first(); // Just use the first set in uncov
Hypergraph::Edge e = H[search_edge];
// Store the indices in the edge for iteration
Hypergraph::Edge new_violating_vertices (H.num_verts());
std::deque<Hypergraph::EdgeIndex> search_indices;
Hypergraph::EdgeIndex v = e.find_first();
while (v != Hypergraph::Edge::npos) {
// If v is already known violating, we skip it entirely
bool known_violating = violating_vertices.test(v);
if (not known_violating and vertex_would_violate(crit, uncov, H, T, S, v)) {
// Otherwise, if it would violate, we mark it
new_violating_vertices.set(v);
++counters.violators;
} else if (not known_violating) {
// And if not, we will consider it in the loop
search_indices.push_front(v);
}
v = e.find_next(v);
}
// Loop over vertices in that edge (in reverse order!)
for (auto& v: search_indices) {
++counters.update_loops;
hsetmap critmark = update_crit_and_uncov(crit, uncov, H, T, S, v);
// Check whether any vertex in S has its first critical
// edge after the search edge
if (any_edge_critical_after_i(search_edge, S, crit)) {
++counters.critical_fails;
SHDAlgorithm::restore_crit_and_uncov(crit, uncov, S, critmark, v);
continue;
}
// if new_uncov is empty, adding v to S makes a hitting set
S.set(v);
if (uncov.none()) {
// In this case, S is a valid hitting set, so we store it
++counters.mhses_found;
if (not count_only) {
hitting_sets.enqueue(S);
}
} else if (cutoff_size == 0 or S.count() < cutoff_size) {
// In this case, S is not yet a hitting set but is not too large either
if (counters.tasks_waiting < 4 and uncov.size() > 2) {
// Spawn a new task if the queue is getting low, but
// don't waste time with small jobs.
// Each one gets its own copy of S, CAND, crit, and uncov
++counters.tasks_waiting;
Hypergraph::Edge new_S = S;
Hypergraph new_crit = crit;
Hypergraph::Edge new_uncov = uncov;
Hypergraph::Edge new_viol = violating_vertices | new_violating_vertices;
#pragma omp task shared(H, T, counters, hitting_sets) // Start a new task
{
--counters.tasks_waiting;
extend_or_confirm_set(H, T, counters, hitting_sets, new_S, new_crit, new_uncov, new_viol);
}
} else {
extend_or_confirm_set(H, T, counters, hitting_sets, S, crit, uncov, violating_vertices | new_violating_vertices);
}
}
// Update crit, uncov, and S, then proceed to the next vertex
S.reset(v);
SHDAlgorithm::restore_crit_and_uncov(crit, uncov, S, critmark, v);
}
};
}
rs.hpp
#ifndef _RS__H
#define _RS__H
#include "hypergraph.hpp"
#include "shd-algorithm.hpp"
#include <atomic>
namespace agdmhs {
struct RSCounters {
std::atomic<unsigned> mhses_found {0};
std::atomic<unsigned> iterations {0};
std::atomic<unsigned> violators {0};
std::atomic<unsigned> critical_fails {0};
std::atomic<unsigned> update_loops {0};
std::atomic<unsigned> tasks_waiting {0};
};
class RSAlgorithm: public SHDAlgorithm {
unsigned num_threads;
unsigned cutoff_size;
bool count_only;
public:
RSAlgorithm (unsigned num_threads, unsigned cutoff_size, bool count_only = false);
Hypergraph transversal (const Hypergraph& H) const override;
private:
void extend_or_confirm_set (const Hypergraph& H, const Hypergraph& T, RSCounters& counters, Hypergraph::EdgeQueue& hitting_sets, Hypergraph::Edge& S, Hypergraph& crit, Hypergraph::Edge& uncov, const Hypergraph::Edge& violating_vertices) const;
static bool any_edge_critical_after_i (Hypergraph::EdgeIndex i, const Hypergraph::Edge& S, const Hypergraph& crit);
};
}
#endif
SHD 算法.cpp
#include "hypergraph.hpp"
#include "mhs-algorithm.hpp"
#include "shd-algorithm.hpp"
#define BOOST_LOG_DYN_LINK 1 // Fix an issue with dynamic library loading
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <cassert>
namespace agdmhs {
bool SHDAlgorithm::vertex_would_violate (const Hypergraph& crit,
const Hypergraph::Edge& uncov,
const Hypergraph& H,
const Hypergraph& T,
const Hypergraph::Edge& S,
Hypergraph::EdgeIndex v) const {
/*
Determine whether addition of v to S would violate any vertices.
(That is, whether any vertex in S would be redundant in S+v.)
*/
// Input specification
assert(not S.test(v));
assert(crit[v].none());
// We only consider edges which are hit by v and are not in uncov
Hypergraph::Edge test_edges = T[v] - uncov;
// Check whether any w in S would lose all its critical edges
Hypergraph::EdgeIndex w = S.find_first();
while (w != Hypergraph::Edge::npos) {
if (crit[w].is_subset_of(test_edges)) {
return true;
}
w = S.find_next(w);
}
// If we make it this far, no vertex was violated
return false;
}
SHDAlgorithm::hsetmap SHDAlgorithm::update_crit_and_uncov (Hypergraph& crit,
Hypergraph::Edge& uncov,
const Hypergraph& H,
const Hypergraph& T,
const Hypergraph::Edge& S,
Hypergraph::EdgeIndex v) const {
assert(not S.test(v));
assert(crit[v].none());
const Hypergraph::Edge& v_edges = T[v];
crit[v] = v_edges;
crit[v] &= uncov;
uncov -= v_edges;
hsetmap critmark;
Hypergraph::EdgeIndex w = S.find_first();
while (w != Hypergraph::Edge::npos) {
critmark[w] = crit[w];
critmark[w] &= v_edges;
crit[w] -= v_edges;
w = S.find_next(w);
}
return critmark;
}
void SHDAlgorithm::restore_crit_and_uncov (Hypergraph& crit,
Hypergraph::Edge& uncov,
const Hypergraph::Edge& S,
const hsetmap& critmark,
Hypergraph::EdgeIndex v) const {
assert(not S.test(v));
assert(not uncov.intersects(crit[v]));
uncov |= crit[v];
crit[v].reset();
Hypergraph::EdgeIndex w = S.find_first();
while (w != Hypergraph::Edge::npos) {
try {
crit[w] |= critmark.at(w);
}
catch (std::out_of_range& e) {
// This may occur if a vertex_violating_exception was thrown.
// It's not an error, so we just catch the exception and
// do nothing.
}
w = S.find_next(w);
}
}
}
shd-algorithm.hpp
#ifndef _SHD__H
#define _SHD__H
#include "hypergraph.hpp"
#include "mhs-algorithm.hpp"
#include <map>
namespace agdmhs {
class vertex_violating_exception: public std::exception {
virtual const char* what() const throw() {
return "The vertex was violating for this candidate hitting set.";
}
};
class SHDAlgorithm: public MHSAlgorithm {
protected:
using hsetmap = std::map<Hypergraph::EdgeIndex, Hypergraph::Edge>;
bool vertex_would_violate (const Hypergraph& crit, const Hypergraph::Edge& uncov, const Hypergraph& H, const Hypergraph& T, const Hypergraph::Edge& S, Hypergraph::EdgeIndex v) const;
hsetmap update_crit_and_uncov(Hypergraph& crit, Hypergraph::Edge& uncov, const Hypergraph& H, const Hypergraph& T, const Hypergraph::Edge& S, Hypergraph::EdgeIndex v) const ;
void restore_crit_and_uncov(Hypergraph& crit, Hypergraph::Edge& uncov, const Hypergraph::Edge& S, const hsetmap& critmark, Hypergraph::EdgeIndex v) const;
};
}
#endif
超图.cpp
#include "hypergraph.hpp"
#include <boost/dynamic_bitset.hpp>
#include <boost/filesystem/fstream.hpp>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <vector>
#define BOOST_LOG_DYN_LINK 1 // Fix an issue with dynamic library loading
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
namespace agdmhs {
Hypergraph::Hypergraph (unsigned num_verts,
unsigned num_edges):
_n_verts(num_verts)
{
_edges = Hypergraph::EdgeVector(num_edges, Edge(num_verts));
};
Hypergraph::Hypergraph (const fs::path& input_file)
{
// Set up file reader
fs::ifstream hypergraph_filestream(input_file);
if (!hypergraph_filestream.good()) {
std::stringstream errorMessage;
errorMessage << "Could not open hypergraph file " << input_file << " for reading.";
throw std::runtime_error(errorMessage.str());
}
// Set up intermediate variables
std::vector<std::vector<Hypergraph::EdgeIndex>> edges_by_indices;
Hypergraph::EdgeIndex max_vertex = 0;
unsigned n_edges = 0;
// Read the file line by line
for (std::string line; std::getline(hypergraph_filestream, line); ) {
// Each line is an edge
std::istringstream linestream(line);
++n_edges;
std::vector<Hypergraph::EdgeIndex> edge_indices;
for (Hypergraph::EdgeIndex v; linestream >> v; ) {
// Each word of the line is a vertex
edge_indices.push_back(v);
max_vertex = std::max(max_vertex, v);
}
edges_by_indices.push_back(edge_indices);
}
// Set up the hypergraph as a vector of edges
_n_verts = max_vertex + 1;
_edges = Hypergraph::EdgeVector(edges_by_indices.size(), Hypergraph::Edge(_n_verts));
for (Hypergraph::EdgeIndex i = 0; i < n_edges; ++i) {
for (auto const& v: edges_by_indices[i]) {
_edges[i][v] = true;
}
}
};
Hypergraph::Hypergraph (const Hypergraph::EdgeVector& edges):
_edges(edges)
{
if (edges.size() > 0) {
_n_verts = edges.at(0).size();
} else {
_n_verts = 0;
}
};
unsigned Hypergraph::num_verts () const {
return _n_verts;
};
unsigned Hypergraph::num_edges () const {
return _edges.size();
};
void Hypergraph::add_edge (const Hypergraph::Edge& edge,
bool test_simplicity) {
if (test_simplicity) {
for (auto const& existing_edge: _edges) {
if (existing_edge.is_subset_of(edge)) {
throw minimality_violated_exception();
}
if (edge.is_subset_of(existing_edge)) {
throw minimality_violated_exception();
}
}
}
_edges.push_back(edge);
if (_n_verts == 0) {
_n_verts = edge.size();
} else if (_n_verts != edge.size()) {
throw std::runtime_error("Attempted to add edge of invalid size!");
}
};
void Hypergraph::reserve_edge_capacity (unsigned n_edges) {
_edges.reserve(n_edges);
};
Hypergraph Hypergraph::edge_vee (const Hypergraph& G,
bool do_minimize) const {
assert(num_verts() == G.num_verts());
Hypergraph::EdgeVector newedges;
newedges.reserve(num_edges() + G.num_edges());
newedges.insert(newedges.end(), _edges.begin(), _edges.end());
newedges.insert(newedges.end(), G._edges.begin(), G._edges.end());
// Build the result hypergraph with these edges
Hypergraph result(newedges);
// Minimize if requested
if (do_minimize) {
result = result.minimization();
}
return result;
}
Hypergraph Hypergraph::transpose () const {
// Return new hypergraph T such that T[i][j] = this[j][i]
Hypergraph T (num_edges());
T.reserve_edge_capacity(_n_verts);
for (Hypergraph::EdgeIndex v = 0; v < _n_verts; ++v) {
T.add_edge(edges_containing_vertex(v));
}
return T;
}
Hypergraph Hypergraph::edge_wedge (const Hypergraph& G,
bool do_minimize) const {
assert(num_verts() == G.num_verts());
Hypergraph::EdgeVector newedges (num_edges() * G.num_edges(), Edge(_n_verts));
for (auto& edge1: _edges) {
for (auto& edge2: G._edges) {
newedges.push_back(edge1 | edge2);
}
}
Hypergraph result(newedges);
if (do_minimize) {
result = result.minimization();
}
return result;
}
Hypergraph Hypergraph::edge_wedge_cutoff (const Hypergraph& G,
unsigned cutoff_size,
bool do_minimize) const {
assert(num_verts() == G.num_verts());
// Container to store all the new edges
Hypergraph result (G.num_verts());
// For every pair of edges in this and G, add their union
for (auto& edge1: _edges) {
for (auto& edge2: G._edges) {
Hypergraph::Edge newedge = edge1 | edge2;
if (newedge.count() <= cutoff_size) {
result.add_edge(newedge);
}
}
}
if (do_minimize) {
result = result.minimization();
}
return result;
}
Hypergraph Hypergraph::contraction (const Hypergraph::Edge& S,
bool do_minimize) const {
Hypergraph result (num_verts());
for (auto& edge: _edges) {
Hypergraph::Edge new_edge = edge & S;
result.add_edge(new_edge);
}
if (do_minimize) {
result = result.minimization();
}
return result;
}
Hypergraph Hypergraph::restriction (const Hypergraph::Edge& S) const {
Hypergraph result (num_verts());
for (auto& edge: _edges) {
if (edge.is_subset_of(S)) {
result.add_edge(edge);
}
}
return result;
}
Hypergraph::Edge& Hypergraph::operator[] (Hypergraph::EdgeIndex edge_index) {
return _edges.at(edge_index);
};
const Hypergraph::Edge& Hypergraph::operator[] (Hypergraph::EdgeIndex edge_index) const {
return _edges.at(edge_index);
}
void Hypergraph::write_to_file (const fs::path& output_file) const {
fs::ofstream output_filestream(output_file);
if (!output_filestream.good()) {
std::stringstream errorMessage;
errorMessage << "Could not open output file " << output_file << " for writing.";
throw std::runtime_error(errorMessage.str());
}
for (auto const& edge: _edges) {
Hypergraph::EdgeIndex v = edge.find_first();
while (v != Edge::npos) {
output_filestream << v << ' ';
v = edge.find_next(v);
}
output_filestream << "\n";
}
};
Hypergraph Hypergraph::minimization () const {
if (_edges.empty()) {
return *this;
}
Hypergraph::EdgeVector sorted_edges = _edges;
std::sort(sorted_edges.begin(), sorted_edges.end());
Hypergraph::EdgeVector new_edges;
for (auto const& new_edge: sorted_edges) {
if (new_edge.none()) {
continue;
}
bool edge_is_minimal = true;
for (auto const& confirmed_edge: new_edges) {
if (confirmed_edge.is_subset_of(new_edge)) {
edge_is_minimal = false;
break;
}
}
if (edge_is_minimal) {
new_edges.push_back(new_edge);
}
}
if (new_edges.empty()) {
Hypergraph Hmin(_n_verts);
return Hmin;
} else {
Hypergraph Hmin(new_edges);
return Hmin;
}
};
Hypergraph::Edge Hypergraph::verts_covered () const {
Hypergraph::Edge result (_n_verts);
for (auto const& edge: _edges) {
result |= edge;
}
return result;
};
std::vector<unsigned> Hypergraph::vertex_degrees () const {
std::vector<unsigned> result (num_verts());
for (auto& edge: _edges) {
for (Hypergraph::EdgeIndex i = 0; i < edge.size(); ++i) {
result[i] += edge[i];
}
}
return result;
}
Hypergraph::Edge Hypergraph::vertices_with_degree_above_threshold (const float degree_threshold) const {
assert(0 <= degree_threshold);
assert(degree_threshold <= 1);
auto&& degrees = vertex_degrees();
unsigned n = num_verts();
unsigned m = num_edges();
unsigned count_threshold = floor(m * degree_threshold);
Edge result (n);
for (Hypergraph::EdgeIndex i = 0; i < n; ++i) {
if (degrees[i] > count_threshold) {
result.set(i);
}
}
return result;
}
Hypergraph::Edge Hypergraph::edges_containing_vertex (Hypergraph::EdgeIndex vertex_index) const {
unsigned n = num_edges();
Hypergraph::Edge result (n);
for (Hypergraph::EdgeIndex edge_index = 0; edge_index < n; ++edge_index) {
if (_edges[edge_index].test(vertex_index)) {
result.set(edge_index);
}
}
return result;
};
bool Hypergraph::is_transversed_by (const Hypergraph::Edge& S) const {
assert(S.size() == _n_verts);
for (auto const& edge: _edges) {
if (not S.intersects(edge)) {
return false;
}
}
return true;
};
bool Hypergraph::has_edge_covered_by (const Hypergraph::Edge& S) const {
// Return true if some edge of this hypergraph is covered by S
// NOTE: equivalent to evaluating as a DNF with S as an assignment
assert(S.size() == _n_verts);
for (auto const& edge: _edges) {
if (edge.is_subset_of(S)) {
return true;
}
}
return false;
}
std::ostream& operator<< (std::ostream& os, const Hypergraph& H) {
os << "Hypergraph with " << H.num_verts() << " vertices and "
<< H.num_edges() << " edges: \n";
for (auto& e: H) {
os << e << "\n";
}
return os;
}
}
超图.hpp
#ifndef _HYPERGRAPH__H
#define _HYPERGRAPH__H
#include "concurrentqueue.h"
#include <boost/filesystem.hpp>
#include <boost/dynamic_bitset.hpp>
#include <exception>
#include <iostream>
#include <vector>
namespace agdmhs {
namespace fs = boost::filesystem;
class minimality_violated_exception: public std::exception {
virtual const char* what() const throw() {
return "A non-minimal edge was added.";
}
};
class Hypergraph {
public:
using Edge = boost::dynamic_bitset<>;
using EdgeVector = std::vector<Edge>;
using EdgeQueue = moodycamel::ConcurrentQueue<Edge>;
using EdgeIndex = Edge::size_type;
Hypergraph(unsigned num_verts = 0, unsigned num_edges = 0);
Hypergraph(const fs::path& input_file);
Hypergraph(const EdgeVector& edges);
unsigned num_verts() const;
unsigned num_edges() const;
void add_edge(const Edge& edge, bool test_simplicity = false);
void reserve_edge_capacity(unsigned n_edges);
Hypergraph edge_vee(const Hypergraph& G, bool do_minimize = true) const;
Hypergraph edge_wedge(const Hypergraph& G, bool do_minimize = true) const;
Hypergraph edge_wedge_cutoff(const Hypergraph& G, unsigned cutoff_size, bool do_minimize = true) const;
Hypergraph contraction(const Edge& S, bool do_minimize = true) const;
Hypergraph restriction(const Edge& S) const;
Edge& operator[] (EdgeIndex edge_index);
const Edge& operator[] (EdgeIndex edge_index) const;
void write_to_file(const fs::path& output_file) const;
Hypergraph minimization() const;
Hypergraph transpose() const;
Edge verts_covered() const;
std::vector<unsigned> vertex_degrees() const;
Edge vertices_with_degree_above_threshold(const float degree_threshold) const;
Edge edges_containing_vertex(EdgeIndex vertex_index) const;
bool is_transversed_by(const Edge& S) const;
bool has_edge_covered_by(const Edge& S) const;
EdgeVector::const_iterator begin() const {return _edges.cbegin();};
EdgeVector::const_iterator end() const {return _edges.cend();};
friend std::ostream& operator<<(std::ostream& os, const Hypergraph& H);
protected:
unsigned _n_verts;
EdgeVector _edges;
};
}
#endif
concurrentqueue.h 可以在这里找到(它很长,所以我决定参考一个链接): https://github.com/cameron314/concurrentqueue/blob/master/concurrentqueue.h
我导入了所有相关代码,以备不时之需。虽然我认为我应该修改的代码在 rs.pp 和 rs.hpp 中。实际上,我尝试用这一行修改 void RSAlgorithm 中 rs.cpp 中的代码,它起作用了:
// add my modification
if (hitting_sets.size_approx() >= 1000) {return;}
我怎样才能添加另一个计时器,以便在给定的时间(例如 60 秒)后停止寻找解决方案,并返回它在 60 秒内找到的所有结果。我的猜测是像这样导入 sth 并添加另一个条件:
#include <chrono>
// add my modification
if (hitting_sets.size_approx() >= 1000 || time_out == 60) {return;}
如何添加额外的条件或额外的函数来停止搜索解决方案并在给定的特定时间后返回找到的解决方案?任何关于我应该在哪里修改它的帮助或指南将不胜感激。事先致谢!
请注意,size_approx() 取自 concurrentqueue.h。
答: 暂无答案
评论