bool embed_truth_table( binary_truth_table& spec, const binary_truth_table& base, properties::ptr settings, properties::ptr statistics ) { std::string garbage_name = get<std::string>( settings, "garbage_name", "g" ); std::vector<unsigned> output_order = get<std::vector<unsigned> >( settings, "output_order", std::vector<unsigned>() ); timer<properties_timer> t; if ( statistics ) { properties_timer rt( statistics ); t.start( rt ); } /* get number of additional garbage lines needed */ std::vector<unsigned> values; unsigned ag = additional_garbage( base, values ); ag = (unsigned)std::max( (int)ag, (int)base.num_inputs() - (int)base.num_outputs() ); unsigned cons = base.num_outputs() + ag - base.num_inputs(); /* we don't need more than that */ assert( base.num_inputs() <= base.num_outputs() + ag ); /* new number of bits */ std::map<unsigned, unsigned> new_spec; unsigned new_bw = base.num_outputs() + ag; /* all outputs which are left */ std::vector<unsigned> all_outputs( 1u << new_bw ); std::copy( boost::make_counting_iterator( 0u ), boost::make_counting_iterator( 1u << new_bw ), all_outputs.begin() ); { /* greedy method */ std::map<unsigned,std::vector<unsigned> > output_assignments; /* output order */ if ( output_order.size() != base.num_outputs() ) { output_order.clear(); std::copy( boost::make_counting_iterator( 0u ), boost::make_counting_iterator( base.num_outputs() ), std::back_inserter( output_order ) ); } /* not in output order for filling up */ std::vector<unsigned> left_positions; for ( unsigned order = 0u; order < new_bw; ++order ) { if ( std::find( output_order.begin(), output_order.end(), order ) == output_order.end() ) { left_positions += order; } } /* since you append the garbage to the end, just count the numbers */ for ( std::vector<unsigned>::const_iterator itValue = values.begin(); itValue != values.end(); ++itValue ) { unsigned base = 0u; for ( unsigned j = 0u; j < output_order.size(); ++j ) { unsigned bit_in_value = !!( *itValue & ( 1u << ( output_order.size() - 1u - j ) ) ); unsigned bit_pos_in_base = new_bw - 1u - output_order.at( j ); base |= ( bit_in_value << bit_pos_in_base ); } /* create the values from (value)0..0 to (value)1..1 with rebaset to output_order */ std::vector<unsigned> assignments; for ( unsigned j = 0u; j < ( 1u << ag ); ++j ) { unsigned assignment = base; for ( unsigned k = 0; k < ag; ++k ) { unsigned bit_in_value = !!( j & ( 1u << ( ag - 1u - k ) ) ); unsigned bit_pos_in_base = new_bw - 1u - left_positions.at( k ); assignment |= ( bit_in_value << bit_pos_in_base ); } assignments += assignment; } output_assignments[*itValue] = assignments; } /* truth table is in order */ for ( binary_truth_table::const_iterator it = base.begin(); it != base.end(); ++it ) { /* input value */ binary_truth_table::cube_type in( it->first.first, it->first.second ); unsigned number_in = truth_table_cube_to_number( in ); /* output value */ binary_truth_table::cube_type out( it->second.first, it->second.second ); unsigned number = truth_table_cube_to_number( out ); /* best suiting element */ std::vector<unsigned>::iterator bestFit = std::min_element( output_assignments[number].begin(), output_assignments[number].end(), minimal_hamming_distance( number_in ) ); new_spec.insert( std::make_pair( number_in, *bestFit ) ); /* remove element from list */ all_outputs.erase( std::find( all_outputs.begin(), all_outputs.end(), *bestFit ) ); output_assignments[number].erase( bestFit ); } } for ( unsigned i = 0u; i < ( 1u << new_bw ); ++i ) { if ( new_spec.find( i ) == new_spec.end() ) { std::vector<unsigned>::iterator bestFit = std::min_element( all_outputs.begin(), all_outputs.end(), minimal_hamming_distance( i ) ); new_spec.insert( std::make_pair( i, *bestFit ) ); all_outputs.erase( bestFit ); } } spec.clear(); for ( std::map<unsigned, unsigned>::const_iterator it = new_spec.begin(); it != new_spec.end(); ++it ) { spec.add_entry( number_to_truth_table_cube( it->first, new_bw ), number_to_truth_table_cube( it->second, new_bw ) ); } /* meta-data */ std::vector<std::string> inputs( new_bw, "i" ); std::fill( inputs.begin(), inputs.begin() + cons, "0" ); std::copy( base.inputs().begin(), base.inputs().end(), inputs.begin() + cons ); spec.set_inputs( inputs ); std::vector<std::string> outputs( new_bw, garbage_name ); for ( std::vector<unsigned>::iterator it = output_order.begin(); it != output_order.end(); ++it ) { unsigned index = std::distance( output_order.begin(), it ); if ( index < base.outputs().size() ) { outputs.at( *it ) = base.outputs().at( index ); } } spec.set_outputs( outputs ); std::vector<constant> constants( new_bw ); std::fill( constants.begin(), constants.begin() + cons, false ); std::fill( constants.begin() + cons, constants.end(), constant() ); spec.set_constants( constants ); std::vector<bool> garbage( new_bw, true ); for ( std::vector<unsigned>::const_iterator it = output_order.begin(); it != output_order.end(); ++it ) { garbage.at( *it ) = false; } spec.set_garbage( garbage ); return true; }
void extend_pla( binary_truth_table& base, binary_truth_table& extended, const extend_pla_settings& settings ) { // copy metadata extended.set_inputs( base.inputs() ); extended.set_outputs( base.outputs() ); // CUDD stuff Cudd mgr( 0, 0 ); std::vector<BDD> vars( base.num_inputs() ); boost::generate( vars, [&mgr]() { return mgr.bddVar(); } ); // A function to create a BDD from a cube auto bddFromCube = [&mgr, &vars]( const std::pair<binary_truth_table::cube_type::const_iterator, binary_truth_table::cube_type::const_iterator>& cube ) { BDD c = mgr.bddOne(); unsigned pos = 0u; for ( const auto& literal : boost::make_iterator_range( cube.first, cube.second ) ) { if ( literal ) c &= ( *literal ? vars.at( pos ) : !vars.at( pos ) ); ++pos; } return c; }; // A function to get truth table cubes from a BDD auto cubesFromBdd = [&mgr, &vars]( BDD& from, std::vector<binary_truth_table::cube_type>& cubes ) { char * cube = new char[vars.size()]; unsigned pos; while ( from.CountMinterm( vars.size() ) > 0.0 ) { from.PickOneCube( cube ); binary_truth_table::cube_type tcube; BDD bcube = mgr.bddOne(); for ( pos = 0u; pos < vars.size(); ++pos ) { switch ( cube[pos] ) { case 0: bcube &= !vars.at( pos ); tcube += false; break; case 1: bcube &= vars.at( pos ); tcube += true; break; case 2: tcube += boost::optional<bool>(); break; } } cubes += tcube; from &= !bcube; } delete[] cube; }; while ( std::distance( base.begin(), base.end() ) > 0 ) { // Pick one cube from base binary_truth_table::iterator base_cube = base.begin(); binary_truth_table::cube_type base_in( base_cube->first.first, base_cube->first.second ); binary_truth_table::cube_type base_out( base_cube->second.first, base_cube->second.second ); if ( settings.verbose ) { std::cout << "[I] Processing:" << std::endl; std::cout << "[I] "; std::for_each( base_cube->first.first, base_cube->first.second, []( const boost::optional<bool>& b ) { std::cout << (b ? (*b ? "1" : "0") : "-"); } ); std::cout << " "; std::for_each( base_cube->second.first, base_cube->second.second, []( const boost::optional<bool>& b ) { std::cout << (b ? (*b ? "1" : "0") : "-"); } ); std::cout << std::endl; } BDD bicube = bddFromCube( base_cube->first ); base.remove_entry( base_cube ); // Go through all cubes of extended bool found_match = false; for ( binary_truth_table::iterator extended_cube = extended.begin(); extended_cube != extended.end(); ++extended_cube ) { BDD bocube = bddFromCube( extended_cube->first ); if ( ( bicube & bocube ).CountMinterm( base.num_inputs() ) > 0.0 ) { if ( settings.verbose ) { std::cout << "[I] Intersection detected with" << std::endl; std::cout << "[I] "; std::for_each( extended_cube->first.first, extended_cube->first.second, []( const boost::optional<bool>& b ) { std::cout << (b ? (*b ? "1" : "0") : "-"); } ); std::cout << " "; std::for_each( extended_cube->second.first, extended_cube->second.second, []( const boost::optional<bool>& b ) { std::cout << (b ? (*b ? "1" : "0") : "-"); } ); std::cout << std::endl; } binary_truth_table::cube_type extended_in( extended_cube->first.first, extended_cube->first.second ); binary_truth_table::cube_type extended_out( extended_cube->second.first, extended_cube->second.second ); extended.remove_entry( extended_cube ); BDD keep_in_base = bicube & !bocube; BDD intersection = bicube & bocube; BDD keep_in_extended = !bicube & bocube; std::vector<binary_truth_table::cube_type> cubes; cubesFromBdd( keep_in_base, cubes ); for ( const auto& cube : cubes ) { bool match = false; for ( binary_truth_table::iterator base_inner_cube = base.begin(); base_inner_cube != base.end(); ++base_inner_cube ) { binary_truth_table::cube_type base_inner_in( base_inner_cube->first.first, base_inner_cube->first.second ); binary_truth_table::cube_type base_inner_out( base_inner_cube->second.first, base_inner_cube->second.second ); if ( cube == base_inner_in ) { base.remove_entry( base_inner_cube ); base.add_entry( cube, combine_pla_cube( base_out, base_inner_out ) ); match = true; break; } } if ( !match ) { base.add_entry( cube, base_out ); } } cubes.clear(); cubesFromBdd( intersection, cubes ); for ( const auto& cube : cubes ) extended.add_entry( cube, combine_pla_cube( base_out, extended_out ) ); cubes.clear(); cubesFromBdd( keep_in_extended, cubes ); for ( const auto& cube : cubes ) extended.add_entry( cube, extended_out ); found_match = true; break; } } // Copy the base_cube if no match has been found if ( !found_match ) { if ( settings.verbose ) { std::cout << "[I] Add directly!" << std::endl; } extended.add_entry( base_in, base_out ); } if ( settings.verbose ) { std::cout << "[I] base:" << std::endl; std::cout << base << std::endl; std::cout << "[I] extended:" << std::endl; std::cout << extended << std::endl << std::endl; } } /* Compact */ if ( settings.post_compact ) { // Compute compacted nouns std::map<binary_truth_table::cube_type, BDD> compacted_monoms; for ( const auto& row : extended ) { BDD in_cube = bddFromCube( row.first ); binary_truth_table::cube_type out_pattern( row.second.first, row.second.second ); auto it = compacted_monoms.find( out_pattern ); if ( it == compacted_monoms.end() ) { compacted_monoms[out_pattern] = in_cube; } else { it->second |= in_cube; } } // Clear extended PLA representation extended.clear(); // Add compacted monoms back to PLA representation for ( const auto& p : compacted_monoms ) { std::vector<binary_truth_table::cube_type> cubes; BDD bdd = p.second; cubesFromBdd( bdd, cubes ); for ( const auto& cube : cubes ) extended.add_entry( cube, p.first ); } } }