Skip to content

Commit bb8c6d0

Browse files
authored
Merge pull request #8 from msoeken/npn_classification
NPN classification
2 parents 17cb4e3 + 3cf216f commit bb8c6d0

17 files changed

+941
-207
lines changed

bench/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
file(GLOB FILENAMES *.cpp)
22

33
# No debugging and full optimization for benchmark test
4-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DNODEBUG")
4+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -DNDEBUG")
55

66
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Enable testing of the benchmark library." FORCE)
77
set(CMAKE_BUILD_TYPE "Release")

bench/canonization.cpp

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/* kitty: C++ truth table library
2+
* Copyright (C) 2017 EPFL
3+
*
4+
* Permission is hereby granted, free of charge, to any person
5+
* obtaining a copy of this software and associated documentation
6+
* files (the "Software"), to deal in the Software without
7+
* restriction, including without limitation the rights to use,
8+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the
10+
* Software is furnished to do so, subject to the following
11+
* conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be
14+
* included in all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23+
* OTHER DEALINGS IN THE SOFTWARE.
24+
*/
25+
26+
#include <benchmark/benchmark.h>
27+
28+
#include <kitty/kitty.hpp>
29+
30+
using namespace kitty;
31+
32+
void BM_exact_npn_canonization_static( benchmark::State& state )
33+
{
34+
while ( state.KeepRunning() )
35+
{
36+
static_truth_table<6> tt;
37+
create_from_hex_string( tt, "17cad20f55459c3f" );
38+
exact_npn_canonization( tt );
39+
}
40+
}
41+
42+
void BM_exact_npn_canonization_dynamic( benchmark::State& state )
43+
{
44+
while ( state.KeepRunning() )
45+
{
46+
dynamic_truth_table tt( 6 );
47+
create_from_hex_string( tt, "17cad20f55459c3f" );
48+
exact_npn_canonization( tt );
49+
}
50+
}
51+
52+
BENCHMARK( BM_exact_npn_canonization_static );
53+
BENCHMARK( BM_exact_npn_canonization_dynamic );
54+
55+
BENCHMARK_MAIN()

bench/operations.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,24 @@ void BM_bitwise_majority_func_dynamic( benchmark::State& state )
105105
}
106106
}
107107

108+
void BM_unary_not_ite_dynamic( benchmark::State& state )
109+
{
110+
while ( state.KeepRunning() )
111+
{
112+
dynamic_truth_table tt( state.range( 0 ) );
113+
const auto tt_new = !get_bit( tt, 0 ) ? unary_not( tt ) : tt;
114+
}
115+
}
116+
117+
void BM_unary_not_if_dynamic( benchmark::State& state )
118+
{
119+
while ( state.KeepRunning() )
120+
{
121+
dynamic_truth_table tt( state.range( 0 ) );
122+
const auto tt_new = unary_not_if( tt, get_bit( tt, 0 ) );
123+
}
124+
}
125+
108126
BENCHMARK_TEMPLATE( BM_bitwise_and_lambda_static, 5 );
109127
BENCHMARK_TEMPLATE( BM_bitwise_and_lambda_static, 7 );
110128
BENCHMARK_TEMPLATE( BM_bitwise_and_lambda_static, 9 );
@@ -123,4 +141,7 @@ BENCHMARK( BM_bitwise_and_std_dynamic )->Arg( 5 )->Arg( 7 )->Arg( 9 );
123141
BENCHMARK( BM_bitwise_and_func_dynamic )->Arg( 5 )->Arg( 7 )->Arg( 9 );
124142
BENCHMARK( BM_bitwise_majority_func_dynamic )->Arg( 5 )->Arg( 7 )->Arg( 9 );
125143

144+
BENCHMARK( BM_unary_not_ite_dynamic )->Arg( 5 )->Arg( 7 )->Arg( 9 );
145+
BENCHMARK( BM_unary_not_if_dynamic )->Arg( 5 )->Arg( 7 )->Arg( 9 );
146+
126147
BENCHMARK_MAIN()

docs/changelog.rst

+15-3
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,37 @@ v0.1
88
* Data structures ``static_truth_table`` and ``dynamic_truth_table``
99
`#1 <https://github.com/msoeken/kitty/pull/1>`_
1010

11-
* Bit-access functions ``set_bit`` and ``get_bit``
11+
* Bit functions: ``set_bit``, ``get_bit``, ``clear_bit``, ``clear``
1212
`#1 <https://github.com/msoeken/kitty/pull/1>`_
13+
`#8 <https://github.com/msoeken/kitty/pull/8>`_
1314

