/**CFile*********************************************************************** FileName [ tblSweep.c ] PackageName [ tbl ] Synopsis [Functions to support network sweeping.] SeeAlso [ tbl.h, tblEntryUtil.c ] Author [ Gitanjali M. Swamy ] Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.] ******************************************************************************/ #include "tblInt.h" static char rcsid[] UNUSED = "$Id: tblSweep.c,v 1.12 2009/04/11 18:26:45 fabio Exp $"; /**AutomaticStart*************************************************************/ /*---------------------------------------------------------------------------*/ /* Static function prototypes */ /*---------------------------------------------------------------------------*/ static void SetAdjustedEntry(Tbl_Table_t *table, Tbl_Entry_t *entry, int index, int rownum, int colnum, boolean flag); static void SetEntry(Tbl_Table_t *newTable, Tbl_Entry_t *entry1, Tbl_Entry_t *entry2, int rownum, int colnum, int index, boolean flag); /**AutomaticEnd***************************************************************/ /*---------------------------------------------------------------------------*/ /* Definition of exported functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [return the result of collapsing table2 into table1] Description [Given two Tbl_Table_t table1 and table2, this function will collapse table2 into the table1. It will remove the column corresponding to the var associated with the first table. Currently, the second table must a constant table. This function checks every row to confirm that the entry corresponding to the variable of table2 does indeed take the constant value. If this condition is satisfied it copies the entire row (minus the column corresponding to the constant variable) into a new resultant table. This condition can be easily checked if the corresponding entry is of type Tbl_EntryNormal_c, using Tbl_EntryTestIntersectEntry. Otherwise its an involved process that entails tracing the entire sequence of equal entries until we encounter a Tbl_EntryNormal_c entry.] SideEffects [required] SeeAlso [optional] ******************************************************************************/ Tbl_Table_t* Tbl_TableCollapse(Tbl_Table_t* table1, Tbl_Table_t* table2,int index) { int rownum, realRowNum, colnum,eqcolnum,count,check; Var_Variable_t *var; Tbl_Table_t *newTable; Tbl_Entry_t *entry1, *entry2; Tbl_Entry_t *testEntry; if (Tbl_TableReadNumOutputs(table2)==1){ newTable = Tbl_TableAlloc(); if (Tbl_TableReadNumRows(table2) !=0) { entry2 = Tbl_TableReadEntry(table2,0,0,1); } else { entry2 = Tbl_TableDefaultReadEntry(table2,0); } /* add every input column except collapsing input */ for(colnum=0;colnum < Tbl_TableReadNumInputs(table1); colnum++) { if (colnum != index) { var = Tbl_TableReadIndexVar(table1,colnum,0); Tbl_TableAddColumn(newTable,var,0); } } for(colnum=0;colnum < Tbl_TableReadNumOutputs(table1); colnum++) { var = Tbl_TableReadIndexVar(table1,colnum,1); Tbl_TableAddColumn(newTable,var,1); } /* (void) Tbl_TableAddRow(newTable); */ realRowNum =0; eqcolnum = index; /* row by row, check if var has given constant value */ for(rownum=0; rownum< Tbl_TableReadNumRows(table1); rownum++) { testEntry = Tbl_TableReadEntry(table1,rownum,index,0); assert(entry2->type == Tbl_EntryNormal_c); /* input column by column */ if (testEntry->type == Tbl_EntryNormal_c){ if (Tbl_EntryTestIntersectEntry(testEntry,entry2)){ (void) Tbl_TableAddRow(newTable); for(colnum=0;colnum < Tbl_TableReadNumInputs(table1); colnum++) { entry1= Tbl_TableReadEntry(table1,rownum,colnum,0); SetEntry(newTable,entry1,entry2,realRowNum,colnum,index,0); } /* do outputs */ for(colnum=0;colnum < Tbl_TableReadNumOutputs(table1); colnum++) { entry1= Tbl_TableReadEntry(table1,rownum,colnum,1); SetEntry(newTable,entry1,entry2,realRowNum,colnum,index,1); } realRowNum++; } } else if (testEntry->type == Tbl_EntryEqual_c){ count = 0; check = 0; while(count<= Tbl_TableReadNumInputs(table1)){ /* Find out the column the entry equal to * and set that column entry to constant value if * its is of type Equal. This gets propagated by the while count * loop until you find a non-equal entry, and then it checks * for an intersection. If no intersection, then it * nullifies the row. Alas, there was no easier way */ if (testEntry->type == Tbl_EntryNormal_c){ if (Tbl_EntryTestIntersectEntry(testEntry,entry2)){ check = 1; } count = Tbl_TableReadNumInputs(table1)+1; } else { eqcolnum = Tbl_EntryReadVarIndex(testEntry); testEntry = Tbl_TableReadEntry(table1,rownum,eqcolnum,0); } if (count == Tbl_TableReadNumInputs(table1)){ check = 1; } count ++; } if (check == 1) { (void) Tbl_TableAddRow(newTable); count = 0; eqcolnum = index; testEntry = Tbl_TableReadEntry(table1,rownum,index,0); while(count<= Tbl_TableReadNumInputs(table1)){ if (testEntry->type == Tbl_EntryNormal_c){ SetEntry(newTable,entry2,entry2,realRowNum,eqcolnum,index,0); count = Tbl_TableReadNumInputs(table1)+1 ; } else { eqcolnum = Tbl_EntryReadVarIndex(testEntry); testEntry = Tbl_TableReadEntry(table1,rownum,eqcolnum,0); count ++; } } /* end of while */ /* fill in zero entries */ for(colnum=0;colnum < Tbl_TableReadNumInputs(table1); colnum++) { entry1= Tbl_TableReadEntry(table1,rownum,colnum,0); SetAdjustedEntry(newTable,Tbl_EntryDup(entry1),index,rownum,colnum,0); } /* do outputs */ for(colnum=0;colnum < Tbl_TableReadNumOutputs(table1); colnum++) { entry1= Tbl_TableReadEntry(table1,rownum,colnum,1); SetEntry(newTable,entry1,entry2,realRowNum,colnum,index,1); } } realRowNum++; } } Tbl_TableForEachDefaultEntry(table1,entry1,colnum) { entry2 = NIL(Tbl_Entry_t); if (entry1 != NIL(Tbl_Entry_t)) { if (entry1->type != Tbl_EntryEqual_c) { entry2 = Tbl_EntryDup(entry1); } else{ eqcolnum = Tbl_EntryReadVarIndex(entry1); if ( eqcolnum < index) { entry2 = Tbl_EntryDup(entry1); } else { if ( eqcolnum > index) { entry2 = Tbl_EntryDup(entry1); Tbl_EntrySetEqual(entry2, eqcolnum -1); } else { entry2 = Tbl_EntryDup(Tbl_TableReadEntry(table2,0,0,1)); } } } } (void) Tbl_TableDefaultSetEntry(newTable,entry2,colnum); } return newTable; } else { fail("The table is not constant\n"); return NIL(Tbl_Table_t); /* not reached */ } } /**Function******************************************************************** Synopsis [Inverts a binary input column in a table.] Description [Inverts a binary input column in a table. It has no effect if the variable associated to the given index is not binary or is symbolic. In some uncommon cases that are tricky to handle, it goves up ad returns a NULL pointer. Otherwise it returns a modified table.] SideEffects [none] SeeAlso [Tbl_TableIsInverter] ******************************************************************************/ Tbl_Table_t * Tbl_TableInvertBinaryInputColumn( Tbl_Table_t *table, int index ) { int rowNum, colNum; Tbl_Entry_t *entry; Tbl_Table_t *newTable; Var_Variable_t *var; var = Tbl_TableReadIndexVar(table, index, 0); if (Var_VariableReadNumValues(var) != 2 || Var_VariableTestIsSymbolic(var)) return NIL(Tbl_Table_t); /* Check default entries. We give up if any variable points to the column * to be complemented, because it's a rare case and it does not seem worth * the effort. */ Tbl_TableForEachDefaultEntry(table, entry, colNum) { if (entry != NIL(Tbl_Entry_t) && Tbl_EntryIsEqual(entry)) { int eqColNum = Tbl_EntryReadVarIndex(entry); if (eqColNum == index) { return NIL(Tbl_Table_t); } } } newTable = Tbl_TableHardDup(table); Tbl_TableForEachInputVar(table, colNum, var) { Tbl_TableSetVar(newTable, colNum, var, 0); } Tbl_TableForEachOutputVar(table, colNum, var) { Tbl_TableSetVar(newTable, colNum, var, 1); } /* Get rid of equal entries in the output part that point to the * column to be negated. We do not currently deal with equal * entries in the input part. If we find one, we give up. */ Tbl_TableForEachOutputEntry(newTable, rowNum, colNum, entry) { if (Tbl_EntryIsEqual(entry)) { int eqColNum = Tbl_EntryReadVarIndex(entry); if (eqColNum == index) { Tbl_Entry_t *eqEntry = Tbl_TableReadEntry(newTable, rowNum, index, 0); if (Tbl_EntryIsEqual(eqEntry) || Tbl_EntryReadNumValues(eqEntry) == 0) { /* Tricky case: we give up. */ Tbl_TableFree(newTable); return NIL(Tbl_Table_t); } else if (Tbl_EntryReadNumValues(eqEntry) == 1) { /* Downgrade the equality to a constant value. */ Tbl_Entry_t *entry2 = Tbl_EntryDup(eqEntry); Tbl_TableSetEntry(newTable, entry2, rowNum, colNum, 1); } else { int i, j; Tbl_Entry_t *entry2; i = Tbl_TableAddRow(newTable); Tbl_RowForEachInputEntry(newTable, rowNum, entry2, j) { if (j == index) { Tbl_Entry_t *entry3 = Tbl_EntryAlloc(Tbl_EntryNormal_c); Tbl_Entry_t *entry4 = Tbl_EntryAlloc(Tbl_EntryNormal_c); Tbl_EntrySetValue(entry3, 0, 0); Tbl_EntrySetValue(entry4, 1, 1); Tbl_TableSetEntry(newTable, entry3, rowNum, j, 0); Tbl_TableSetEntry(newTable, entry4, i, j, 0); } else { Tbl_TableSetEntry(newTable, Tbl_EntryDup(entry2), i, j, 0); } } Tbl_RowForEachOutputEntry(newTable, rowNum, entry2, j) { if (Tbl_EntryIsEqual(entry2) && Tbl_EntryReadVarIndex(entry) == index) { Tbl_Entry_t *entry3 = Tbl_EntryAlloc(Tbl_EntryNormal_c); Tbl_Entry_t *entry4 = Tbl_EntryAlloc(Tbl_EntryNormal_c); Tbl_EntrySetValue(entry3, 0, 0); Tbl_EntrySetValue(entry4, 1, 1); Tbl_TableSetEntry(newTable, entry3, rowNum, j, 1); Tbl_TableSetEntry(newTable, entry4, i, j, 1); } else { Tbl_TableSetEntry(newTable, Tbl_EntryDup(entry2), i, j, 1); } } continue; } } } } Tbl_TableForEachInputEntry(newTable, rowNum, colNum, entry) { if (Tbl_EntryIsEqual(entry)) { if (colNum == index) { Tbl_TableFree(newTable); return NIL(Tbl_Table_t); } else { int eqColNum = Tbl_EntryReadVarIndex(entry); if (eqColNum == index) { Tbl_TableFree(newTable); return NIL(Tbl_Table_t); } } } else if (colNum == index) { if (Tbl_EntryReadNumValues(entry) == 1) { Tbl_EntryComplement(entry, 0, 1); } } } return newTable; } /* Tbl_TableInvertBinaryInputColumn */ /*---------------------------------------------------------------------------*/ /* Definition of internal functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [Remove last row from table] Description [optional] SideEffects [required] SeeAlso [optional] ******************************************************************************/ boolean TblTableDeleteLastRow( Tbl_Table_t* table) { array_t *dataArray; Tbl_Row_t *row; int rowNum; dataArray = array_dup(TblTableReadData(table)); array_free(TblTableReadData(table)); TblTableReadData(table)= array_alloc(Tbl_Row_t*,0); for(rowNum=0; rowNum < (array_n(dataArray)-1); rowNum++) { row = array_fetch(Tbl_Row_t*,dataArray,rowNum); array_insert_last(Tbl_Row_t*,TblTableReadData(table),row); } return TRUE; } /*---------------------------------------------------------------------------*/ /* Definition of static functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [Set entry correctly] Description [optional] SideEffects [required] SeeAlso [optional] ******************************************************************************/ static void SetAdjustedEntry( Tbl_Table_t *table, Tbl_Entry_t *entry, int index, int rownum, int colnum, boolean flag) { Tbl_Entry_t *newEntry; if (flag ==0) { if (colnum < index) { /* should free if necessary */ newEntry = Tbl_TableReadEntry(table,rownum,colnum,0); if (newEntry==NIL(Tbl_Entry_t)) { Tbl_TableSetEntry(table,entry,rownum,colnum,0); } else { Tbl_EntryFree(entry); } } else if (colnum > index) { /* should free if necessary */ newEntry = Tbl_TableReadEntry(table,rownum,colnum-1,0); if (newEntry==NIL(Tbl_Entry_t)) { Tbl_TableSetEntry(table,entry,rownum,colnum-1,0); } else { Tbl_EntryFree(entry); } } else { Tbl_EntryFree(entry); } } else { newEntry = Tbl_TableReadEntry(table,rownum,colnum,1); if (newEntry== NIL(Tbl_Entry_t)) { Tbl_TableSetEntry(table,entry,rownum,colnum,1); } else { Tbl_EntryFree(newEntry); Tbl_TableSetEntry(table,entry,rownum,colnum,1); } } } /**Function******************************************************************** Synopsis [Set entry correctly] Description [optional] SideEffects [required] SeeAlso [optional] ******************************************************************************/ static void SetEntry( Tbl_Table_t *newTable, Tbl_Entry_t *entry1, Tbl_Entry_t *entry2, int rownum, int colnum, int index, boolean flag) { int varcolnum; Tbl_Entry_t *newEntry; if (entry1->type == Tbl_EntryNormal_c) { SetAdjustedEntry(newTable,Tbl_EntryDup(entry1),index,rownum,colnum, flag); } else { /* its of type equal */ varcolnum = Tbl_EntryReadVarIndex(entry1); if (varcolnum < index) { SetAdjustedEntry(newTable,Tbl_EntryDup(entry1),index,rownum,colnum, flag); } else { if (varcolnum > index) { newEntry = Tbl_EntryDup(entry1); Tbl_EntrySetEqual(newEntry,varcolnum-1); SetAdjustedEntry(newTable,newEntry,index,rownum,colnum,flag); } else { SetAdjustedEntry(newTable,Tbl_EntryDup(entry2),index,rownum,colnum, flag); } } } }