Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
Two_Sat.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
58# ifndef TWO_SAT_H
59# define TWO_SAT_H
60
61# include <ah-graph-concepts.H>
62
63# include <cassert>
64# include <utility>
65# include <limits>
66
67# include <ah-errors.H>
68# include <tpl_array.H>
69# include <tpl_dynArray.H>
70# include <tpl_graph.H>
71# include <tpl_dynSetTree.H>
72# include <Tarjan.H>
73
74namespace Aleph {
75
83template <AlephGraph GT = List_Digraph<Graph_Node<Empty_Class>,
84 Graph_Arc<Empty_Class>>>
86{
87public:
88 using Node = typename GT::Node;
89 using Arc = typename GT::Arc;
90
91private:
92 size_t num_vars;
95
96public:
97
100
105 [[nodiscard]] static constexpr size_t
106 pos_lit(const size_t var) noexcept { return 2 * var; }
107
112 [[nodiscard]] static constexpr size_t
113 neg_lit(const size_t var) noexcept { return 2 * var + 1; }
114
119 [[nodiscard]] static constexpr size_t
120 negate_lit(const size_t lit) noexcept { return lit ^ 1; }
121
126 [[nodiscard]] static constexpr size_t
127 lit_var(const size_t lit) noexcept { return lit >> 1; }
128
133 [[nodiscard]] static constexpr bool
134 is_pos_lit(const size_t lit) noexcept { return (lit & 1) == 0; }
135
143 [[nodiscard]] static size_t signed_to_lit(const long v)
144 {
145 ah_domain_error_if(v == 0)
146 << "Two_Sat::signed_to_lit: variable index 0 is invalid";
147 ah_domain_error_if(v == std::numeric_limits<long>::min())
148 << "Two_Sat::signed_to_lit: variable index LONG_MIN is invalid";
149
150 if (v > 0)
151 return pos_lit(static_cast<size_t>(v - 1));
152
153 // Handle v < 0 safely, avoiding overflow for LONG_MIN (guarded above).
154 const size_t magnitude_minus_one = static_cast<size_t>(-(v + 1));
156 }
157
159
161 Two_Sat(const Two_Sat &) = delete;
162
164 Two_Sat & operator=(const Two_Sat &) = delete;
165
169 Two_Sat(const size_t n)
170 : num_vars(n), lit_nodes(Array<Node *>::create(2 * n))
171 {
172 for (size_t i = 0; i < 2 * n; ++i)
173 lit_nodes(i) = ig.insert_node();
174 }
175
177 [[nodiscard]] size_t size() const noexcept { return num_vars; }
178
180 [[nodiscard]] size_t num_nodes() const noexcept { return 2 * num_vars; }
181
183 [[nodiscard]] const GT & implication_graph() const noexcept { return ig; }
184
190 void add_clause(size_t a, size_t b)
191 {
193 << "Two_Sat::add_clause: literal " << a
194 << " refers to variable " << lit_var(a)
195 << " but only " << num_vars << " variables exist";
197 << "Two_Sat::add_clause: literal " << b
198 << " refers to variable " << lit_var(b)
199 << " but only " << num_vars << " variables exist";
200
203 }
204
209 void add_clause_signed(const long a, const long b)
210 {
211 ah_domain_error_if(a == 0 or b == 0)
212 << "Two_Sat::add_clause_signed: variable index 0 is invalid";
213 ah_domain_error_if(a == std::numeric_limits<long>::min() or
214 b == std::numeric_limits<long>::min())
215 << "Two_Sat::add_clause_signed: variable index LONG_MIN is invalid";
217 }
218
223 void add_implication(const size_t a, const size_t b)
224 {
225 add_clause(negate_lit(a), b);
226 }
227
231 void set_true(const size_t a)
232 {
233 add_clause(a, a);
234 }
235
239 void set_false(const size_t a)
240 {
242 }
243
248 void add_xor(const size_t a, const size_t b)
249 {
250 add_clause(a, b);
252 }
253
258 void add_equiv(const size_t a, const size_t b)
259 {
260 add_implication(a, b);
261 add_implication(b, a);
262 }
263
277 {
279 for (size_t i = 0; i < lits.size(); ++i)
280 {
281 const size_t lit = lits(i);
283 << "Two_Sat::add_at_most_one: literal " << lit
284 << " refers to variable " << lit_var(lit)
285 << " but only " << num_vars << " variables exist";
286 unique_lits.insert(lit);
287 }
288
289 if (unique_lits.size() < 2)
290 return;
291
293 unique_lits.for_each([&u_dyn](const size_t & lit) { u_dyn.append(lit); });
294 const Array<size_t> u = u_dyn.to_array();
295 for (size_t i = 0; i < u.size(); ++i)
296 for (size_t j = i + 1; j < u.size(); ++j)
297 add_clause(negate_lit(u(i)), negate_lit(u(j)));
298 }
299
304 {
305 return solve().first;
306 }
307
311 [[nodiscard]] std::pair<bool, Array<bool>> solve()
312 {
315
316 long scc_id = 0;
317 sccs.for_each([&scc_id](auto & scc) {
318 scc.for_each([&scc_id](Node * node) {
319 NODE_COUNTER(node) = scc_id;
320 });
321 ++scc_id;
322 });
323
324# ifndef NDEBUG
325 for (size_t lit = 0; lit < lit_nodes.size(); ++lit)
326 for (Out_Iterator<GT> it(lit_nodes(lit)); it.has_curr(); it.next_ne())
327 {
328 Node * const src = lit_nodes(lit);
329 Node * const tgt = ig.get_tgt_node(it.get_curr());
330 const long src_id = NODE_COUNTER(src);
331 const long tgt_id = NODE_COUNTER(tgt);
333 }
334# endif
335
337
338 for (size_t i = 0; i < num_vars; ++i)
339 {
340 const long id_pos = NODE_COUNTER(lit_nodes(pos_lit(i)));
341 const long id_neg = NODE_COUNTER(lit_nodes(neg_lit(i)));
342
343 if (id_pos == id_neg)
344 return {false, Array<bool>()};
345
346 // This depends on connected_components() returning SCCs in reverse
347 // topological order, which is then recorded in NODE_COUNTER(...).
348 assignment(i) = id_pos < id_neg;
349 }
350
351 return {true, std::move(assignment)};
352 }
353};
354
355
356} // end namespace Aleph
357
358# endif /* TWO_SAT_H */
Tarjan's algorithm for strongly connected components.
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
C++20 concepts for the protocol shared by graph algorithms.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:196
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:365
Array to_array() const
Copy to Aleph::Array (requires copyable elements).
Definition tpl_array.H:597
bool has_curr() const noexcept
Return true the iterator has an current arc.
Definition tpl_graph.H:1726
Dynamic set backed by balanced binary search trees with automatic memory management.
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:525
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:605
Filtered iterator for outcoming arcs of a node.
Definition tpl_graph.H:1831
Computes strongly connected components (SCCs) in a directed graph using Tarjan's algorithm.
Definition Tarjan.H:169
void connected_components(const GT &g, DynList< GT > &blk_list, DynList< typename GT::Arc * > &arc_list)
Computes the strongly connected components (SCCs) of a digraph.
Definition Tarjan.H:622
2-SAT solver using Tarjan's SCC algorithm.
Definition Two_Sat.H:86
void add_clause_signed(const long a, const long b)
Add a clause using signed 1-based variables.
Definition Two_Sat.H:209
Two_Sat(const size_t n)
Construct a solver for n variables.
Definition Two_Sat.H:169
typename GT::Arc Arc
Definition Two_Sat.H:89
static constexpr size_t pos_lit(const size_t var) noexcept
Get the positive literal for a variable.
Definition Two_Sat.H:106
std::pair< bool, Array< bool > > solve()
Solve the 2-SAT instance.
Definition Two_Sat.H:311
Two_Sat(const Two_Sat &)=delete
Deleted copy constructor to avoid dangling internal Node* pointers.
static size_t signed_to_lit(const long v)
Convert a signed 1-based variable to a literal index.
Definition Two_Sat.H:143
void set_true(const size_t a)
Force literal a to be true.
Definition Two_Sat.H:231
void add_implication(const size_t a, const size_t b)
Add an implication a -> b.
Definition Two_Sat.H:223
static constexpr bool is_pos_lit(const size_t lit) noexcept
Check if a literal is positive.
Definition Two_Sat.H:134
void set_false(const size_t a)
Force literal a to be false.
Definition Two_Sat.H:239
const GT & implication_graph() const noexcept
Definition Two_Sat.H:183
typename GT::Node Node
Definition Two_Sat.H:88
static constexpr size_t neg_lit(const size_t var) noexcept
Get the negative literal for a variable.
Definition Two_Sat.H:113
static constexpr size_t negate_lit(const size_t lit) noexcept
Negate a literal.
Definition Two_Sat.H:120
size_t num_vars
Definition Two_Sat.H:92
void add_at_most_one(const Array< size_t > &lits)
Add at-most-one constraint over a set of literals.
Definition Two_Sat.H:276
Two_Sat & operator=(const Two_Sat &)=delete
Deleted copy assignment to avoid dangling internal Node* pointers.
static constexpr size_t lit_var(const size_t lit) noexcept
Get the variable index of a literal.
Definition Two_Sat.H:127
void add_equiv(const size_t a, const size_t b)
Add equivalence constraint: a <-> b.
Definition Two_Sat.H:258
Array< Node * > lit_nodes
Definition Two_Sat.H:94
void add_xor(const size_t a, const size_t b)
Add XOR constraint: exactly_one(a, b).
Definition Two_Sat.H:248
size_t num_nodes() const noexcept
Definition Two_Sat.H:180
bool is_satisfiable()
Check if the formula is satisfiable.
Definition Two_Sat.H:303
void add_clause(size_t a, size_t b)
Add a clause (a OR b).
Definition Two_Sat.H:190
size_t size() const noexcept
Definition Two_Sat.H:177
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:796
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:785
#define NODE_COUNTER(p)
Get the counter of a node.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Dynamic array container with automatic resizing.
Lazy and scalable dynamic array implementation.
Dynamic set implementations based on balanced binary search trees.
Generic graph and digraph implementations.