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;
  }
Example #2
0
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 );
    }
  }
}