Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Classification-SD #119

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ add_example(spectral_enumeration spectral_enumeration.cpp)
add_example(spectral_enumeration_file spectral_enumeration_file.cpp)
add_example(spectral_enumeration_map spectral_enumeration_map.cpp)
add_example(spectral_enumeration_fuller spectral_enumeration_fuller.cpp)
add_example(sd sd.cpp)
68 changes: 68 additions & 0 deletions examples/sd.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* kitty: C++ truth table library
* Copyright (C) 2017-2020 EPFL
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

#include <iostream>
#include <unordered_set>

#include <kitty/kitty.hpp>

int main()
{

uint32_t num_vars = 2u;
const auto classes_2u = kitty::calculate_sd_represtative_class( num_vars );

/* Print the size of the class. */
std::cout << "[i] enumerated "
<< ( 1 << ( 1 << num_vars ) ) << " functions into "
<< classes_2u.size() << " classes." << std::endl;

num_vars = 3u;
const auto classes_3u = kitty::calculate_sd_represtative_class( num_vars );

/* Print the size of the class. */
std::cout << "[i] enumerated "
<< ( 1 << ( 1 << num_vars ) ) << " functions into "
<< classes_3u.size() << " classes." << std::endl;

num_vars = 4u;
const auto classes_4u = kitty::calculate_sd_represtative_class( num_vars );

/* Print the size of the class. */
std::cout << "[i] enumerated "
<< ( 1 << ( 1 << num_vars ) ) << " functions into "
<< classes_4u.size() << " classes." << std::endl;

/*Disabling this example as it takes a long time to evaluate NPN (dependent) class for 6 variables.*/
/*num_vars = 5u;
const auto classes_5u = kitty::calculate_sd_represtative_class( num_vars );

// Print the size of the class.
std::cout << "[i] enumerated "
<< ( 1 << ( 1 << num_vars ) ) << " functions into "
<< classes_5u.size() << " classes." << std::endl;
*/
return 0;
}
3 changes: 2 additions & 1 deletion include/kitty/kitty.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include "implicant.hpp"
#include "isop.hpp"
#include "npn.hpp"
#include "sd.hpp"
#include "operations.hpp"
#include "operators.hpp"
#include "permutation.hpp"
Expand All @@ -64,4 +65,4 @@
/ \
/ ___ \
\/___\/
*/
*/
113 changes: 106 additions & 7 deletions include/kitty/npn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ std::tuple<TT, uint32_t, std::vector<uint8_t>> exact_p_canonization( const TT& t
/* Special case for n = 1 */
if ( num_vars == 1 )
{
return std::make_tuple( tt, 0u, std::vector<uint8_t>{0} );
return std::make_tuple( tt, 0u, std::vector<uint8_t>{ 0 } );
}

assert( num_vars >= 2 && num_vars <= 7 );
Expand Down Expand Up @@ -171,7 +171,7 @@ std::tuple<TT, uint32_t, std::vector<uint8_t>> exact_npn_canonization( const TT&
if ( num_vars == 1 )
{
const auto bit1 = get_bit( tt, 1 );
return std::make_tuple( unary_not_if( tt, bit1 ), static_cast<uint32_t>( bit1 << 1 ), std::vector<uint8_t>{0} );
return std::make_tuple( unary_not_if( tt, bit1 ), static_cast<uint32_t>( bit1 << 1 ), std::vector<uint8_t>{ 0 } );
}

assert( num_vars >= 2 && num_vars <= 6 );
Expand Down Expand Up @@ -262,6 +262,106 @@ std::tuple<TT, uint32_t, std::vector<uint8_t>> exact_npn_canonization( const TT&
return std::make_tuple( tmin, phase, perm );
}

/*! \brief Exact NPN Represtative

Given a truth table, this function finds the lexicographically smallest truth
table in its NPN class, called NPN representative. Two functions are in the
same NPN class, if one can obtain one from the other by input negation, input
permutation, and output negation.

The function can accept a callback as second parameter which is called for
every visited function when trying out all combinations. This allows to
exhaustively visit the whole NPN class.

The function returns a NPN representative (truth table).

\param tt The truth table (with at most 6 variables)
\param fn Callback for each visited truth table in the class (default does nothing)
\return NPN representative
*/
template<typename TT, typename Callback = decltype( kitty::detail::exact_npn_canonization_null_callback<TT> )>
TT exact_npn_representative( const TT& tt, Callback&& fn = kitty::detail::exact_npn_canonization_null_callback<TT> )
{

static_assert( kitty::is_complete_truth_table<TT>::value, "Can only be applied on complete truth tables." );

const auto num_vars = tt.num_vars();

/* Special case for n = 0 */
if ( num_vars == 0 )
{
const auto bit = get_bit( tt, 0 );
return kitty::unary_not_if( tt, bit );
}

/* Special case for n = 1 */
if ( num_vars == 1 )
{
const auto bit1 = get_bit( tt, 1 );
return kitty::unary_not_if( tt, bit1 );
}

assert( num_vars >= 2 && num_vars <= 6 );

auto t1 = tt, t2 = ~tt;
auto tmin = std::min( t1, t2 );

fn( t1 );
fn( t2 );

const auto& swaps = kitty::detail::swaps[num_vars - 2u];
const auto& flips = kitty::detail::flips[num_vars - 2u];

for ( std::size_t i = 0; i < swaps.size(); ++i )
{
const auto pos = swaps[i];
kitty::swap_adjacent_inplace( t1, pos );
kitty::swap_adjacent_inplace( t2, pos );

fn( t1 );
fn( t2 );

if ( t1 < tmin || t2 < tmin )
{
tmin = std::min( t1, t2 );
}
}

for ( std::size_t j = 0; j < flips.size(); ++j )
{
const auto pos = flips[j];
kitty::swap_adjacent_inplace( t1, 0 );
kitty::flip_inplace( t1, pos );
kitty::swap_adjacent_inplace( t2, 0 );
kitty::flip_inplace( t2, pos );

fn( t1 );
fn( t2 );

if ( t1 < tmin || t2 < tmin )
{
tmin = std::min( t1, t2 );
}

for ( std::size_t i = 0; i < swaps.size(); ++i )
{
const auto pos = swaps[i];
kitty::swap_adjacent_inplace( t1, pos );
kitty::swap_adjacent_inplace( t2, pos );

fn( t1 );
fn( t2 );

if ( t1 < tmin || t2 < tmin )
{
tmin = std::min( t1, t2 );
}
}
}

return tmin;
}

/*! \brief Flip-swap NPN heuristic

This algorithm will iteratively try to reduce the numeric value of the truth
Expand Down Expand Up @@ -292,7 +392,7 @@ std::tuple<TT, uint32_t, std::vector<uint8_t>> flip_swap_npn_canonization( const
std::vector<uint8_t> perm( num_vars );
std::iota( perm.begin(), perm.end(), 0u );

uint32_t phase{0u};
uint32_t phase{ 0u };

auto npn = tt;
auto improvement = true;
Expand Down Expand Up @@ -438,7 +538,6 @@ void sifting_p_canonization_loop( TT& p, uint32_t& phase, std::vector<uint8_t>&
}
forward = !forward;
}

}
} /* namespace detail */
/*! \endcond */
Expand Down Expand Up @@ -471,7 +570,7 @@ std::tuple<TT, uint32_t, std::vector<uint8_t>> sifting_npn_canonization( const T
/* initialize permutation and phase */
std::vector<uint8_t> perm( num_vars );
std::iota( perm.begin(), perm.end(), 0u );
uint32_t phase{0u};
uint32_t phase{ 0u };

if ( num_vars < 2 )
{
Expand Down Expand Up @@ -528,7 +627,7 @@ std::tuple<TT, uint32_t, std::vector<uint8_t>> sifting_p_canonization( const TT&
/* initialize permutation and phase */
std::vector<uint8_t> perm( num_vars );
std::iota( perm.begin(), perm.end(), 0u );
uint32_t phase{0u};
uint32_t phase{ 0u };

if ( num_vars < 2u )
{
Expand Down Expand Up @@ -593,4 +692,4 @@ TT create_from_npn_config( const std::tuple<TT, uint32_t, std::vector<uint8_t>>&
return res;
}

} /* namespace kitty */
} /* namespace kitty */
59 changes: 49 additions & 10 deletions include/kitty/operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ template<typename TT>
inline TT unary_not_if( const TT& tt, bool cond )
{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4146)
#pragma warning( push )
#pragma warning( disable : 4146 )
#endif
const auto mask = -static_cast<uint64_t>( cond );
#ifdef _MSC_VER
#pragma warning(pop)
#pragma warning( pop )
#endif
return unary_operation( tt, [mask]( auto a ) { return a ^ mask; } );
}
Expand Down Expand Up @@ -142,10 +142,9 @@ inline TT mux_var( uint8_t var_index, const TT& then_, const TT& else_ )
auto res = then_.construct();

std::transform( then_.begin(), then_.end(), else_.begin(), res.begin(),
[&]( auto a, auto b ) {
return ( j++ % ( 2 * step ) ) < step ? b : a;
}
);
[&]( auto a, auto b ) {
return ( j++ % ( 2 * step ) ) < step ? b : a;
} );

return res;
}
Expand Down Expand Up @@ -483,7 +482,7 @@ void swap_adjacent_inplace( TT& tt, uint8_t var_index )
auto it = std::begin( tt._bits );
while ( it != std::end( tt._bits ) )
{
for ( auto i = decltype( step ){0}; i < step; ++i )
for ( auto i = decltype( step ){ 0 }; i < step; ++i )
{
std::swap( *( it + i + step ), *( it + i + 2 * step ) );
}
Expand Down Expand Up @@ -567,7 +566,7 @@ void swap_inplace( TT& tt, uint8_t var_index1, uint8_t var_index2 )
auto it = std::begin( tt._bits );
while ( it != std::end( tt._bits ) )
{
for ( auto i = decltype( step ){0}; i < step; ++i )
for ( auto i = decltype( step ){ 0 }; i < step; ++i )
{
const auto low_to_high = ( *( it + i ) & detail::projections[var_index1] ) >> shift;
const auto high_to_low = ( *( it + i + step ) << shift ) & detail::projections[var_index1];
Expand Down Expand Up @@ -666,7 +665,7 @@ void flip_inplace( TT& tt, uint8_t var_index )
auto it = std::begin( tt._bits );
while ( it != std::end( tt._bits ) )
{
for ( auto i = decltype( step ){0}; i < step; ++i )
for ( auto i = decltype( step ){ 0 }; i < step; ++i )
{
std::swap( *( it + i ), *( it + i + step ) );
}
Expand Down Expand Up @@ -1191,4 +1190,44 @@ inline TT shift_with_mask( const TT& f, uint8_t mask )
return copy;
}

/*! \brief Calculates the dual function of the passed truth table.

\param tt Truth table
\return dual of given truth table
*/
template<typename TT, typename = std::enable_if_t<kitty::is_complete_truth_table<TT>::value>>
kitty::dynamic_truth_table dual_of( const TT& tt )
{
auto numvars = tt.num_vars();
auto tt1 = tt;
auto tt2 = ~tt1;
for ( auto i = 0u; i < numvars; i++ )
{
tt1 = flip( tt1, i );
}
return ~tt1;
}

/*! \brief Extends a given truth table with 'n' variables to
'n+1' variables. To extend, it appends the given truth table
in the end of the given truth table.

\param tt Truth table
\return extended Truth Table
*/
template<typename TT, typename = std::enable_if_t<kitty::is_complete_truth_table<TT>::value>>
kitty::dynamic_truth_table extend_tt( const TT& tt )
{
int num_vars = (int)tt.num_vars();
kitty::dynamic_truth_table extended_tt( num_vars + 1 );
for ( int i = 0; i < (int)extended_tt.num_bits(); i++ )
{
if ( kitty::get_bit( tt, i % ( tt.num_bits() ) ) == 1 )
{
kitty::set_bit( extended_tt, i );
}
}
return extended_tt;
}

} // namespace kitty
Loading