Has anyone seen a 2-Sat implementation - c++

I have been looking for a while, but I just can't seem to find any implementation of the 2-Sat algorithm.
I am working in c++ with the boost library (which has a strongly connected component module) and need some guidance to either create an efficient 2-Sat program or find an existing library for me to utilise through c++.

I suppose you know how to model a 2-Sat problem to solve it with SCC.
The way I handle vars and its negation isn't very elegant, but allows a short implementation:
Given n variables numbered from 0 to n-1, in the clauses -i means the negation of variable i, and in the graph i+n means the same (am I clear ?)
#include <boost/config.hpp>
#include <iostream>
#include <vector>
#include <boost/graph/strong_components.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/foreach.hpp>
typedef std::pair<int, int> clause;
//Properties of our graph. By default oriented graph
typedef boost::adjacency_list<> Graph;
const int nb_vars = 5;
int var_to_node(int var)
{
if(var < 0)
return (-var + nb_vars);
else
return var;
}
int main(int argc, char ** argv)
{
std::vector<clause> clauses;
clauses.push_back(clause(1,2));
clauses.push_back(clause(2,-4));
clauses.push_back(clause(1,4));
clauses.push_back(clause(1,3));
clauses.push_back(clause(-2,4));
//Creates a graph with twice as many nodes as variables
Graph g(nb_vars * 2);
//Let's add all the edges
BOOST_FOREACH(clause c, clauses)
{
int v1 = c.first;
int v2 = c.second;
boost::add_edge(
var_to_node(-v1),
var_to_node(v2),
g);
boost::add_edge(
var_to_node(-v2),
var_to_node(v1),
g);
}
// Every node will belong to a strongly connected component
std::vector<int> component(num_vertices(g));
std::cout << strong_components(g, &component[0]) << std::endl;
// Let's check if there is variable having it's negation
// in the same SCC
bool satisfied = true;
for(int i=0; i<nb_vars; i++)
{
if(component[i] == component[i+nb_vars])
satisfied = false;
}
if(satisfied)
std::cout << "Satisfied!" << std::endl;
else
std::cout << "Not satisfied!" << std::endl;
}

Related

Is the complexity of this topological sort algorithm O(P+D) where P is projects and D is dependencies?

