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 <cassert>
62# include <utility>
63# include <limits>
64
65# include <ah-errors.H>
66# include <tpl_array.H>
67# include <tpl_dynArray.H>
68# include <tpl_graph.H>
69# include <tpl_dynSetTree.H>
70# include <Tarjan.H>
71
72namespace Aleph {
73
81template <class GT = List_Digraph<Graph_Node<Empty_Class>,
82 Graph_Arc<Empty_Class>>>
84{
85public:
86 using Node = typename GT::Node;
87 using Arc = typename GT::Arc;
88
89private:
90 size_t num_vars;
93
94public:
95
98
103 [[nodiscard]] static constexpr size_t
104 pos_lit(const size_t var) noexcept { return 2 * var; }
105
110 [[nodiscard]] static constexpr size_t
111 neg_lit(const size_t var) noexcept { return 2 * var + 1; }
112
117 [[nodiscard]] static constexpr size_t
118 negate_lit(const size_t lit) noexcept { return lit ^ 1; }
119
124 [[nodiscard]] static constexpr size_t
125 lit_var(const size_t lit) noexcept { return lit >> 1; }
126
131 [[nodiscard]] static constexpr bool
132 is_pos_lit(const size_t lit) noexcept { return (lit & 1) == 0; }
133
141 [[nodiscard]] static size_t signed_to_lit(const long v)
142 {
143 ah_domain_error_if(v == 0)
144 << "Two_Sat::signed_to_lit: variable index 0 is invalid";
145 ah_domain_error_if(v == std::numeric_limits<long>::min())
146 << "Two_Sat::signed_to_lit: variable index LONG_MIN is invalid";
147
148 if (v > 0)
149 return pos_lit(static_cast<size_t>(v - 1));
150
151 // Handle v < 0 safely, avoiding overflow for LONG_MIN (guarded above).
152 const size_t magnitude_minus_one = static_cast<size_t>(-(v + 1));
154 }
155
157
159 Two_Sat(const Two_Sat &) = delete;
160
162 Two_Sat & operator=(const Two_Sat &) = delete;
163
167 Two_Sat(const size_t n)
168 : num_vars(n), lit_nodes(Array<Node *>::create(2 * n))
169 {
170 for (size_t i = 0; i < 2 * n; ++i)
171 lit_nodes(i) = ig.insert_node();
172 }
173
175 [[nodiscard]] size_t size() const noexcept { return num_vars; }
176
178 [[nodiscard]] size_t num_nodes() const noexcept { return 2 * num_vars; }
179
181 [[nodiscard]] const GT & implication_graph() const noexcept { return ig; }
182
188 void add_clause(size_t a, size_t b)
189 {
191 << "Two_Sat::add_clause: literal " << a
192 << " refers to variable " << lit_var(a)
193 << " but only " << num_vars << " variables exist";
195 << "Two_Sat::add_clause: literal " << b
196 << " refers to variable " << lit_var(b)
197 << " but only " << num_vars << " variables exist";
198
201 }
202
207 void add_clause_signed(const long a, const long b)
208 {
209 ah_domain_error_if(a == 0 or b == 0)
210 << "Two_Sat::add_clause_signed: variable index 0 is invalid";
211 ah_domain_error_if(a == std::numeric_limits<long>::min() or
212 b == std::numeric_limits<long>::min())
213 << "Two_Sat::add_clause_signed: variable index LONG_MIN is invalid";
215 }
216
221 void add_implication(const size_t a, const size_t b)
222 {
223 add_clause(negate_lit(a), b);
224 }
225
229 void set_true(const size_t a)
230 {
231 add_clause(a, a);
232 }
233
237 void set_false(const size_t a)
238 {
240 }
241
246 void add_xor(const size_t a, const size_t b)
247 {
248 add_clause(a, b);
250 }
251
256 void add_equiv(const size_t a, const size_t b)
257 {
258 add_implication(a, b);
259 add_implication(b, a);
260 }
261
275 {
277 for (size_t i = 0; i < lits.size(); ++i)
278 {
279 const size_t lit = lits(i);
281 << "Two_Sat::add_at_most_one: literal " << lit
282 << " refers to variable " << lit_var(lit)
283 << " but only " << num_vars << " variables exist";
284 unique_lits.insert(lit);
285 }
286
287 if (unique_lits.size() < 2)
288 return;
289
291 unique_lits.for_each([&u_dyn](const size_t & lit) { u_dyn.append(lit); });
292 const Array<size_t> u = u_dyn.to_array();
293 for (size_t i = 0; i < u.size(); ++i)
294 for (size_t j = i + 1; j < u.size(); ++j)
295 add_clause(negate_lit(u(i)), negate_lit(u(j)));
296 }
297
302 {
303 return solve().first;
304 }
305
309 [[nodiscard]] std::pair<bool, Array<bool>> solve()
310 {
313
314 long scc_id = 0;
315 sccs.for_each([&scc_id](auto & scc) {
316 scc.for_each([&scc_id](Node * node) {
317 NODE_COUNTER(node) = scc_id;
318 });
319 ++scc_id;
320 });
321
322# ifndef NDEBUG
323 for (size_t lit = 0; lit < lit_nodes.size(); ++lit)
324 for (Out_Iterator<GT> it(lit_nodes(lit)); it.has_curr(); it.next_ne())
325 {
326 Node * const src = lit_nodes(lit);
327 Node * const tgt = ig.get_tgt_node(it.get_curr());
328 const long src_id = NODE_COUNTER(src);
329 const long tgt_id = NODE_COUNTER(tgt);
331 }
332# endif
333
335
336 for (size_t i = 0; i < num_vars; ++i)
337 {
338 const long id_pos = NODE_COUNTER(lit_nodes(pos_lit(i)));
339 const long id_neg = NODE_COUNTER(lit_nodes(neg_lit(i)));
340
341 if (id_pos == id_neg)
342 return {false, Array<bool>()};
343
344 // This depends on connected_components() returning SCCs in reverse
345 // topological order, which is then recorded in NODE_COUNTER(...).
346 assignment(i) = id_pos < id_neg;
347 }
348
349 return {true, std::move(assignment)};
350 }
351};
352
353
354} // end namespace Aleph
355
356# 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:522
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:194
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:351
Array to_array() const
Copy to Aleph::Array (requires copyable elements).
Definition tpl_array.H:460
bool has_curr() const noexcept
Return true the iterator has an current arc.
Definition tpl_graph.H:1645
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:524
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
Filtered iterator for outcoming arcs of a node.
Definition tpl_graph.H:1750
Computes strongly connected components (SCCs) in a directed graph using Tarjan's algorithm.
Definition Tarjan.H:171
void connected_components(const GT &g, DynList< GT > &blk_list, DynList< typename GT::Arc * > &arc_list)
Computes the strongly connected components of a digraph.
Definition Tarjan.H:626
2-SAT solver using Tarjan's SCC algorithm.
Definition Two_Sat.H:84
void add_clause_signed(const long a, const long b)
Add a clause using signed 1-based variables.
Definition Two_Sat.H:207
Two_Sat(const size_t n)
Construct a solver for n variables.
Definition Two_Sat.H:167
typename GT::Arc Arc
Definition Two_Sat.H:87
static constexpr size_t pos_lit(const size_t var) noexcept
Get the positive literal for a variable.
Definition Two_Sat.H:104
std::pair< bool, Array< bool > > solve()
Solve the 2-SAT instance.
Definition Two_Sat.H:309
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:141
void set_true(const size_t a)
Force literal a to be true.
Definition Two_Sat.H:229
void add_implication(const size_t a, const size_t b)
Add an implication a -> b.
Definition Two_Sat.H:221
static constexpr bool is_pos_lit(const size_t lit) noexcept
Check if a literal is positive.
Definition Two_Sat.H:132
void set_false(const size_t a)
Force literal a to be false.
Definition Two_Sat.H:237
const GT & implication_graph() const noexcept
Definition Two_Sat.H:181
typename GT::Node Node
Definition Two_Sat.H:86
static constexpr size_t neg_lit(const size_t var) noexcept
Get the negative literal for a variable.
Definition Two_Sat.H:111
static constexpr size_t negate_lit(const size_t lit) noexcept
Negate a literal.
Definition Two_Sat.H:118
size_t num_vars
Definition Two_Sat.H:90
void add_at_most_one(const Array< size_t > &lits)
Add at-most-one constraint over a set of literals.
Definition Two_Sat.H:274
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:125
void add_equiv(const size_t a, const size_t b)
Add equivalence constraint: a <-> b.
Definition Two_Sat.H:256
Array< Node * > lit_nodes
Definition Two_Sat.H:92
void add_xor(const size_t a, const size_t b)
Add XOR constraint: exactly_one(a, b).
Definition Two_Sat.H:246
size_t num_nodes() const noexcept
Definition Two_Sat.H:178
bool is_satisfiable()
Check if the formula is satisfiable.
Definition Two_Sat.H:301
void add_clause(size_t a, size_t b)
Add a clause (a OR b).
Definition Two_Sat.H:188
size_t size() const noexcept
Definition Two_Sat.H:175
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:779
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:743
#define NODE_COUNTER(p)
Get the counter of a node.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
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.