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

Project 1 #41

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
166 changes: 148 additions & 18 deletions include/kitty/threshold_identification.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,6 @@
\author CS-472 2020 Fall students
*/

#pragma once

#include <vector>
// #include <lpsolve/lp_lib.h> /* uncomment this line to include lp_solve */
#include "traits.hpp"

namespace kitty
{

/*! \brief Threshold logic function identification

Given a truth table, this function determines whether it is a threshold logic function (TF)
Expand All @@ -55,22 +46,161 @@ namespace kitty
in the end.
\return `true` if `tt` is a TF; `false` if `tt` is a non-TF.
*/

#pragma once
#include "isop.hpp"
#include "operations.hpp"
#include "algorithm.hpp"
#include <vector>
#include <fstream>
#include <iostream>
#include <lpsolve/lp_lib.h> /* uncomment this line to include lp_solve */
#include "traits.hpp"


namespace kitty
{
// unate_in_var returns true if the function is unate in a single variable , false if not
template<typename TT, typename = std::enable_if_t<is_complete_truth_table<TT>::value>>
bool unate_in_var( TT& tt, uint8_t var )
{
/*uint8_t numvars = tt.num_vars();*/
/* co-factor */
auto const tt1 = cofactor0( tt, var );
auto const tt2 = cofactor1( tt, var );
if ( binary_predicate( tt1, tt2, std::greater_equal<>()) || binary_predicate( tt1,tt2, std ::less_equal<>()) )
{
return true;
}
else
{
return false;
}
}
// neg_unate_in_var returns true if the function is negative unate in a single variable , false if not
template<typename TT, typename = std::enable_if_t<is_complete_truth_table<TT>::value>>
bool neg_unate_in_var(const TT& tt, uint8_t var)
{
/* co-factor */
auto const tt2 = cofactor0( tt, var );
auto const tt1 = cofactor1( tt, var );
if (binary_predicate( tt1,tt2, std ::less_equal<>() )){
return true;

}
return false;

}


template<typename TT, typename = std::enable_if_t<is_complete_truth_table<TT>::value>>
bool is_threshold( const TT& tt, std::vector<int64_t>* plf = nullptr )
{
std::vector<int64_t> linear_form;
uint8_t numvars = tt.num_vars();
TT tt_copy = tt; // tt_copy will be built to be equal to the function f*

/* TODO */
/* if tt is non-TF: */
return false;

/* if tt is TF: */
/* push the weight and threshold values into `linear_form` */
if ( plf )
std::vector<int64_t> linear_form(numvars + 1, 0);
std::vector<bool> negative_unate(numvars, false); // a vector of booleans that will define the type of uunateness of the function for each variable.

// Check if the given function is unate
for ( uint8_t i(0); i < numvars; ++i )
{
if (! unate_in_var(tt_copy, i) )return false;


if ( neg_unate_in_var(tt,i))
{
negative_unate[i] = true;// This vector stores the original type of unateness in each variable

flip_inplace(tt_copy, i); // so as we obtain a positive unate function in all the variables.


}
}
// if the function is unate: Create constraints
// to speed up the ILP part, we can work on the irredundant SOP representations.

std:: vector<cube> ONset (isop(tt_copy));
std:: vector<cube> OFFset (isop(~tt_copy));
// the model is built row by row , so in the beginning we will start by creating a model with 0 rows and numvars + 1 columns
auto lp = make_lp( 0, numvars + 1 ); // numvars+1= number of columns comprising the varables and threshold

set_verbose( lp, 1 );

std::vector<REAL> row(numvars + 2, 0);
row[numvars + 1] = -1; // Threshold
REAL *Obj_fun = &row[0]; // pointer to the objective function :An array with 1+column elements that contains the values of the objective function.

// construct rows for ONset
for ( auto &cube: ONset )
{
for ( auto i = 0u; i < numvars; ++i )
{
if ( cube.get_mask(i) && cube.get_bit(i) )
row[i + 1] = 1; // vector on which we will apply the ON_constraits
else
row[i + 1] = 0;
}
add_constraint(lp, Obj_fun, GE, 0);
}

// construct rows for OFFset
for ( auto &cube: OFFset )
{
*plf = linear_form;
for ( auto i = 0u; i < numvars; ++i )
{
if ( !cube.get_mask(i) || cube.get_bit(i) )
row[i + 1] = 1;
else
row[i + 1] = 0;
}
add_constraint(lp, Obj_fun, LE, -1);
}


for ( auto i = 1u; i <= numvars + 1; ++i )
{
row[i] = 1;
}
set_obj_fn( lp, Obj_fun );




if ( solve( lp ) == INFEASIBLE )
return false;



if ( plf )
{
// recuperate the solution for f*
REAL *solution;
get_ptr_variables( lp, &solution );
// change the weights corresponding to the variables where the original function is negative unate .

for ( auto var = 0u; var < numvars + 1; ++var )
linear_form[var] = solution[var];

for ( auto var = 0u; var < numvars; ++var )

if ( negative_unate[var] ) {
linear_form.back() -= linear_form[var];
linear_form[var] = -linear_form[var];
}

plf->swap(linear_form);

}
return true;
}


if (lp != 0) {
/* clean up such that all used memory by lpsolve is freed */
delete_lp(lp);
}

//write_lp(lp, "model.lp");
}
} /* namespace kitty */