1415
* Constructors ``create_nth_var``, ``create_from_binary_string``, ``create_from_hex_string``, and ``create_majority``
1516
`#1 <https://github.com/msoeken/kitty/pull/1>`_
1617
`#4 <https://github.com/msoeken/kitty/pull/4>`_
1718
`#5 <https://github.com/msoeken/kitty/pull/5>`_
1819

19-
* Unary and binary operations: ``unary_not``, ``binary_and``, ``binary_or``, and ``binary_xor``
20+
* Unary and binary operations: ``unary_not``, ``unary_not_if``, ``binary_and``, ``binary_or``, and ``binary_xor``
2021
`#2 <https://github.com/msoeken/kitty/pull/2>`_
22+
`#8 <https://github.com/msoeken/kitty/pull/8>`_
2123

2224
* Ternary operations: ``ternary_majority`` and ``ternary_ite``
2325
`#3 <https://github.com/msoeken/kitty/pull/3>`_
2426

25-
* Binary predicates: ``equal``
27+
* Binary predicates: ``equal``, ``less_than``
2628
`#4 <https://github.com/msoeken/kitty/pull/4>`_
29+
`#8 <https://github.com/msoeken/kitty/pull/8>`_
30+
31+
* Operators: ``~``, ``==``, ``<``
32+
`#8 <https://github.com/msoeken/kitty/pull/8>`_
2733

2834
* Swap adjacent variables: ``swap_adjacent_inplace``, ``swap_adjacent``
2935
`#6 <https://github.com/msoeken/kitty/pull/6>`_
3036

37+
* Swap variables: ``swap_inplace``, ``swap``
38+
`#8 <https://github.com/msoeken/kitty/pull/8>`_
39+
3140
* Flip variable: ``flip_inplace``, ``flip``
3241
`#7 <https://github.com/msoeken/kitty/pull/7>`_
42+
43+
* NPN canonization: ``exact_npn_canonization``, ``create_from_npn_config``
44+
`#8 <https://github.com/msoeken/kitty/pull/8>`_

docs/reference.rst

+10
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,13 @@ Operations
3636

3737
.. doxygenfile:: operations.hpp
3838

39+
Operators
40+
---------
41+
42+
.. doxygenfile:: operators.hpp
43+
44+
Canonization
45+
------------
46+
47+
.. doxygenfile:: canonization.hpp
48+

include/kitty/bit_operations.hpp

+18
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,22 @@ void clear_bit( static_truth_table<NumVars, true>& tt, uint64_t index )
9292
tt._bits &= ~( uint64_t( 1 ) << index );
9393
}
9494
/*! \endcond */
95+
96+
/*! Clears all bits.
97+
98+
\param tt Truth table
99+
*/
100+
template<typename TT>
101+
void clear( TT& tt )
102+
{
103+
std::fill( std::begin( tt._bits ), std::end( tt._bits ), 0 );
104+
}
105+
106+
/*! \cond PRIVATE */
107+
template<int NumVars>
108+
void clear( static_truth_table<NumVars, true>& tt )
109+
{
110+
tt._bits = 0;
111+
}
112+
/*! \endcond */
95113
} // namespace kitty

include/kitty/canonization.hpp