I have written a topological sorting algorithm in c++ but i am not sure if the complexity is as good as it should be. I know theres a topological sort algorithm that works in O(P+D) time where p is projects and D is number of dependencies, but I am unsure if i wrote it correctly. Can you take a look? Code is below. Any other suggestions on improvement is welcome too, I feel like having 2 lists for adjacency is inefficient and I think there should be a better way to do it.
#include <iostream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <queue>
using namespace std;
class Graph
{
public:
Graph(vector<string> projects, vector<pair<string,string>> dependencies)
{
int counter=0;
for(int i=0;i< projects.size();i++)
{
strToInt[projects[i]]=counter++;
}
adjList.resize(projects.size());
for(int i=0;i<dependencies.size();i++)
{
adjList[strToInt[dependencies[i].second]].first.insert(strToInt[dependencies[i].first]);
adjList[strToInt[dependencies[i].first]].second.push_back(strToInt[dependencies[i].second]);
}
}
vector<pair<unordered_set<int>,vector<int>>> adjList;
unordered_map<string,int> strToInt;
bool BuildOrder(){
vector<int> visited(adjList.size(),0);
queue<int> q;
int count =0;
for(int i=0;i<adjList.size();i++)
{
if(adjList[i].first.size()==0)
{
count++;
q.push(i);
}
}
while(!q.empty())
{
count++;
int temp=q.front();
q.pop();
visited[temp]=1;
for(int i=0;i<adjList[temp].second.size();i++)
{
adjList[i].first.erase(temp);
if(adjList[i].first.size()==0&&visited[i]==0)
{
q.push(i);
}
}
}
if(count==visited.size())
{
return true;
}
return false;
}
};
int main()
{
vector<string> projects {"a", "b", "c", "d", "e", "f"};
vector<pair<string,string>> dependencies{
{"a","d"},
{"f","b"},
{"b","d"},
{"f","a"},
{"d","c"}
};
Graph g(projects,dependencies);
bool temp=g.BuildOrder();
return 0;
}
I dont totally understand what your code is doing but I think it is implementing Kahn's algorithm. The thing with Kahn's algorithm is that it requires a graph representation in which you can get the in-neighbors and the out-neighbors of a given vertex in the digraph efficiently. To me this makes it too cumbersome to bother with given that a topological sort kind of naturally falls out of a depth-first search of out-neighbors only.
Below is an implementation of the DFS way. I do it with two visited sets like they explain in the Wikipedia article, because that way you do not even need to keep track of the source vertices of the graph, the vertices with in-degree zero, when building the graph -- although if you know the sources the DFS based algorithm is even simpler.
#include <iostream>
#include <iterator>
#include <functional>
#include <algorithm>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <deque>
using Edges = std::vector<std::pair<std::string, std::string>>;
using Vertices = std::vector<std::string>;
using Graph = std::unordered_map<std::string, std::vector<std::string>>;
Graph BuildAjacencyList(const Edges& edges)
{
Graph graph;
for (const auto& edge : edges)
graph[edge.first].push_back(edge.second);
return graph;
}
Vertices FindTopologicalOrder(const Vertices& vertices, const Edges& edges)
{
auto graph = BuildAjacencyList(edges);
std::unordered_set<std::string> unexplored, visited;
std::copy(vertices.begin(), vertices.end(), std::inserter(unexplored, unexplored.end()));
std::deque<std::string> topo_order;
std::function<bool(std::string)> visit = [&](std::string vert) {
if (unexplored.find(vert) == unexplored.end())
return true;
if (visited.find(vert) != visited.end())
return false;
visited.insert(vert);
for (const auto& neighbor : graph[vert])
if (!visit(neighbor))
return false;
visited.erase(vert);
unexplored.erase(vert);
topo_order.push_front(vert);
return true;
};
while (!unexplored.empty())
if (!visit(*unexplored.begin()))
return Vertices(); // the dependency graph has a cycle.
return Vertices(topo_order.begin(), topo_order.end());
}
int main()
{
std::vector<std::string> projects{ "a", "b", "c", "d", "e", "f" };
Edges dependencies{
{"a","d"},
{"f","b"},
{"b","d"},
{"f","a"},
{"d","c"},
{"b","e"}
};
auto order = FindTopologicalOrder(projects, dependencies);
if (order.empty()) {
std::cout << "there is a cycle in these dependencies\n";
} else {
for (const auto& vert : order)
std::cout << vert << std::endl;
}
return 0;
}

Boost Graph bellman_ford_shortest_paths with labeled_graph

