mirror of https://github.com/YosysHQ/abc.git
1248 lines
43 KiB
C
Executable File
1248 lines
43 KiB
C
Executable File
/**CFile****************************************************************
|
|
|
|
FileName [utilNet.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [Network synthesis.]
|
|
|
|
Synopsis [Network synthesis.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - June 20, 2005.]
|
|
|
|
Revision [$Id: utilNet.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
|
|
#include "abc_global.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
// the max number of nodes
|
|
#define MSIZE 15
|
|
|
|
/*************************************************************
|
|
literal manipulation, etc
|
|
**************************************************************/
|
|
|
|
// operations on variables and literals
|
|
static inline int tn_v2l( int Var, int c ) { assert(Var >= 0 && !(c >> 1)); return Var + Var + c; }
|
|
static inline int tn_l2v( int Lit ) { assert(Lit >= 0); return Lit >> 1; }
|
|
static inline int tn_l2c( int Lit ) { assert(Lit >= 0); return Lit & 1; }
|
|
static inline int tn_lnot( int Lit ) { assert(Lit >= 0); return Lit ^ 1; }
|
|
static inline int tn_lnotc( int Lit, int c ) { assert(Lit >= 0); return Lit ^ (int)(c > 0); }
|
|
static inline int tn_lreg( int Lit ) { assert(Lit >= 0); return Lit & ~01; }
|
|
|
|
// min/max/abs
|
|
static inline int tn_abs( int a ) { return a < 0 ? -a : a; }
|
|
static inline int tn_max( int a, int b ) { return a > b ? a : b; }
|
|
static inline int tn_min( int a, int b ) { return a < b ? a : b; }
|
|
|
|
// swapping two variables
|
|
#define TN_SWAP(Type, a, b) { Type t = a; a = b; b = t; }
|
|
|
|
/*************************************************************
|
|
Vector of 32-bit integers
|
|
**************************************************************/
|
|
|
|
typedef struct tn_vi_ {
|
|
int size;
|
|
int cap;
|
|
int* ptr;
|
|
} tn_vi;
|
|
|
|
// iterator through the entries in the vector
|
|
#define tn_vi_for_each_entry( v, entry, i ) \
|
|
for (i = 0; (i < (v)->size) && (((entry) = tn_vi_read((v), i)), 1); i++)
|
|
#define tn_vi_for_each_set( v, size, i ) \
|
|
for (i = 0; (i < (v)->size) && (((size) = tn_vi_read((v), i++)), 1); i += size)
|
|
|
|
static inline void tn_vi_start (tn_vi* v, int cap) { v->size = 0; v->cap = cap; v->ptr = (int*)malloc( sizeof(int)*v->cap); }
|
|
static inline void tn_vi_stop (tn_vi* v) { if ( v->ptr ) free(v->ptr); }
|
|
static inline tn_vi* tn_vi_alloc (int cap) { tn_vi* v = (tn_vi *)malloc(sizeof(tn_vi)); tn_vi_start(v, cap); return v; }
|
|
static inline void tn_vi_free (tn_vi* v) { if ( v->ptr ) free(v->ptr); free(v); }
|
|
static inline int* tn_vi_array (tn_vi* v) { return v->ptr; }
|
|
static inline int tn_vi_read (tn_vi* v, int k) { assert(k < v->size); return v->ptr[k]; }
|
|
static inline void tn_vi_write (tn_vi* v, int k, int e) { assert(k < v->size); v->ptr[k] = e; }
|
|
static inline int tn_vi_size (tn_vi* v) { return v->size; }
|
|
static inline void tn_vi_resize (tn_vi* v, int k) { assert(k <= v->size); v->size = k; } // only safe to shrink !!
|
|
static inline int tn_vi_pop (tn_vi* v) { assert(v->size > 0); return v->ptr[--v->size]; }
|
|
static inline void tn_vi_grow (tn_vi* v)
|
|
{
|
|
if (v->size < v->cap)
|
|
return;
|
|
int newcap = (v->cap < 4) ? 8 : (v->cap / 2) * 3;
|
|
v->ptr = (int*)realloc( v->ptr, sizeof(int)*newcap );
|
|
if ( v->ptr == NULL )
|
|
{
|
|
printf( "Failed to realloc memory from %.1f MB to %.1f MB.\n", 4.0 * v->cap / (1<<20), 4.0 * newcap / (1<<20) );
|
|
fflush( stdout );
|
|
}
|
|
v->cap = newcap;
|
|
}
|
|
static inline void tn_vi_push (tn_vi* v, int e) { tn_vi_grow(v); v->ptr[v->size++] = e; }
|
|
static inline void tn_vi_fill (tn_vi* v, int n, int fill) { int i; tn_vi_resize(v, 0); for (i = 0; i < n; i++) tn_vi_push(v, fill); }
|
|
static inline int tn_vi_remove(tn_vi* v, int e)
|
|
{
|
|
int j;
|
|
for ( j = 0; j < v->size; j++ )
|
|
if ( v->ptr[j] == e )
|
|
break;
|
|
if ( j == v->size )
|
|
return 0;
|
|
for ( ; j < v->size-1; j++ )
|
|
v->ptr[j] = v->ptr[j+1];
|
|
tn_vi_resize( v, v->size-1 );
|
|
return 1;
|
|
}
|
|
static inline tn_vi * tn_vi_dup(tn_vi* v) {
|
|
tn_vi * p = tn_vi_alloc(v->size);
|
|
p->size = v->size;
|
|
memmove(p->ptr, v->ptr, sizeof(int)*p->size);
|
|
return p;
|
|
}
|
|
static inline void tn_vi_print(tn_vi* v) {
|
|
printf( "Array with %d entries:", v->size ); int i, entry;
|
|
tn_vi_for_each_entry( v, entry, i )
|
|
printf( " %d", entry );
|
|
printf( "\n" );
|
|
}
|
|
static inline void tn_vi_print_sets(tn_vi* v) {
|
|
int i, k, size, count = 0;
|
|
tn_vi_for_each_set( v, size, i )
|
|
count++;
|
|
printf( "Array with %d sets:\n", count );
|
|
count = 0;
|
|
tn_vi_for_each_set( v, size, i ) {
|
|
printf( "Set %3d : ", count );
|
|
printf( "Size %3d :", size );
|
|
for ( k = 0; k < size; k++ )
|
|
printf( " %d", tn_vi_read(v, i+k) );
|
|
printf( "\n" );
|
|
count++;
|
|
}
|
|
}
|
|
|
|
/*************************************************************
|
|
counting wall time
|
|
**************************************************************/
|
|
|
|
static inline iword Tn_Clock()
|
|
{
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
#define APPLE_MACH (__APPLE__ & __MACH__)
|
|
#else
|
|
#define APPLE_MACH 0
|
|
#endif
|
|
#if (defined(LIN) || defined(LIN64)) && !APPLE_MACH && !defined(__MINGW32__)
|
|
struct timespec ts;
|
|
if ( clock_gettime(CLOCK_MONOTONIC, &ts) < 0 )
|
|
return (iword)-1;
|
|
iword res = ((iword) ts.tv_sec) * CLOCKS_PER_SEC;
|
|
res += (((iword) ts.tv_nsec) * CLOCKS_PER_SEC) / 1000000000;
|
|
return res;
|
|
#else
|
|
return (iword) clock();
|
|
#endif
|
|
}
|
|
static inline void Tn_PrintTime( const char * pStr, iword time )
|
|
{
|
|
printf( "%s = %9.2f sec\n", pStr, 1.0*((double)(time))/((double)CLOCKS_PER_SEC));
|
|
}
|
|
static inline int Tn_Base2Log( unsigned n )
|
|
{
|
|
int r; if ( n < 2 ) return (int)n; for ( r = 0, n--; n; n >>= 1, r++ ) {}; return r;
|
|
}
|
|
|
|
/*************************************************************
|
|
Permutation generation
|
|
**************************************************************/
|
|
|
|
// generate next permutation in lexicographic order
|
|
static void Tn_GetNextPerm(int *currPerm, int nVars)
|
|
{
|
|
int i = nVars - 1;
|
|
while (i >= 0 && currPerm[i - 1] >= currPerm[i])
|
|
i--;
|
|
if (i >= 0)
|
|
{
|
|
int j = nVars;
|
|
while (j > i && currPerm[j - 1] <= currPerm[i - 1])
|
|
j--;
|
|
TN_SWAP(int, currPerm[i - 1], currPerm[j - 1])
|
|
i++;
|
|
j = nVars;
|
|
while (i < j)
|
|
{
|
|
TN_SWAP(int, currPerm[i - 1], currPerm[j - 1])
|
|
i++;
|
|
j--;
|
|
}
|
|
}
|
|
}
|
|
static int Tn_Factorial(int nVars)
|
|
{
|
|
int i, Res = 1;
|
|
for ( i = 1; i <= nVars; i++ )
|
|
Res *= i;
|
|
return Res;
|
|
}
|
|
|
|
// permutation testing procedure
|
|
void Tn_PermTest()
|
|
{
|
|
int i, k, nVars = 5, currPerm[MSIZE] = {0};
|
|
for ( i = 0; i < nVars; i++ )
|
|
currPerm[i] = i;
|
|
int fact = Tn_Factorial( nVars );
|
|
for ( i = 0; i < fact; i++ )
|
|
{
|
|
printf( "%3d :", i );
|
|
for ( k = 0; k < nVars; k++ )
|
|
printf( " %d", currPerm[k] );
|
|
printf( "\n" );
|
|
Tn_GetNextPerm( currPerm, nVars );
|
|
}
|
|
}
|
|
|
|
/*************************************************************
|
|
cut/path generation
|
|
**************************************************************/
|
|
|
|
// pos cut vars imply the nodes are connected
|
|
static inline tn_vi * Tn_CutGen( int n, int nins )
|
|
{
|
|
tn_vi * v = tn_vi_alloc( 1000 );
|
|
int i, j, m, nMiddle = 0, Middle[MSIZE] = {0};
|
|
assert( n <= MSIZE );
|
|
for ( i = 1+nins; i < n-1; i++ )
|
|
Middle[nMiddle++] = i;
|
|
assert( nMiddle == n - nins - 2 );
|
|
for ( m = 0; m < (1<<nMiddle); m++ ) {
|
|
int nPart[2] = {0}, Part[2][MSIZE];
|
|
Part[0][nPart[0]++] = 0;
|
|
for ( i = 0; i < nMiddle; i++ )
|
|
Part[(m >> i)&1][nPart[(m >> i)&1]++] = Middle[i];
|
|
Part[1][nPart[1]++] = n-1;
|
|
tn_vi_push( v, 2*nPart[0]*nPart[1] );
|
|
for ( i = 0; i < nPart[0]; i++ )
|
|
for ( j = 0; j < nPart[1]; j++ ) {
|
|
tn_vi_push( v, Part[0][i] );
|
|
tn_vi_push( v, Part[1][j] );
|
|
}
|
|
}
|
|
//printf( "Generating cuts for %d nodes and %d inputs:\n", n, nins );
|
|
//tn_vi_print_sets( v );
|
|
return v;
|
|
}
|
|
// neg path vars imply the nodes are disconnected
|
|
static inline tn_vi * Tn_PathGen( int n, int nins )
|
|
{
|
|
tn_vi * v = tn_vi_alloc( 1000 );
|
|
assert( nins < n-2 );
|
|
tn_vi_push( v, 2 );
|
|
tn_vi_push( v, 0 );
|
|
tn_vi_push( v, n-1 );
|
|
for ( int i = 1; i <= n-2-nins; i++ ) {
|
|
int nfact = Tn_Factorial(i);
|
|
int m, nmints = 1 << (n-2-nins);
|
|
for ( m = 0; m < nmints; m++ ) {
|
|
int o, nones = 0;
|
|
for ( o = 0; o < n-2-nins; o++ )
|
|
nones += (m >> o) & 1;
|
|
if ( nones != i )
|
|
continue;
|
|
// collect variables
|
|
int j, nvars = 0, varMap[MSIZE];
|
|
for ( j = 0; j < n-2-nins; j++ )
|
|
if ( (m >> j) & 1 )
|
|
varMap[nvars++] = 1+nins+j;
|
|
assert( nvars == i );
|
|
// generate permutations
|
|
int p, currPerm[MSIZE];
|
|
for ( j = 0; j < i; j++ )
|
|
currPerm[j] = j;
|
|
for ( p = 0; p < nfact; p++ ) {
|
|
tn_vi_push( v, i+2 );
|
|
tn_vi_push( v, 0 );
|
|
for ( j = 0; j < i; j++ )
|
|
tn_vi_push( v, varMap[currPerm[j]] );
|
|
tn_vi_push( v, n-1 );
|
|
Tn_GetNextPerm( currPerm, i );
|
|
}
|
|
}
|
|
}
|
|
//printf( "Generating paths for %d nodes and %d inputs:\n", n, nins );
|
|
//tn_vi_print_sets( v );
|
|
return v;
|
|
}
|
|
static inline void Tn_SetSwap( tn_vi * p, int Obj1, int Obj2 )
|
|
{
|
|
int i, n, size, * pArray = tn_vi_array(p);
|
|
tn_vi_for_each_set( p, size, i )
|
|
for ( n = 0; n < size; n++ )
|
|
if ( pArray[i+n] == Obj1 )
|
|
pArray[i+n] = Obj2;
|
|
else if ( pArray[i+n] == Obj2 )
|
|
pArray[i+n] = Obj1;
|
|
}
|
|
|
|
|
|
/*************************************************************
|
|
generating SAT instance
|
|
**************************************************************/
|
|
|
|
typedef struct tn_gr_ {
|
|
int nIns; // primary inputs
|
|
int nOuts; // primary outputs
|
|
int nNodes; // all objects (const 1, nIns, internal nodes, nOuts)
|
|
int nNodes2; // the square of the above
|
|
int nMints; // the number of input minterms
|
|
int nEdgeLimit; // maximum transistor count
|
|
int nLevelLimit; // maximum transistor depth
|
|
int fVerbose; // user flag
|
|
char * pTypes; // control type for each node (none, neg, pos, both)
|
|
word pOuts[MSIZE]; // truth tables for each output
|
|
tn_vi * pVecs[6]; // constraints for each output
|
|
FILE * pFile; // file for CNF writing
|
|
int nCnfVars; // total number of variables
|
|
int nCnfClas; // total number of clauses
|
|
int nCnfVars2; // total number of variables
|
|
int nCnfClas2; // total number of clauses
|
|
tn_vi * vTemp[2]; // temporary vector
|
|
tn_vi * vCnf; // collected clauses
|
|
tn_vi * vSol; // assignment derived by the solver
|
|
} tn_gr;
|
|
|
|
/*************************************************************
|
|
variable mapping
|
|
**************************************************************/
|
|
|
|
static inline int Tn_MapVar( tn_gr * p, int i, int j, int Shift )
|
|
{
|
|
assert( i >= 0 && i < p->nNodes );
|
|
assert( j >= 0 && j < p->nNodes );
|
|
return Shift * p->nNodes2 + i * p->nNodes + j;
|
|
}
|
|
static inline int Tn_CtrlVar( tn_gr * p, int i, int j, int iVar, int Inv )
|
|
{
|
|
assert( i != j );
|
|
assert( iVar >= 0 && iVar < p->nIns );
|
|
assert( Inv == 0 || Inv == 1 );
|
|
if ( Inv )
|
|
return Tn_MapVar( p, tn_max(i, j), tn_min(i, j), iVar );
|
|
else
|
|
return Tn_MapVar( p, tn_min(i, j), tn_max(i, j), iVar );
|
|
}
|
|
static inline int Tn_EdgeVar( tn_gr * p, int i, int j, int Mint )
|
|
{
|
|
assert( i != j );
|
|
assert( Mint >= 0 && Mint < (1 << p->nIns) );
|
|
return Tn_MapVar( p, tn_min(i, j), tn_max(i, j), p->nIns + Mint );
|
|
}
|
|
static inline int Tn_NodeVar( tn_gr * p, int i, int Mint )
|
|
{
|
|
assert( Mint >= 0 && Mint < (1 << p->nIns) );
|
|
return Tn_MapVar( p, i, i, p->nIns + Mint );
|
|
}
|
|
static inline void Tn_PrintMapVar( tn_gr * p )
|
|
{
|
|
int i, j, n, Limit = 3; // p->nIns + (1 << p->nIns);
|
|
for ( n = 0; n < Limit; n++ ) {
|
|
printf("\n");
|
|
printf( "Set %2d : ", n );
|
|
for ( j = 0; j < p->nNodes; j++ )
|
|
printf( "%4d", j );
|
|
printf( "\n\n" );
|
|
for ( i = 0; i < p->nNodes; i++ ) {
|
|
printf( "%6d : ", i );
|
|
for ( j = 0; j < p->nNodes; j++ )
|
|
printf( "%4d", Tn_MapVar(p, i, j, n) );
|
|
printf( "\n" );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*************************************************************
|
|
graph manipulation
|
|
**************************************************************/
|
|
|
|
static inline tn_gr * Tn_Init( int nIns, int nOuts, word * pOuts, char * pTypes, int nEdgeLimit, int nLevelLimit, int fVerbose )
|
|
{
|
|
tn_gr * p = (tn_gr *)calloc( sizeof(tn_gr), 1 ); int i;
|
|
p->nIns = nIns;
|
|
p->nOuts = nOuts;
|
|
p->nNodes = strlen(pTypes);
|
|
p->nNodes2 = p->nNodes * p->nNodes;
|
|
p->nMints = 1 << p->nIns;
|
|
p->nCnfVars = p->nNodes2 * (p->nIns + p->nMints);
|
|
p->pTypes = pTypes;
|
|
p->nEdgeLimit = nEdgeLimit;
|
|
p->nLevelLimit= nLevelLimit;
|
|
p->fVerbose = fVerbose;
|
|
for ( i = 0; i < p->nNodes; i++ )
|
|
assert( pTypes[i] == '*' || pTypes[i] == '-' || (pTypes[i] >= '0' && pTypes[i] <= '2') );
|
|
assert( 1 + p->nIns + p->nOuts <= p->nNodes && p->nNodes <= MSIZE );
|
|
for ( i = 0; i < nOuts; i++ )
|
|
p->pOuts[i] = pOuts[i];
|
|
p->vCnf = tn_vi_alloc( 1000 );
|
|
p->pVecs[0] = Tn_CutGen( p->nNodes, p->nIns ); // pos -> connected
|
|
p->pVecs[1] = Tn_PathGen( p->nNodes, p->nIns ); // neg -> disconnected
|
|
assert( p->nOuts >= 1 && p->nOuts <= 3 );
|
|
if ( nOuts == 2 || nOuts == 3 ) {
|
|
Tn_SetSwap( (p->pVecs[2] = tn_vi_dup(p->pVecs[0])), p->nNodes-1, p->nNodes-2 );
|
|
Tn_SetSwap( (p->pVecs[3] = tn_vi_dup(p->pVecs[1])), p->nNodes-1, p->nNodes-2 );
|
|
}
|
|
if ( nOuts == 3 ) {
|
|
Tn_SetSwap( (p->pVecs[4] = tn_vi_dup(p->pVecs[0])), p->nNodes-1, p->nNodes-3 );
|
|
Tn_SetSwap( (p->pVecs[5] = tn_vi_dup(p->pVecs[1])), p->nNodes-1, p->nNodes-3 );
|
|
}
|
|
p->vTemp[0] = tn_vi_alloc( 100 );
|
|
p->vTemp[1] = tn_vi_alloc( 100 );
|
|
//printf( "Created graph with %d input, %d output, %d nodes and %s node types.\n", p->nIns, p->nOuts, p->nNodes, p->pTypes );
|
|
return p;
|
|
}
|
|
static inline void Tn_Free( tn_gr * p )
|
|
{
|
|
tn_vi_free(p->vCnf);
|
|
for ( int i = 0; i < 6; i++ )
|
|
if ( p->pVecs[i] )
|
|
tn_vi_free(p->pVecs[i]);
|
|
tn_vi_free(p->vTemp[0]);
|
|
tn_vi_free(p->vTemp[1]);
|
|
free(p);
|
|
}
|
|
static inline int Tn_CountLabel( tn_gr * p )
|
|
{
|
|
int i, k, v, nLabels = 0;
|
|
if ( p->vSol == NULL )
|
|
return 0;
|
|
for ( i = 0; i < p->nNodes-1; i++ )
|
|
for ( k = i+1; k < p->nNodes; k++ )
|
|
for ( v = 0; v < p->nIns; v++ )
|
|
{
|
|
int ValP = p->vSol ? tn_vi_read(p->vSol, Tn_CtrlVar(p, i, k, v, 0)) : 0;
|
|
int ValN = p->vSol ? tn_vi_read(p->vSol, Tn_CtrlVar(p, i, k, v, 1)) : 0;
|
|
assert( ValP + ValN < 2 );
|
|
nLabels += ValP + ValN;
|
|
}
|
|
return nLabels;
|
|
}
|
|
static inline void Tn_PrintStats( tn_gr * p )
|
|
{
|
|
printf( "Problem %s has %d inputs, %d outputs, %d nodes, and %d labels.\n",
|
|
p->pTypes, p->nIns, p->nOuts, p->nNodes-p->nIns, Tn_CountLabel(p) );
|
|
}
|
|
static inline void Tn_PrintGraph( tn_gr * p )
|
|
{
|
|
int i, k, v, nLabels = 0;
|
|
if ( 0 && p->vSol ) {
|
|
tn_vi_for_each_entry( p->vSol, v, i )
|
|
{
|
|
if ( i % p->nNodes2 == 0 )
|
|
printf( "\n" );
|
|
if ( i == p->nIns * p->nNodes2 )
|
|
break;
|
|
if ( v == 1 )
|
|
printf( " %d", i );
|
|
}
|
|
printf( "\n");
|
|
}
|
|
|
|
printf( " " );
|
|
for ( i = 0; i < p->nNodes; i++ ) {
|
|
for ( v = 0; v <= p->nIns-2; v++ )
|
|
printf( " " );
|
|
printf( "%2d", i );
|
|
}
|
|
printf( "\n" );
|
|
for ( i = 0; i < p->nNodes-1; i++, printf("\n") ) {
|
|
printf( "%2d : ", i );
|
|
for ( k = 0; k < p->nNodes; k++ ) {
|
|
if ( k <= i )
|
|
{
|
|
for ( v = 0; v <= p->nIns; v++ )
|
|
printf( " " );
|
|
continue;
|
|
}
|
|
for ( v = 0; v < p->nIns; v++ )
|
|
{
|
|
int ValP = p->vSol ? tn_vi_read(p->vSol, Tn_CtrlVar(p, i, k, v, 0)) : 0;
|
|
int ValN = p->vSol ? tn_vi_read(p->vSol, Tn_CtrlVar(p, i, k, v, 1)) : 0;
|
|
assert( ValP + ValN < 2 );
|
|
printf( "%c", ValP + ValN == 0 ? '-' : (ValP ? 'A' : 'a')+v );
|
|
nLabels += ValP + ValN;
|
|
}
|
|
printf(" ");
|
|
}
|
|
}
|
|
//printf( "\nTotal labels = %d.\n\n", nLabels );
|
|
}
|
|
static inline void Tn_PrintGraph2( tn_gr * p )
|
|
{
|
|
int i, k, v, nLabels = 0;
|
|
if ( 0 && p->vSol ) {
|
|
tn_vi_for_each_entry( p->vSol, v, i )
|
|
{
|
|
if ( i % p->nNodes2 == 0 )
|
|
printf( "\n" );
|
|
if ( i == p->nIns * p->nNodes2 )
|
|
break;
|
|
if ( v == 1 )
|
|
printf( " %d", i );
|
|
}
|
|
printf( "\n");
|
|
}
|
|
|
|
printf( " " );
|
|
for ( i = p->nIns + 1; i < p->nNodes; i++ ) {
|
|
for ( v = 0; v <= p->nIns-2; v++ )
|
|
printf( " " );
|
|
printf( "%2d", i-p->nIns );
|
|
}
|
|
printf( "\n" );
|
|
for ( i = 0; i < p->nNodes-1; i++ ) {
|
|
if ( i >= 1 && i <= p->nIns )
|
|
continue;
|
|
printf( "%2d : ", i ? i - p->nIns : 0 );
|
|
for ( k = p->nIns + 1; k < p->nNodes; k++ ) {
|
|
if ( k <= i )
|
|
{
|
|
for ( v = 0; v <= p->nIns; v++ )
|
|
printf( " " );
|
|
continue;
|
|
}
|
|
for ( v = 0; v < p->nIns; v++ )
|
|
{
|
|
int ValP = p->vSol ? tn_vi_read(p->vSol, Tn_CtrlVar(p, i, k, v, 0)) : 0;
|
|
int ValN = p->vSol ? tn_vi_read(p->vSol, Tn_CtrlVar(p, i, k, v, 1)) : 0;
|
|
assert( ValP + ValN < 2 );
|
|
printf( "%c", ValP + ValN == 0 ? '-' : (ValP ? 'A' : 'a')+v );
|
|
nLabels += ValP + ValN;
|
|
}
|
|
printf(" ");
|
|
}
|
|
printf("\n");
|
|
}
|
|
//printf( "\nTotal labels = %d.\n\n", nLabels );
|
|
}
|
|
|
|
/*************************************************************
|
|
CNF writing
|
|
**************************************************************/
|
|
|
|
static inline void Tn_DumpFile( tn_gr * p, const char * pFileName )
|
|
{
|
|
FILE * pFile = fopen( pFileName, "wb" );
|
|
if ( pFile == NULL ) {
|
|
printf( "Cannot open file \"%s\" for writing CNF.\n", pFileName );
|
|
return;
|
|
}
|
|
fprintf( pFile, "p cnf %d %d\n", p->nCnfVars, p->nCnfClas );
|
|
int i, n, size, nClas = 0, * pArray = tn_vi_array(p->vCnf);
|
|
tn_vi_for_each_set( p->vCnf, size, i ) {
|
|
for ( n = 0; n < size; n++ )
|
|
fprintf( pFile, "%s%d ", tn_l2c(pArray[i+n]) ? "-" : "", tn_l2v(pArray[i+n]) );
|
|
fprintf( pFile, "0\n" );
|
|
nClas++;
|
|
}
|
|
assert( nClas == p->nCnfClas );
|
|
fclose( pFile );
|
|
//printf( "Finished dumping CNF with %d variables and %d clauses.\n", p->nCnfVars, p->nCnfClas );
|
|
}
|
|
|
|
static inline int Tn_GenClause( tn_gr * p, int * pLits, int nLits )
|
|
{
|
|
int i, k = 0;
|
|
for ( i = 0; i < nLits; i++ ) {
|
|
if ( pLits[i] == 1 )
|
|
return 0;
|
|
else if ( pLits[i] == 0 )
|
|
continue;
|
|
else if ( pLits[i] <= 2*p->nCnfVars )
|
|
pLits[k++] = pLits[i];
|
|
else assert( 0 );
|
|
}
|
|
nLits = k;
|
|
assert( nLits > 0 );
|
|
//if ( p->pFile ) {
|
|
if ( 1 ) {
|
|
p->nCnfClas++;
|
|
//for ( i = 0; i < nLits; i++ )
|
|
// fprintf( p->pFile, "%s%d ", tn_l2c(pLits[i]) ? "-" : "", tn_l2v(pLits[i]) );
|
|
//fprintf( p->pFile, "0\n" );
|
|
tn_vi_push( p->vCnf, nLits );
|
|
for ( i = 0; i < nLits; i++ )
|
|
tn_vi_push( p->vCnf, pLits[i] );
|
|
}
|
|
if ( 0 )
|
|
{
|
|
for ( i = 0; i < nLits; i++ )
|
|
fprintf( stdout, "%s%d ", tn_l2c(pLits[i]) ? "-" : " ", tn_l2v(pLits[i]) );
|
|
fprintf( stdout, "\n" );
|
|
}
|
|
return 1;
|
|
}
|
|
static inline int Tn_GenClauseVec( tn_gr * p, tn_vi * v )
|
|
{
|
|
return Tn_GenClause( p, tn_vi_array(v), tn_vi_size(v) );
|
|
}
|
|
static inline int Tn_GenClause4( tn_gr * p, int Lit0, int Lit1, int Lit2, int Lit3 )
|
|
{
|
|
int pLits[4] = { Lit0, Lit1, Lit2, Lit3 };
|
|
return Tn_GenClause( p, pLits, 4 );
|
|
}
|
|
// generate constraints for (Out = a0*b0 + a1*b1 + a2 + a3)
|
|
static inline void Tn_GenAndOrGate( tn_gr * pG, int iOutVar, tn_vi * vA, tn_vi * vB )
|
|
{
|
|
tn_vi * pArrays[2] = { vA, vB };
|
|
assert( tn_vi_size(vA) >= tn_vi_size(vB) );
|
|
int v, m, nmints = 1 << tn_vi_size(vB);
|
|
for ( m = 0; m < nmints; m++ ) {
|
|
int nvars = 0, pVars[MSIZE];
|
|
pVars[nvars++] = tn_v2l( iOutVar, 1 );
|
|
for ( v = 0; v < tn_vi_size(vB); v++ )
|
|
pVars[nvars++] = tn_v2l( tn_vi_read(pArrays[(m>>v)&1], v), 0 );
|
|
for ( ; v < tn_vi_size(vA); v++ )
|
|
pVars[nvars++] = tn_v2l( tn_vi_read(pArrays[0], v), 0 );
|
|
Tn_GenClause( pG, pVars, nvars );
|
|
}
|
|
for ( v = 0; v < tn_vi_size(vA); v++ ) {
|
|
int nvars = 0, pVars[MSIZE];
|
|
pVars[nvars++] = tn_v2l( iOutVar, 0 );
|
|
if ( v < tn_vi_size(vB) )
|
|
pVars[nvars++] = tn_v2l( tn_vi_read(vB, v), 1 );
|
|
pVars[nvars++] = tn_v2l( tn_vi_read(vA, v), 1 );
|
|
Tn_GenClause( pG, pVars, nvars );
|
|
}
|
|
}
|
|
/*************************************************************
|
|
candinality constraint
|
|
**************************************************************/
|
|
|
|
static inline int Tn_AddClause( tn_vi * p, int* begin, int* end )
|
|
{
|
|
tn_vi_push( p, (int)(end-begin) );
|
|
while ( begin < end )
|
|
tn_vi_push( p, (int)*begin++ );
|
|
return 1;
|
|
}
|
|
static inline int Tn_AddHalfSorter( tn_vi * p, int iVarA, int iVarB, int iVar0, int iVar1 )
|
|
{
|
|
int Lits[3];
|
|
int Cid;
|
|
|
|
Lits[0] = tn_v2l( iVarA, 0 );
|
|
Lits[1] = tn_v2l( iVar0, 1 );
|
|
Cid = Tn_AddClause( p, Lits, Lits + 2 );
|
|
assert( Cid );
|
|
|
|
Lits[0] = tn_v2l( iVarA, 0 );
|
|
Lits[1] = tn_v2l( iVar1, 1 );
|
|
Cid = Tn_AddClause( p, Lits, Lits + 2 );
|
|
assert( Cid );
|
|
|
|
Lits[0] = tn_v2l( iVarB, 0 );
|
|
Lits[1] = tn_v2l( iVar0, 1 );
|
|
Lits[2] = tn_v2l( iVar1, 1 );
|
|
Cid = Tn_AddClause( p, Lits, Lits + 3 );
|
|
assert( Cid );
|
|
return 3;
|
|
}
|
|
static inline void Tn_AddSorter( tn_vi * p, int * pVars, int i, int k, int * pnVars )
|
|
{
|
|
int iVar1 = (*pnVars)++;
|
|
int iVar2 = (*pnVars)++;
|
|
Tn_AddHalfSorter( p, iVar1, iVar2, pVars[i], pVars[k] );
|
|
pVars[i] = iVar1;
|
|
pVars[k] = iVar2;
|
|
}
|
|
static inline void Tn_AddCardinConstrMerge( tn_vi * p, int * pVars, int lo, int hi, int r, int * pnVars )
|
|
{
|
|
int i, step = r * 2;
|
|
if ( step < hi - lo )
|
|
{
|
|
Tn_AddCardinConstrMerge( p, pVars, lo, hi-r, step, pnVars );
|
|
Tn_AddCardinConstrMerge( p, pVars, lo+r, hi, step, pnVars );
|
|
for ( i = lo+r; i < hi-r; i += step )
|
|
Tn_AddSorter( p, pVars, i, i+r, pnVars );
|
|
for ( i = lo+r; i < hi-r-1; i += r )
|
|
{
|
|
int Lits[2] = { tn_v2l(pVars[i], 0), tn_v2l(pVars[i+r], 1) };
|
|
int Cid = Tn_AddClause( p, Lits, Lits + 2 );
|
|
assert( Cid );
|
|
}
|
|
}
|
|
}
|
|
static inline void Tn_AddCardinConstrRange( tn_vi * p, int * pVars, int lo, int hi, int * pnVars )
|
|
{
|
|
if ( hi - lo >= 1 )
|
|
{
|
|
int i, mid = lo + (hi - lo) / 2;
|
|
for ( i = lo; i <= mid; i++ )
|
|
Tn_AddSorter( p, pVars, i, i + (hi - lo + 1) / 2, pnVars );
|
|
Tn_AddCardinConstrRange( p, pVars, lo, mid, pnVars );
|
|
Tn_AddCardinConstrRange( p, pVars, mid+1, hi, pnVars );
|
|
Tn_AddCardinConstrMerge( p, pVars, lo, hi, 1, pnVars );
|
|
}
|
|
}
|
|
int Tn_AddCardinConstrPairWise( tn_vi * p, tn_vi * vVars )
|
|
{
|
|
int nVars = tn_vi_size(vVars);
|
|
Tn_AddCardinConstrRange( p, tn_vi_array(vVars), 0, nVars - 1, &nVars );
|
|
return nVars;
|
|
}
|
|
int Tn_AddCardinSolver( int LogN, tn_vi ** pvVars, tn_vi ** pvRes )
|
|
{
|
|
int i, nVars = 1 << LogN;
|
|
int nVarsAlloc = nVars + 2 * (nVars * LogN * (LogN-1) / 4 + nVars - 1);
|
|
tn_vi * vRes = tn_vi_alloc( 1000 );
|
|
tn_vi * vVars = tn_vi_alloc( nVars );
|
|
for ( i = 0; i < nVars; i++ )
|
|
tn_vi_push( vVars, i );
|
|
int nVarsReal = Tn_AddCardinConstrPairWise( vRes, vVars );
|
|
assert( nVarsReal == nVarsAlloc );
|
|
*pvVars = vVars;
|
|
*pvRes = vRes;
|
|
return nVarsReal;
|
|
}
|
|
void Tn_AddCardinality( tn_gr * p, tn_vi * vCard )
|
|
{
|
|
assert( p->nEdgeLimit );
|
|
tn_vi * vVars = NULL;
|
|
tn_vi * vRes = NULL;
|
|
int LogN = Tn_Base2Log( tn_vi_size(vCard) );
|
|
int nVarsReal = Tn_AddCardinSolver( LogN, &vVars, &vRes ), n, i, Var, size, pLits[2];
|
|
p->nCnfVars2 = p->nCnfVars;
|
|
p->nCnfClas2 = p->nCnfClas;
|
|
p->nCnfVars += nVarsReal;
|
|
tn_vi_for_each_entry( vCard, Var, i ) {
|
|
for ( n = 0; n < 2; n++ ) {
|
|
pLits[0] = tn_v2l( Var, n );
|
|
pLits[1] = tn_v2l( p->nCnfVars2+i, !n );
|
|
Tn_GenClause( p, pLits, 2 );
|
|
}
|
|
}
|
|
for ( ; i < (1<<LogN); i++ ) {
|
|
pLits[0] = tn_v2l( p->nCnfVars2+i, 1 );
|
|
Tn_GenClause( p, pLits, 1 );
|
|
}
|
|
int * pArray = tn_vi_array(vRes);
|
|
tn_vi_for_each_set( vRes, size, i ) {
|
|
for ( n = 0; n < size; n++ )
|
|
pArray[i+n] += 2*p->nCnfVars2;
|
|
Tn_GenClause( p, pArray+i, size );
|
|
}
|
|
pLits[0] = tn_v2l( p->nCnfVars2+tn_vi_read(vVars, p->nEdgeLimit), 1 );
|
|
Tn_GenClause( p, pLits, 1 );
|
|
tn_vi_free( vVars );
|
|
tn_vi_free( vRes );
|
|
}
|
|
|
|
/*************************************************************
|
|
CNF generation
|
|
**************************************************************/
|
|
|
|
static inline tn_vi * Tn_GenCnfStart( tn_gr * p )
|
|
{
|
|
int i, j, n;
|
|
//printf( "The first controls\n" );
|
|
for ( n = 0; n < p->nIns; n++ )
|
|
for ( i = 1; i <=p->nIns; i++ )
|
|
for ( j = 0; j < p->nNodes; j++ ) if ( i != j ) {
|
|
Tn_GenClause4( p, tn_v2l(Tn_CtrlVar(p, i, j, n, 0), 1), 0, 0, 0 );
|
|
Tn_GenClause4( p, tn_v2l(Tn_CtrlVar(p, i, j, n, 1), 1), 0, 0, 0 );
|
|
}
|
|
//printf( "Unused middle vars\n" );
|
|
for ( n = 0; n < p->nIns; n++ )
|
|
for ( i = 0; i < p->nNodes; i++ )
|
|
Tn_GenClause4( p, tn_v2l(Tn_MapVar(p, i, i, n), 1), 0, 0, 0 );
|
|
//printf( "The other controls\n" );
|
|
tn_vi * vCard = tn_vi_alloc( 100 );
|
|
for ( n = 0; n < p->nIns; n++ )
|
|
for ( i = 0; i < p->nNodes; i++ ) {
|
|
if ( i >= 1 && i <= p->nIns )
|
|
continue;
|
|
for ( j = i+1; j < p->nNodes; j++ ) {
|
|
if ( j >= 1 && j <= p->nIns )
|
|
continue;
|
|
if ( p->pTypes[1+n] == '0' ) { // negative - remove positive (i < j)
|
|
Tn_GenClause4( p, tn_v2l(Tn_CtrlVar(p, i, j, n, 0), 1), 0, 0, 0 );
|
|
tn_vi_push( vCard, Tn_CtrlVar(p, i, j, n, 1) );
|
|
}
|
|
else if ( p->pTypes[1+n] == '1' ) { // positive - remove negative (i > j)
|
|
Tn_GenClause4( p, tn_v2l(Tn_CtrlVar(p, i, j, n, 1), 1), 0, 0, 0 );
|
|
tn_vi_push( vCard, Tn_CtrlVar(p, i, j, n, 0) );
|
|
}
|
|
else if ( p->pTypes[1+n] == '-' || p->pTypes[1+n] == '*' ) {
|
|
Tn_GenClause4( p, tn_v2l(Tn_CtrlVar(p, i, j, n, 0), 1), 0, 0, 0 );
|
|
Tn_GenClause4( p, tn_v2l(Tn_CtrlVar(p, i, j, n, 1), 1), 0, 0, 0 );
|
|
}
|
|
else if ( p->pTypes[1+n] == '2' ) {
|
|
tn_vi_push( vCard, Tn_CtrlVar(p, i, j, n, 0) );
|
|
tn_vi_push( vCard, Tn_CtrlVar(p, i, j, n, 1) );
|
|
}
|
|
else assert( 0 );
|
|
}
|
|
}
|
|
//printf( "Pair-wise one-hot\n" );
|
|
for ( n = 0; n < p->nIns; n++ )
|
|
for ( i = 0; i < p->nNodes; i++ )
|
|
for ( j = i+1; j < p->nNodes; j++ )
|
|
Tn_GenClause4( p, tn_v2l(Tn_CtrlVar(p, i, j, n, 0), 1), tn_v2l(Tn_CtrlVar(p, i, j, n, 1), 1), 0, 0 );
|
|
return vCard;
|
|
}
|
|
static inline void Tn_GenCnfMint( tn_gr * p, int m, int mout )
|
|
{
|
|
int i, j, v, size;
|
|
/*
|
|
//printf( "Generating minterm %d / %d:\n", m, mout );
|
|
Tn_GenClause4( p, tn_v2l(Tn_NodeVar(p, 0, m), 0), 0, 0, 0 );
|
|
for ( i = 0; i < p->nIns; i++ )
|
|
Tn_GenClause4( p, tn_v2l(Tn_NodeVar(p, 1+i, m), ((m>>i)&1)==0), 0, 0, 0 );
|
|
for ( i = 0; i < p->nOuts; i++ )
|
|
Tn_GenClause4( p, tn_v2l(Tn_NodeVar(p, p->nNodes-p->nOuts+p->nOuts-1-i, m), ((mout>>i)&1)==0), 0, 0, 0 );
|
|
//printf( "Functionality:\n" );
|
|
for ( i = 0; i < p->nNodes; i++ )
|
|
for ( j = i+1; j < p->nNodes; j++ )
|
|
{
|
|
int iEdge = Tn_EdgeVar(p, i, j, m);
|
|
int iNodeI = Tn_NodeVar(p, i, m);
|
|
int iNodeJ = Tn_NodeVar(p, j, m);
|
|
Tn_GenClause4( p, tn_v2l(iEdge, 1), tn_v2l(iNodeI, 0), tn_v2l(iNodeJ, 1), 0 );
|
|
Tn_GenClause4( p, tn_v2l(iEdge, 1), tn_v2l(iNodeI, 1), tn_v2l(iNodeJ, 0), 0 );
|
|
}
|
|
*/
|
|
//printf( "Edge variables:\n" );
|
|
for ( i = 0; i < p->nNodes; i++ )
|
|
for ( j = i+1; j < p->nNodes; j++ )
|
|
{
|
|
tn_vi_resize( p->vTemp[0], 0 );
|
|
tn_vi_resize( p->vTemp[1], 0 );
|
|
for ( v = 0; v < p->nIns; v++ )
|
|
tn_vi_push( p->vTemp[0], Tn_CtrlVar(p, i, j, v, ((m>>v)&1)==0) );
|
|
Tn_GenAndOrGate( p, Tn_EdgeVar(p, i, j, m), p->vTemp[0], p->vTemp[1] );
|
|
}
|
|
//printf( "Connectivity:\n" );
|
|
for ( i = 0; i < p->nOuts; i++ )
|
|
{
|
|
if ( (mout>>i)&1 ) { // p->pVecs[0] pos cut vars -> connected
|
|
tn_vi_for_each_set( p->pVecs[2*i+0], size, j ) {
|
|
assert( (size & 1) == 0 );
|
|
tn_vi_resize( p->vTemp[0], 0 );
|
|
for ( v = 0; v < size/2; v++ ) {
|
|
int start = tn_vi_read(p->pVecs[2*i+0], j+2*v+0);
|
|
int next = tn_vi_read(p->pVecs[2*i+0], j+2*v+1);
|
|
tn_vi_push( p->vTemp[0], tn_v2l(Tn_EdgeVar(p, start, next, m), 0) );
|
|
}
|
|
Tn_GenClauseVec( p, p->vTemp[0] );
|
|
}
|
|
if ( p->nLevelLimit == 0 )
|
|
continue;
|
|
tn_vi_for_each_set( p->pVecs[2*i+1], size, j ) { // p->pVecs[1] neg path vars -> disconnected
|
|
if ( size <= p->nLevelLimit+1 )
|
|
continue;
|
|
int next, start = tn_vi_read(p->pVecs[2*i+1], j);
|
|
tn_vi_resize( p->vTemp[0], 0 );
|
|
for ( v = 1; v < size && (next = tn_vi_read(p->pVecs[2*i+1], j+v)); v++, start = next )
|
|
tn_vi_push( p->vTemp[0], tn_v2l(Tn_EdgeVar(p, start, next, m), 1) );
|
|
Tn_GenClauseVec( p, p->vTemp[0] );
|
|
}
|
|
}
|
|
else { // p->pVecs[1] neg path vars -> disconnected
|
|
tn_vi_for_each_set( p->pVecs[2*i+1], size, j ) {
|
|
int next, start = tn_vi_read(p->pVecs[2*i+1], j);
|
|
tn_vi_resize( p->vTemp[0], 0 );
|
|
for ( v = 1; v < size && (next = tn_vi_read(p->pVecs[2*i+1], j+v)); v++, start = next )
|
|
tn_vi_push( p->vTemp[0], tn_v2l(Tn_EdgeVar(p, start, next, m), 1) );
|
|
Tn_GenClauseVec( p, p->vTemp[0] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static inline void Tn_GenCnf( tn_gr * p, const char * pFileName )
|
|
{
|
|
int o, m, mout;
|
|
assert( p->pFile == NULL );
|
|
p->pFile = fopen( pFileName, "wb" );
|
|
if ( p->pFile == NULL ) {
|
|
printf( "Cannot open file \"%s\" for writing CNF.\n", pFileName );
|
|
return;
|
|
}
|
|
fputs( "p cnf \n", p->pFile );
|
|
tn_vi * vCard = Tn_GenCnfStart( p );
|
|
for ( m = 0; m < (1<<p->nIns); m++ ) {
|
|
for ( mout = o = 0; o < p->nOuts; o++ )
|
|
if ( (p->pOuts[o] >> m) & 1 )
|
|
mout |= 1 << o;
|
|
Tn_GenCnfMint( p, m, mout );
|
|
}
|
|
if ( p->nEdgeLimit > 0 )
|
|
Tn_AddCardinality( p, vCard );
|
|
rewind( p->pFile );
|
|
fprintf( p->pFile, "p cnf %d %d", p->nCnfVars, p->nCnfClas );
|
|
fclose( p->pFile );
|
|
p->pFile = NULL;
|
|
printf( "Dumped file \"%s\" with %d vars and %d clauses (%d out of %d: %d vars and %d clauses).\n",
|
|
pFileName, p->nCnfVars, p->nCnfClas, p->nEdgeLimit, tn_vi_size(vCard),
|
|
p->nCnfVars2 ? p->nCnfVars-p->nCnfVars2 : 0,
|
|
p->nCnfClas2 ? p->nCnfClas-p->nCnfClas2 : 0 );
|
|
tn_vi_free( vCard );
|
|
}
|
|
static inline void Tn_GenCnf2( tn_gr * p )
|
|
{
|
|
int o, m, mout;
|
|
assert( tn_vi_size(p->vCnf) == 0 );
|
|
tn_vi * vCard = Tn_GenCnfStart( p );
|
|
for ( m = 0; m < (1<<p->nIns); m++ ) {
|
|
for ( mout = o = 0; o < p->nOuts; o++ )
|
|
if ( (p->pOuts[o] >> m) & 1 )
|
|
mout |= 1 << o;
|
|
Tn_GenCnfMint( p, m, mout );
|
|
}
|
|
if ( p->nEdgeLimit > 0 )
|
|
Tn_AddCardinality( p, vCard );
|
|
printf( "Created CNF with %d vars and %d clauses (%d out of %d: %d vars and %d clauses).\n",
|
|
p->nCnfVars, p->nCnfClas, p->nEdgeLimit, tn_vi_size(vCard),
|
|
p->nCnfVars2 ? p->nCnfVars-p->nCnfVars2 : 0,
|
|
p->nCnfClas2 ? p->nCnfClas-p->nCnfClas2 : 0 );
|
|
tn_vi_free( vCard );
|
|
}
|
|
|
|
/*************************************************************
|
|
Reading input data
|
|
**************************************************************/
|
|
|
|
// truth table size in 64-bit words
|
|
static inline int Tn_TruthWordNum( int n ) { return n <= 6 ? 1 : 1 << (n-6); }
|
|
static inline int Tn_HexDigitNum( int n ) { return n <= 2 ? 1 : 1 << (n-2); }
|
|
|
|
static inline int Tn_Hex2Int( char c ) {
|
|
int Digit = 0;
|
|
if ( c >= '0' && c <= '9' )
|
|
Digit = c - '0';
|
|
else if ( c >= 'A' && c <= 'F' )
|
|
Digit = c - 'A' + 10;
|
|
else if ( c >= 'a' && c <= 'f' )
|
|
Digit = c - 'a' + 10;
|
|
else return -1;
|
|
assert( Digit >= 0 && Digit < 16 );
|
|
return Digit;
|
|
}
|
|
static inline void Tn_PrintHexTruth( FILE * pFile, word * pTruth, int nVars ) {
|
|
int k, Digit, nDigits = Tn_HexDigitNum(nVars);
|
|
for ( k = nDigits-1; k >= 0; k-- ) {
|
|
Digit = (int)((pTruth[k/16] >> ((k%16) * 4)) & 15);
|
|
if ( Digit < 10 )
|
|
fprintf( pFile, "%d", Digit );
|
|
else
|
|
fprintf( pFile, "%c", 'A' + Digit-10 );
|
|
}
|
|
}
|
|
int Tn_ReadHexTruth( char * pInput, word * pTruth )
|
|
{
|
|
int nChars = strlen(pInput), i;
|
|
int nVars = Tn_Base2Log(4*nChars);
|
|
if ( (1 << nVars) != 4*nChars ) {
|
|
printf( "The input string length (%d chars) does not match the size (%d bits) of the truth table of %d-var function.\n",
|
|
nChars, 1<<nVars, nVars );
|
|
return 0;
|
|
}
|
|
word Num = 0;
|
|
for ( i = nChars-1; i >= 0; i-- ) {
|
|
Num |= (word)Tn_Hex2Int(pInput[nChars-1-i]) << ((i & 0xF) * 4);
|
|
if ( (i & 0xF) == 0 )
|
|
pTruth[i>>4] = Num, Num = 0;
|
|
}
|
|
assert( Num == 0 );
|
|
printf( "Finished entring %d-input function: ", nVars );
|
|
Tn_PrintHexTruth( stdout, pTruth, nVars );
|
|
printf( "\n" );
|
|
return nVars;
|
|
}
|
|
|
|
/*************************************************************
|
|
dumping spice format
|
|
**************************************************************/
|
|
|
|
static inline void Tn_DumpNode( tn_gr * p, FILE * pFile, int i )
|
|
{
|
|
if ( i == 0 )
|
|
fprintf( pFile, " VDD" );
|
|
else if ( i >= p->nNodes - p->nOuts ) {
|
|
fprintf( pFile, " Y" );
|
|
Tn_PrintHexTruth( pFile, p->pOuts+(i-(p->nNodes - p->nOuts)), p->nIns );
|
|
}
|
|
else
|
|
fprintf( pFile, " net%d", i-p->nIns );
|
|
}
|
|
static inline int Tn_DumpLabels( tn_gr * p, FILE * pFile )
|
|
{
|
|
int i, k, v, nLabels = 0;
|
|
if ( p->vSol == NULL )
|
|
return 0;
|
|
for ( i = 0; i < p->nNodes-1; i++ )
|
|
for ( k = i+1; k < p->nNodes; k++ )
|
|
for ( v = 0; v < p->nIns; v++ )
|
|
{
|
|
int ValP = p->vSol ? tn_vi_read(p->vSol, Tn_CtrlVar(p, i, k, v, 0)) : 0;
|
|
int ValN = p->vSol ? tn_vi_read(p->vSol, Tn_CtrlVar(p, i, k, v, 1)) : 0;
|
|
assert( ValP + ValN < 2 );
|
|
if ( ValP + ValN == 0 )
|
|
continue;
|
|
// MM1 net10 B VDD VDD pmos_rvt w=xxxn l=yyyn nfin=2
|
|
fprintf( pFile, "mm%d", nLabels );
|
|
Tn_DumpNode( p, pFile, tn_max(i, k) );
|
|
fprintf( pFile, " %c", 'A'+v );
|
|
Tn_DumpNode( p, pFile, tn_min(i, k));
|
|
fprintf( pFile, " VDD" );
|
|
fprintf( pFile, " %cmos_rvt\n", ValP ? 'p' : 'n' );
|
|
nLabels += ValP + ValN;
|
|
}
|
|
return nLabels;
|
|
}
|
|
static inline void Tn_DumpSpice( tn_gr * p )
|
|
{
|
|
const char * pFileName = "temp.sp"; int i;
|
|
FILE * pFile = fopen( pFileName, "wb" );
|
|
if ( pFile == NULL ) {
|
|
printf( "Cannot open file \"%s\" for writing SPICE format.\n", pFileName );
|
|
return;
|
|
}
|
|
//.SUBCKT <name> A VDD VSS Y
|
|
fprintf( pFile, ".SUBCKT tn" );
|
|
for ( i = 0; i < p->nOuts; i++ ) {
|
|
fprintf( pFile, "_" );
|
|
Tn_PrintHexTruth( pFile, p->pOuts+i, p->nIns );
|
|
}
|
|
for ( i = 0; i < p->nIns; i++ )
|
|
fprintf( pFile, " %c", 'A' + i );
|
|
fprintf( pFile, " VDD VSS");
|
|
for ( i = 0; i < p->nOuts; i++ ) {
|
|
fprintf( pFile, " Y" );
|
|
Tn_PrintHexTruth( pFile, p->pOuts+i, p->nIns );
|
|
}
|
|
fprintf( pFile, "\n");
|
|
Tn_DumpLabels( p, pFile );
|
|
fprintf( pFile, ".ENDS\n\n" );
|
|
fclose( pFile );
|
|
printf( "Finished dumping SPICE description into file \"%s\".\n", pFileName );
|
|
}
|
|
|
|
/*************************************************************
|
|
Solving the problem
|
|
**************************************************************/
|
|
|
|
tn_vi * Tn_ParseSolution( const char * pFileName )
|
|
{
|
|
tn_vi * vRes = NULL;
|
|
char * pToken, pBuffer[1000];
|
|
FILE * pFile = fopen( pFileName, "rb" );
|
|
if ( pFile == NULL )
|
|
{
|
|
printf( "Cannot open file \"%s\".\n", pFileName );
|
|
return NULL;
|
|
}
|
|
while ( fgets( pBuffer, 1000, pFile ) != NULL )
|
|
{
|
|
if ( pBuffer[0] == 's' )
|
|
{
|
|
if ( strncmp(pBuffer+2, "SAT", 3) )
|
|
break;
|
|
assert( vRes == NULL );
|
|
vRes = tn_vi_alloc( 100 );
|
|
}
|
|
else if ( pBuffer[0] == 'v' )
|
|
{
|
|
pToken = strtok( pBuffer+1, " \n\r\t" );
|
|
while ( pToken )
|
|
{
|
|
int Token = atoi(pToken);
|
|
if ( Token == 0 )
|
|
break;
|
|
int nSizeMax = tn_abs(Token) + 1;
|
|
while ( tn_vi_size(vRes) < nSizeMax )
|
|
tn_vi_push( vRes, -1 );
|
|
tn_vi_write( vRes, tn_abs(Token), Token > 0 );
|
|
//Vec_IntSetEntryFull( vRes, Tn_AbsInt(Token), Token > 0 );
|
|
pToken = strtok( NULL, " \n\r\t" );
|
|
}
|
|
}
|
|
else if ( pBuffer[0] != 'c' )
|
|
assert( 0 );
|
|
}
|
|
fclose( pFile );
|
|
unlink( pFileName );
|
|
return vRes;
|
|
}
|
|
tn_vi * Tn_SolveSat( const char * pFileNameIn, const char * pFileNameOut, int Seed, int TimeOut, int fVerbose )
|
|
{
|
|
int fVerboseSolver = 0;
|
|
iword clkTotal = Tn_Clock();
|
|
tn_vi * vRes = NULL;
|
|
#ifdef _WIN32
|
|
const char * pKissat = "kissat.exe";
|
|
#else
|
|
const char * pKissat = "kissat";
|
|
#endif
|
|
char Command[1000], * pCommand = (char *)&Command;
|
|
if ( TimeOut )
|
|
sprintf( pCommand, "%s --seed=%d --time=%d %s %s > %s", pKissat, Seed, TimeOut, fVerboseSolver ? "": "-q", pFileNameIn, pFileNameOut );
|
|
else
|
|
sprintf( pCommand, "%s --seed=%d %s %s > %s", pKissat, Seed, fVerboseSolver ? "": "-q", pFileNameIn, pFileNameOut );
|
|
//if ( fVerbose )
|
|
// printf( "Running command line: %s\n", pCommand );
|
|
#if defined(__wasm)
|
|
if ( 1 )
|
|
#else
|
|
if ( system( pCommand ) == -1 )
|
|
#endif
|
|
{
|
|
printf( "Command \"%s\" did not succeed.\n", pCommand );
|
|
return 0;
|
|
}
|
|
vRes = Tn_ParseSolution( pFileNameOut );
|
|
if ( fVerbose )
|
|
{
|
|
if ( vRes )
|
|
printf( "The problem has a solution. " );
|
|
else if ( vRes == NULL && TimeOut == 0 )
|
|
printf( "The problem has no solution. " );
|
|
else if ( vRes == NULL )
|
|
printf( "The problem has no solution or timed out after %d sec. ", TimeOut );
|
|
Tn_PrintTime( "SAT solver time", Tn_Clock() - clkTotal );
|
|
}
|
|
return vRes;
|
|
}
|
|
static inline void Tn_AppendClause( tn_gr * p, tn_vi * vSol )
|
|
{
|
|
int v, k = 0, Limit = p->nIns * p->nNodes2;
|
|
for ( v = 1; v < Limit; v++ )
|
|
if ( tn_vi_read(p->vSol, v) )
|
|
tn_vi_write( p->vSol, k++, tn_v2l(v, 1) );
|
|
tn_vi_resize( p->vSol, k );
|
|
Tn_GenClauseVec( p, p->vSol );
|
|
//printf("Finished adding clause: ");
|
|
//tn_vi_print( p->vSol );
|
|
}
|
|
void Tn_SolveProblem( int nIns, int nOuts, word * pOuts, char * pTypes, int nEdgeLimit, int nLevelLimit, int nSolsMax, int Seed, int TimeOut, int fVerbose )
|
|
{
|
|
const char * pFileNameIn = "_temp_.cnf";
|
|
const char * pFileNameOut = "_temp_.txt";
|
|
tn_gr * p = Tn_Init( nIns, nOuts, pOuts, pTypes, nEdgeLimit, nLevelLimit, fVerbose );
|
|
//Tn_PrintMapVar( p );
|
|
Tn_GenCnf2( p );
|
|
for ( int n = 0; n < nSolsMax; n++ ) {
|
|
printf( "\nIteration %d:\n", n );
|
|
Tn_DumpFile( p, pFileNameIn );
|
|
p->vSol = Tn_SolveSat( pFileNameIn, pFileNameOut, Seed, TimeOut, fVerbose );
|
|
Tn_PrintStats( p );
|
|
if ( p->vSol ) {
|
|
//Tn_PrintGraph( p );
|
|
Tn_PrintGraph2( p );
|
|
Tn_DumpSpice( p );
|
|
Tn_AppendClause( p, p->vSol );
|
|
tn_vi_free( p->vSol );
|
|
p->vSol = NULL;
|
|
}
|
|
else {
|
|
printf( "Problem has no solution.\n" );
|
|
break;
|
|
}
|
|
}
|
|
Tn_Free( p );
|
|
}
|
|
|
|
/*************************************************************
|
|
main() procedure
|
|
**************************************************************/
|
|
|
|
#if 0
|
|
|
|
int main(int argc, char ** argv)
|
|
{
|
|
if ( argc == 1 )
|
|
{
|
|
printf( "usage: %s -C <str> [-ELNSTV <num>] <truth[0]> ... <truth[m-1]>\n", argv[0] );
|
|
printf( " this program synthesizes networks for multi-output functions\n" );
|
|
printf( "\n" );
|
|
printf( " -C <str> : the configuration string (no default)\n" );
|
|
printf( " -E <num> : the max number of edges (default = no limit)\n" );
|
|
printf( " -L <num> : the max number of levels (default = no limit)\n" );
|
|
printf( " -N <num> : the max number of solutions (default = 1)\n" );
|
|
printf( " -S <num> : the random seed (default = 0)\n" );
|
|
printf( " -T <num> : the timeout in seconds (default = no timeout)\n" );
|
|
printf( " -V <num> : the verbosiness levels (default = 1)\n" );
|
|
printf( " <truth[0]> : the truth table of the first output in the hexadecimal notation\n" );
|
|
printf( " <truth[m-1]> : the truth table of the last output in the hexadecimal notation\n" );
|
|
printf( " the truth tables are assumed to depend on the same variables\n" );
|
|
printf( " the strings should contain 2^(<num_inputs>-2) hexadecimal digits\n" );
|
|
printf( "\n" );
|
|
printf( " Example 1: Synthesizing 3-node 2-edge 2-input and-gate:\n" );
|
|
printf( " %s -C *11** -E 2 8\n", argv[0] );
|
|
printf( " Example 2: Synthesizing 4-node 5-edge 3-input majority gate:\n" );
|
|
printf( " %s -C *111*** -E 5 E8\n", argv[0] );
|
|
// printf( " Example 3: Synthesizing 9-node 10-edge 3-input 2-output full-adder:\n" );
|
|
// printf( " %s -C *111****1 -E 10 96 E8\n", argv[0] );
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
int nIns = 0, nOuts = 0, nEdgeLimit = 0, nLevelLimit = 0, nSolsMax = 1, Seed = 0, TimeOut = 0, fVerbose = 1;
|
|
char * pTypes = NULL;
|
|
word Truths[MSIZE] = {0};
|
|
for ( int c = 1; c < argc; c++ ) {
|
|
if ( argv[c][0] == '-' && argv[c][1] == 'C' )
|
|
pTypes = argv[++c];
|
|
else if ( argv[c][0] == '-' && argv[c][1] == 'E' )
|
|
nEdgeLimit = atoi(argv[++c]);
|
|
else if ( argv[c][0] == '-' && argv[c][1] == 'L' )
|
|
nLevelLimit = atoi(argv[++c]);
|
|
else if ( argv[c][0] == '-' && argv[c][1] == 'N' )
|
|
nSolsMax = atoi(argv[++c]);
|
|
else if ( argv[c][0] == '-' && argv[c][1] == 'S' )
|
|
Seed = atoi(argv[++c]);
|
|
else if ( argv[c][0] == '-' && argv[c][1] == 'T' )
|
|
TimeOut = atoi(argv[++c]);
|
|
else if ( argv[c][0] == '-' && argv[c][1] == 'V' )
|
|
fVerbose = atoi(argv[++c]);
|
|
else if ( Tn_Hex2Int(argv[c][0]) != -1 ) {
|
|
int nVarsOut = Tn_ReadHexTruth( argv[c], Truths + nOuts++ );
|
|
if ( nIns == 0 )
|
|
nIns = nVarsOut;
|
|
else if ( nIns != nVarsOut ) {
|
|
printf( "The support size of output functions is not the same.\n" );
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
printf( "String \"%s\" does not look like a truth table in the hexadecimal notation.\n", argv[c] );
|
|
break;
|
|
}
|
|
}
|
|
printf( "Finished reading %d output%s\n\n", nOuts, nOuts == 1 ? "" : "s" );
|
|
Tn_SolveProblem( nIns, nOuts, Truths, pTypes, nEdgeLimit, nLevelLimit, nSolsMax, Seed, TimeOut, fVerbose );
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*************************************************************
|
|
end of file
|
|
**************************************************************/
|
|
|
|
ABC_NAMESPACE_IMPL_END
|
|
|