+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/* kitty: C++ truth table library
2+
* Copyright (C) 2017 EPFL
3+
*
4+
* Permission is hereby granted, free of charge, to any person
5+
* obtaining a copy of this software and associated documentation
6+
* files (the "Software"), to deal in the Software without
7+
* restriction, including without limitation the rights to use,
8+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the
10+
* Software is furnished to do so, subject to the following
11+
* conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be
14+
* included in all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23+
* OTHER DEALINGS IN THE SOFTWARE.
24+
*/
25+
26+
#pragma once
27+
28+
#include <numeric>
29+
30+
#include "detail/constants.hpp"
31+
#include "operators.hpp"
32+
33+
namespace kitty
34+
{
35+
36+
/*! Exact NPN canonization
37+
38+
Given a truth table, this function finds the lexicographically
39+
smallest truth table in its NPN class, called NPN representative.
40+
Two functions are in the same NPN class, if one can obtain one from
41+
the other by input negation, input permutation, and output negation.
42+
43+
The function returns a NPN configuration which contains the
44+
necessary transformations to obtain the representative. It is a
45+
tuple of
46+
47+
- the NPN representative
48+
- input negations and output negation, output negation is stored as
49+
bit *n*, where *n* is the number of variables in `tt`
50+
- input permutation to apply
51+
52+
\param tt The truth table
53+
\return NPN configuration
54+
*/
55+
template<typename TT>
56+
std::tuple<TT, uint32_t, std::vector<uint8_t>> exact_npn_canonization( const TT& tt )
57+
{
58+
const auto num_vars = tt.num_vars();
59+
60+
/* Special case for n = 0 */
61+
if ( num_vars == 0 )
62+
{
63+
const auto bit = get_bit( tt, 0 );
64+
return std::make_tuple( unary_not_if( tt, bit ), bit, std::vector<uint8_t>{} );
65+
}
66+
67+
/* Special case for n = 1 */
68+
if ( num_vars == 1 )
69+
{
70+
const auto bit1 = get_bit( tt, 1 );
71+
return std::make_tuple( unary_not_if( tt, bit1 ), bit1 << 1, std::vector<uint8_t>{ 0 } );
72+
}
73+
74+
assert( num_vars >= 2 && num_vars <= 6u );
75+
76+
auto t1 = tt, t2 = ~tt;
77+
auto tmin = std::min( t1, t2 );
78+
auto invo = tmin == t2;
79+
80+
const auto& swaps = detail::swaps[num_vars - 2u];
81+
const auto& flips = detail::flips[num_vars - 2u];
82+
83+
int best_swap = -1;
84+
int best_flip = -1;
85+
86+
for ( int i = 0; i < swaps.size(); ++i )
87+
{
88+
const auto pos = swaps[i];
89+
swap_adjacent_inplace( t1, pos );
90+
swap_adjacent_inplace( t2, pos );
91+
if ( t1 < tmin || t2 < tmin )
92+
{
93+
best_swap = i;
94+
tmin = std::min( t1, t2 );
95+
invo = tmin == t2;
96+
}
97+
}
98+
99+
for ( int j = 0; j < flips.size(); ++j )
100+
{
101+
const auto pos = flips[j];
102+
swap_adjacent_inplace( t1, 0 );
103+
flip_inplace( t1, pos );
104+
swap_adjacent_inplace( t2, 0 );
105+
flip_inplace( t2, pos );
106+
if ( t1 < tmin || t2 < tmin )
107+
{
108+
best_swap = -1;
109+
best_flip = j;
110+
tmin = std::min( t1, t2 );
111+
invo = tmin == t2;
112+
}
113+
114+
for ( int i = 0; i < swaps.size(); ++i )
115+
{
116+
const auto pos = swaps[i];
117+
swap_adjacent_inplace( t1, pos );
118+
swap_adjacent_inplace( t2, pos );
119+
if ( t1 < tmin || t2 < tmin )
120+
{
121+
best_swap = i;
122+
best_flip = j;
123+
tmin = std::min( t1, t2 );
124+
invo = tmin == t2;
125+
}
126+
}
127+
}
128+
129+
std::vector<uint8_t> perm( num_vars );
130+
std::iota( perm.begin(), perm.end(), 0u );
131+
132+
for ( auto i = 0; i <= best_swap; ++i )
133+
{
134+
const auto pos = swaps[i];
135+
std::swap( perm[pos], perm[pos + 1] );
136+
}
137+
138+
uint32_t phase = uint32_t( invo ) << num_vars;
139+
for ( auto i = 0; i <= best_flip; ++i )
140+
{
141+
phase ^= 1 << flips[i];
142+
}
143+
144+
return std::make_tuple( tmin, phase, perm );
145+
}
146+
147+
/*! Obtain truth table from NPN configuration
148+
149+
Given an NPN configuration, which contains a representative
150+
function, input/output negations, and input permutations this
151+
function computes the original truth table.
152+
153+
\param config NPN configuration
154+
*/
155+
template<typename TT>
156+
TT create_from_npn_config( const std::tuple<TT, uint32_t, std::vector<uint8_t>>& config )
157+
{
158+
const auto& from = std::get<0>( config );
159+
const auto& phase = std::get<1>( config );
160+
auto perm = std::get<2>( config );
161+
const auto num_vars = from.num_vars();
162+
163+
/* is output complemented? */
164+
auto res = ( ( phase >> num_vars ) & 1 ) ? ~from : from;
165+
166+
/* input permutations */
167+
for ( auto i = 0; i < num_vars; ++i )
168+
{
169+
if ( perm[i] == i ) continue;
170+
171+
int k = i;
172+
while ( perm[k] != i )
173+
{
174+
++k;
175+
}
176+
177+
swap_inplace( res, i, k );
178+
std::swap( perm[i], perm[k] );
179+
}
180+
181+
/* input complementations */
182+
for ( auto i = 0; i < num_vars; ++i )
183+
{
184+
if ( ( phase >> i ) & 1 )
185+
{
186+
flip_inplace( res, i );
187+
}
188+
}
189+
190+
191+
return res;
192+
}
193+
194+
} // namespace kitty

0 commit comments

Comments
 (0)