I'm trying to run the Bellman-Ford algorithm using the Boost Library. I have a labeled graph, but I'm getting an exception invalid conversion from ‘void*’ to ‘int. Any help would only be appreciated. Here is my code:
// g++ -std=c++17 -Wall test.c++ -l boost_system && ./a.out
#include <iostream> // for cout
#include <utility> // for pair
#include <algorithm> // for for_each
#include <vector> // For dist[] and pred[]
#include <limits> // To reliably indicate infinity
#include <map>
#include <list>
#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/directed_graph.hpp>
#include <boost/graph/labeled_graph.hpp>
#include <boost/graph/bellman_ford_shortest_paths.hpp>
using namespace boost;
using namespace std;
class Node
{
public:
int id;
int group;
};
struct EdgeProperties {
double weight;
EdgeProperties(){}
EdgeProperties(double w){ weight = w; }
};
typedef labeled_graph<adjacency_list<hash_setS, hash_setS, directedS, Node, EdgeProperties>, int> Graph;
int main(){
cout << "Calling main()" << endl;
Graph g;
// populate the graph
{
add_vertex( 0, g );
g[0].id = 0;
g[0].group = 10;
add_vertex( 1, g );
g[1].id = 1;
g[1].group = 20;
add_edge_by_label( 0, 1, EdgeProperties(110), g);
add_edge_by_label( 1, 0, EdgeProperties(222), g);
print_graph(g, get(&Node::id, g));
cout << "There are " << num_vertices(g) << " nodes and " << num_edges(g) << " edges in the graph" << endl;
}
// number of verticies in the graph
auto n = num_vertices(g);
// weight map
auto ewp = weight_map(get(&EdgeProperties::weight, g.graph()));
const int source = 0;
const int target = 1;
// Distance Map (with n elements of value infinity; source's value is 0)
auto inf = numeric_limits<double>::max();
vector<double> dist(n, inf);
dist[source] = 0.0;
// Predecessor Map (with n elements)
vector<int> pred(n);
bellman_ford_shortest_paths(
g.graph(),
n,
ewp
.distance_map(make_iterator_property_map(dist.begin(), get(&Node::id, g)))
.predecessor_map(make_iterator_property_map(pred.begin(), get(&Node::id, g)))
);
return 0;
}
I saw the example on https://www.boost.org/doc/libs/1_53_0/libs/graph/example/bellman-example.cpp but the example uses not a labeled graph.
Here is a live preview of my code:
https://wandbox.org/permlink/WsQA8A0IyRvGWTIj
Thank you
The source of the problem has been touched upon in the existing answer you accepted.
However, there's more to this.
Firstly, you're pretty much "within your right" to want use Node::id as the vertex index, and there could be many good reasons to use something else than vector as the vertex container selector¹.
Secondly, that stuff should... probably have worked. bellman_ford documents:
The PredecessorMap type must be a Read/Write Property Map which key and vertex types the same as the vertex descriptor type of the graph.
And iterator_property_map documents:
This property map is an adaptor that converts any random access iterator into a Lvalue Property Map. The OffsetMap type is responsible for converting key objects to integers that can be used as offsets with the random access iterator.
Now LValuePropertyMap might in fact be readonly, but in this case it clearly shouldn't be.
When using make_iterator_property_map with the additional id-map parameter, it should in fact be behaving like any associative property map both the key and value types vertex_descriptor as required by the algorithm.
UPDATE See "BONUS" below
I might dive in a little more detail later to see why that didn't work, but for now let's just work around the issue without modifying the graph model:
Live On Coliru
auto gg = g.graph();
auto id = get(&Node::id, gg);
std::map<Graph::vertex_descriptor, Graph::vertex_descriptor> assoc_pred;
bellman_ford_shortest_paths(gg, n,
weight_map(get(&EdgeProperties::weight, gg))
.distance_map(make_iterator_property_map(dist.begin(), id))
.predecessor_map(make_assoc_property_map(assoc_pred))
);
That works as it should and as expected:
Calling main()
1 --> 0
0 --> 1
There are 2 nodes and 2 edges in the graph
BONUS
I found the missing link: the predecessor map was defined with the wrong value-type:
vector<Graph::vertex_descriptor> pred(n);
Will obviously work: Live On Coliru
¹ that's subtly different from the vertex descriptor, but related in the sense that the choice of vertex container will usually predict the actual type of vertex descriptor

Iterating std::vectors simultaneously using standard C++ [duplicate]

This question already has answers here:
What's the best way to iterate over two or more containers simultaneously
(11 answers)
Closed 4 years ago.
I'm new to C++ and hence would need some help in accomplishing a certain task. The problem is, I have to iterate over three or more vectors simultaneously, like so:
#include <vector>
#include <iostream>
#include <string>
#include <boost/range/combine.hpp>
using namespace std;
int main(int, char**) {
vector<string> questions = {"Planet", "Rocket", "Galaxy"};
vector<string> answers = {"Planet", "Saturn", "Star"};
vector<int> count = { 12, 34, 79};
vector<int> score = { 324, 956, 289};
vector<int> result;
vector<int> subscore;
string a, q;
int c, s;
for ( const string q : questions ) {
int match = 0;
for( auto tuple : boost::combine(answers, count) ) {
boost::tie(a,c) = tuple;
if( q.substr(0,2) == a.substr(0,2)) {std::cout << q.substr(0,3) << " " << a.substr(0,3) << endl; match = c; }
else cout << "No match!" << '\n';
}
if( match ) { result.push_back(match); }
else result.push_back(0); subscore.push_back(0);
This approach works but I can't use it in the framework we are using.
Maybe someone here can point me to a similar solution that does not depend on boost but is still efficient.
Many thanks!
You can use good old index:
auto size = std::min( answers.size(), count.size() ); // or at least assert that size is equal
for( size_t i = 0; i < size; ++i ) {
const auto &a = answers[i];
const auto c = count[i];
// .. same as before
note this way you possibly avoiding to make 2 copies of std::string per iteration - answers -> tuple -> a
This seems a transform so in C++ you can use std::transform... for example:
#include <vector>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main(int, char**) {
vector<string> questions = {"Planet", "Rocket", "Galaxy"};
vector<string> answers = {"Planet", "Saturn", "Star"};
vector<int> count = { 12, 34, 79};
vector<int> result;
for(const auto& q : questions)
{
transform(begin(answers), end(answers), begin(count), back_inserter(result),
[&q](const auto& answer, auto count)
{
if (q.substr(0, 2) == answer.substr(0, 2))
{
std::cout << q.substr(0,3) << " " << answer.substr(0,3) << endl;
return count;
}
else
cout << "No Match!" << endl;
return 0;
});
}
}
Now the results vector holds all results. back_inserter is used in order to dynamically grow the result std::vector.

How to manipulate vectors in C++

I'm trying to manipulate a set of elements in vectors in c++.
vector <int> vectorOfValue;
vectorOfValue.push_back(1);
vectorOfValue.push_back(2);
vectorOfValue.push_back(3);
vectorOfValue.push_back(4);
vectorOfValue.push_back(5);
vectorOfValue.push_back(6);
vectorOfValue.push_back(7);
vectorOfValue.push_back(8);
vectorOfValue.push_back(9);
vectorOfValue.push_back(10);
I would like to know how the program can print out the vectors of values bigger 3 and smaller than 9.
It is a set of the data to exclude the outliers for example.
If you want to use the standard library algorithms and iterators, you could use std::copy_if:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
auto main(int argc, char* argv[]) -> int
{
std::vector<int> vectorOfValue;
// code for initialization of vector ..
std::copy_if(vectorOfValue.begin(),
vectorOfValue.end(),
std::ostream_iterator<int>(std::cout, "\n"),
[](const int value) { return value > 3 && value < 9; });
}
Short approach of mine using auto syntax instead of using iterator :
for(auto &i : vectorOfValue) {
if (i > 3 && i < 9) {
std::cout << i << std::endl;
}
}

Correct way to compare two pointees to use in std algorithms

I am playing with boost::range and boost::lambda with following example to compare two numbers and get the element out which has same number.
#include <iostream>
#include <boost/optional.hpp>
#include <boost/range/algorithm/find_if.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/utility/compare_pointees.hpp>
template <class Range, class Predicate>
boost::optional<typename boost::range_value<Range>::type>
search_for(const Range& r, Predicate pred)
{
BOOST_AUTO (it, boost::find_if(r, pred));
if (it == boost::end(r))
return boost::none;
return *it;
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int d = 3;
std::vector<int*> m = {&a, &b, &c};
if (boost::optional<int*> number =
search_for(m, boost::equal_pointees(???, &d))) {
std::cout << "found:" << (*number.get()) << std::endl;
}
else {
std::cout << "not found" << std::endl;
}
}
What should I use for ??? above in search_for function?
I believe it could be very simple but don't know how to do it. I can use the boost::bind or std::bind2d, etc to compare but was thinking if there is any elegant way to do it. Also, this code sample could be restructured to much simpler one but I am just learning.
With boost::lambda, it looks like this:
namespace ll = boost::lambda;
search_for(m, *ll::_1 == d)
Which is far less complicated than taking a pointer to d just so you can use equal_pointees.