home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- *
- * decimal.c
- *
- * Quine - McClusky Method
- *
- * By: John A. Schlack
- * Dates: October 1994 - November 1994
- *
- *
- * This program implements to Quine-McClusky method for reducing a function to its
- * prime implicants. The user must specify the number of variables (2 to 8) and the
- * decimal components that define the function. The program will calculate the prime
- * implicants. The output is in the form: x1x2...xn (where n has a maximum value of
- * the number of variables chosen by the user). x1 is the most significant term (bit)
- * while xn is the least significant.
- *
- *
- * Limitations:
- * 1) No more than 8 variables can be used (even if "MAX_VARS" is changed below)
- * without major changes to the data structures. The data structures use
- * "unsigned char", which limits the total variables to 8. This can be changed,
- * but be wary that certain constants (which are hard coded) may also need to
- * be altered.
- *
- * 2) This code has not been extensively tested. It seems to work properly, but
- * cases not yet tested may cause errors.
- *
- * 3) This code was developed on a Power Macintosh computer running in 32 bit mode
- * (and using a flat memory model). Segmented architectures may cause this
- * program problems, and may also limit the maximum number of variables that
- * can be used.
- *
- * 4) The user interface code may be a major limiting factor. It requires the user
- * to hand enter the decimal components of the function. This can be tedious
- * and error prone. Also, continuing the decimal function on more than one
- * line has not been tested.
- *
- * 5) This code is written entirely in ANSI C. This means that it is compatible
- * across all major computer systems. It also means that platform specific
- * code to take advantage of proprietary user interfaces does not exist, making
- * data entry more difficult.
- *
- *
- * You may not use any portion of this code (whether in source code or compiled form)
- * without written permission from its author. You may contact the author by writing to:
- *
- * John A. Schlack
- * 406 Newgate Court, Apt. A1
- * Andalusia, Pa. 19020
- * USA
- *
- *
- * Release Notes:
- *
- * 1.00 10/19/94 Created Quine-McClusky method of generating
- * prime implicants (they are NOT irredundant form).
- * 1.10 11/02/94 Isolate Quine-McClusky method from user input.
- * Return pointer to resulting prime implicants
- * for reduction or manipulation by other routines.
- * 1.20 11/28/94 Fixed bug in bit table which caused it to be only
- * 128 elements instead of 256 (crashed on 8 variables).
- *
- ****************************************************************************/
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include "qmPrime.h"
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- typedef struct entryStruct
- {
- unsigned char * decimal;
- unsigned char * difference;
- char used;
- } entryStruct;
-
- typedef struct segmentStruct
- {
- short count;
- entryStruct * entries;
- } segmentStruct;
-
- typedef struct listStruct
- {
- short listNum;
- short count;
- segmentStruct * segments;
- } listStruct;
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- /* PROTOTYPES */
-
- static char * buildBitsSetArray( short vars );
- static void freeList( listStruct * list, short num );
- static void freeSegment( segmentStruct * baseSeg, short numSegs );
- static void purgeSegment( segmentStruct * segment );
- static void freeEntries( entryStruct * baseEntry, short entryCount );
- static listStruct * buildBaseList( short vars );
- static void doQuineMcClusky( char * bitTable, listStruct * list, short * func, short fNum,
- short vars );
- static short compareSegments( char * bitTable, segmentStruct * seg1, segmentStruct * seg2,
- segmentStruct * nextSeg, short curLevel );
- static void buildList1( char * bitTable, listStruct * list1, short * func, short fNum );
- static entryStruct * appendEntry( segmentStruct * seg, short decCount, short difCount );
- static long printResults( listStruct * list, short actualVars );
- static void simplifyList( listStruct * list );
- static int ucharSortFunc( const void * a1, const void * a2 );
- static void dumpList( listStruct * list );
- static irredundant * primes2Irredundant( listStruct * list, long count, short actualVars );
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- irredundant * doDecimal( short * decFunction, short decCount, short actualVars )
- {
- irredundant * ir;
- listStruct * list;
- char * binaryBitsSet;
- long primes;
- short maxDecs;
-
- maxDecs = 1 << actualVars;
- if (decCount >= maxDecs)
- {
- printf( "\n*** Trivial solution: 1 ***\n" );
- exit( 1 );
- }
- if (decCount <= 0)
- {
- printf( "\n*** Trivial solution: 0 ***\n" );
- exit( 1 );
- }
-
- binaryBitsSet = buildBitsSetArray( MAX_VARS );
- list = buildBaseList( MAX_VARS );
- doQuineMcClusky( binaryBitsSet, list, decFunction, decCount, actualVars );
- primes = printResults( list, actualVars );
- ir = (primes > 0L) ? (primes2Irredundant( list, primes, actualVars )) : NULL;
- free( binaryBitsSet );
- freeList( list, MAX_VARS );
-
- return ir;
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- /*
- static char * buildBitsSetArray( short vars )
-
- Description:
- This function builds a table of the number of bits set for the table's
- index. That is, for index entry 4, the value is 1 since 4 has 1 bit set.
- The number of entries in this table is 2 to the "vars" power.
-
- This function will abort the program on an invalid parameter or low memory.
-
- Input:
- "vars" is the number of variables that this program can handle. This
- value control the number of entries in the table.
-
- Output:
- none
-
- Globals Modified:
- none
-
- Returns:
- Pointer to the table.
- */
-
-
- static char * buildBitsSetArray( short vars )
- {
- char * array;
- long i, j, entries;
- short count;
-
- if ((vars < 2) || (vars > 32))
- paramError( "buildBitsSetArray", 1 );
- entries = 1L << vars;
-
- array = malloc( entries * sizeof( char ) );
- if (array == NULL)
- lowMemory();
-
- for (i=0L; i<entries; i++)
- {
- for (j=1L, count=0; j<entries; j<<=1)
- {
- if (i & j)
- count++;
- }
- array[i] = (char) count;
- }
-
- return array;
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- static void freeList( listStruct * list, short num )
- {
- short i;
-
- if (list == NULL)
- return;
-
- for (i=0; i<num; i++)
- freeSegment( list[i].segments, list[i].count );
- free( list );
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- static void freeSegment( segmentStruct * baseSeg, short numSegs )
- {
- short i;
-
- if (baseSeg == NULL)
- return;
-
- for (i=0; i<numSegs; i++)
- freeEntries( baseSeg[i].entries, baseSeg[i].count );
- free( baseSeg );
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- /*
- This function is used to free up system memory after a segment's entries
- have been processed. All used entries are deleted since their data will
- no longer be used in this program.
- */
- static void purgeSegment( segmentStruct * segment )
- {
- entryStruct * entry;
- short i;
-
- if (segment == NULL)
- return;
-
- entry = segment->entries;
- if (entry == NULL)
- return;
-
- for (i=0; i<segment->count; i++, entry++)
- {
- if (entry->used)
- {
- if (entry->decimal != NULL)
- {
- free( entry->decimal );
- entry->decimal = NULL;
- }
- if (entry->difference != NULL)
- {
- free( entry->difference );
- entry->difference = NULL;
- }
- }
- }
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- /*
- "baseEntry" is a pointer to the first element of an entries array. We must free all
- of the "decimal" and "difference" arrays before freeing the actual base.
- */
- static void freeEntries( entryStruct * baseEntry, short entryCount )
- {
- entryStruct * entry;
- short i;
-
- if (baseEntry == NULL)
- return;
-
- entry = baseEntry;
- for (i=0; i<entryCount; i++, entry++)
- {
- if (entry->decimal != NULL)
- free( entry->decimal );
- if (entry->difference != NULL)
- free( entry->difference );
- }
- free( baseEntry );
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- /*
- listStruct * buildBaseList( short vars )
-
- Description:
- This function allocates the base memory for all possible lists and
- segment arrays within those lists. One list is created for each
- variable, with the number of segments per list set at ("vars" -
- list number - 1). All segments are zeroed.
-
- Input:
- "vars" is the number of variables that this program can handle. This
- value control the number of lists.
-
- Output:
- none
-
- Globals Modified:
- none
-
- Returns:
- Pointer to the list array.
- */
-
-
- static listStruct * buildBaseList( short vars )
- {
- listStruct * list;
- size_t size;
- short i;
-
- if ((vars < 2) || (vars > 32))
- paramError( "buildBaseList", 1 );
-
- // create array of list pointers
- size = vars * sizeof( listStruct );
- list = malloc( size );
- if (list == NULL)
- lowMemory();
-
- // initialize list pointers
- for (i=0; i<vars; i++)
- {
- list[i].listNum = i + 1;
- list[i].count = vars + 1 - i;
- list[i].segments = calloc( list[i].count, sizeof( segmentStruct ) );
- if (list[i].segments == NULL)
- lowMemory();
- }
-
- return list;
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- static void doQuineMcClusky( char * bitTable, listStruct * list, short * func, short fNum, short vars )
- {
- segmentStruct * nextSeg;
- short doNextList, i, j;
-
- buildList1( bitTable, &(list[0]), func, fNum );
-
- for (i=1; i<vars; i++, list++)
- {
- doNextList = 0;
- nextSeg = (list+1)->segments; // point to first segment in next list
-
- for (j=1; j<list->count; j++)
- {
- if (compareSegments( bitTable, &list->segments[j-1], &list->segments[j],
- nextSeg, i ))
- {
- nextSeg++; // created some segment entries, go to next segment
- doNextList = 1; // at least 1 new entry in next list, will continue
- }
- purgeSegment( &list->segments[j-1] ); // purge each segment as it is compared
- }
- purgeSegment( &list->segments[j-1] ); // purge last segment
-
- if (!doNextList)
- break;
-
- #if DEBUG
- dumpList( list + 1 );
- #endif
-
- simplifyList( list + 1 ); // remove duplicate entries from new list
-
- #if DEBUG
- dumpList( list + 1 );
- #endif
- }
-
- #if DEBUG
- dumpList( list );
- #endif
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- static short compareSegments( char * bitTable, segmentStruct * seg1, segmentStruct * seg2,
- segmentStruct * nextSeg, short curLevel )
- {
- entryStruct * elo, * ehi, * enew;
- long count;
- short i, j, seg1count, seg2count, diff;
- short nextDec, nextDif, curDec, curDif;
-
- // verify parameters
- if ((seg1->count == 0) || (seg2->count == 0))
- return 0;
-
- // initialize search variables
- seg1count = seg1->count;
- seg2count = seg2->count;
- elo = seg1->entries;
- count = 0L;
- nextDec = 1 << curLevel;
- nextDif = curLevel;
- curDec = nextDec >> 1;
- curDif = nextDif - 1;
-
- // compare all entries in lower segment with those in upper segment
- for (i=0; i<seg1count; i++, elo++)
- {
- ehi = seg2->entries;
- for (j=0; j<seg2count; j++, ehi++)
- {
- // verify difference values
- if (curDif)
- if (memcmp( elo->difference, ehi->difference, (size_t) curDif ))
- continue;
-
- // check differences in first entry
- diff = (short) *ehi->decimal - (short) *elo->decimal;
- if (diff <= 0)
- continue;
-
- // insert entry in next list (difference is multiple of 2)
- if (bitTable[diff] == 1)
- {
- // update entries as used and create a new entry in the next list
- elo->used = ehi->used = 1;
- count++;
- enew = appendEntry( nextSeg, nextDec, nextDif );
- enew->used = 0;
-
- // copy decimal data
- memcpy( enew->decimal, elo->decimal, (size_t) curDec );
- memcpy( enew->decimal + curDec, ehi->decimal, (size_t) curDec );
-
- // copy difference data
- if (curDif > 0)
- memcpy( enew->difference, elo->difference, (size_t) curDif );
- *(enew->difference + curDif) = (unsigned char) diff;
- }
- }
- }
-
- return ((count) ? 1 : 0);
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- /*
- static void buildList1( char * bitTable, listStruct * list1, short * func, short fNum )
-
- Description:
- This function builds the initial list (list 1) from the user specified
- decimal function.
-
- Input:
- "bitTable" is a table with entries that correspond to the number of set bits
- in a decimal number.
- "func" is a list of user specified decimals that specify the function.
- "fNum" are the number of entries in the array "func".
-
- Output:
- "list1" points to the first entry of the list master pointer. It's segments
- will be altered to contain the user specified data.
-
- Globals Modified:
- none
-
- Returns:
- none
- */
-
-
- static void buildList1( char * bitTable, listStruct * list1, short * func, short fNum )
- {
- segmentStruct * seg;
- entryStruct * entry;
- short i, indx, dec;
-
- for (i=0; i<fNum; i++)
- {
- // get segment number by looking up decimal in bit table
- dec = func[i];
- indx = (short) bitTable[dec];
- seg = &(list1->segments[indx]);
-
- // add decimal data to list
- entry = appendEntry( seg, 1, 0 );
- entry->decimal[0] = (unsigned char) dec;
- }
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- /*
- static entryStruct * appendEntry( segmentStruct * seg, short decCount, short difCount )
-
- Description:
- This routine expands segment to include a new entry. The memory for the
- entry sub-data is also allocated. The calling function must fill this
- space.
-
- Input:
- "decCount" is the number of decimal entries to allocate in the new
- "entry" struct.
- "difCount" is the number of difference entries to allocate in the
- new "entry" struct.
-
- Output:
- "seg" is the segment data that is being expanded.
-
- Globals Modified:
- none
-
- Returns:
- Pointer to the new "entry" struct (the new element appended to "seg").
- */
-
-
- static entryStruct * appendEntry( segmentStruct * seg, short decCount, short difCount )
- {
- entryStruct * entry;
- size_t size;
-
- // insert a new entry in the array
- (seg->count)++;
- size = seg->count * sizeof( entryStruct );
- seg->entries = realloc( seg->entries, size );
- if (seg->entries == NULL)
- lowMemory();
-
- // allocate decimal list for new entry
- entry = &(seg->entries[seg->count - 1]);
- entry->used = 0;
- entry->decimal = calloc( decCount, sizeof( unsigned char ) );
- if (entry->decimal == NULL)
- lowMemory();
-
- // allocate difference list for new entry
- if (difCount <= 0)
- entry->difference = NULL;
- else
- {
- entry->difference = calloc( difCount, sizeof( unsigned char ) );
- if (entry->difference == NULL)
- lowMemory();
- }
-
- return entry;
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- static long printResults( listStruct * list, short actualVars )
- {
- segmentStruct * seg;
- entryStruct * entry;
- long count;
- short i, j, k, minLevel;
-
- printf( "\n--------------------------------------------\n" );
- printf( "Prime Implicants (x%d is MSB, x0 is LSB):\n\n", actualVars - 1 );
-
- count = 0L;
- minLevel = 0;
- for (i=0; i<actualVars; i++, list++)
- {
- if (list->count <= 0)
- continue;
-
- seg = list->segments;
- for (j=0; j<list->count; j++, seg++)
- {
- if (seg->count <= 0)
- continue;
-
- entry = seg->entries;
- for (k=0; k<seg->count; k++, entry++)
- {
- if (!(entry->used))
- {
- printEntry( entry->decimal, entry->difference, list->listNum,
- actualVars, &minLevel );
- count++;
- }
- }
- }
- }
-
- if (!count)
- printf( "\n*** ERROR! No prime implicants found. ***\n" );
-
- return count;
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- static void simplifyList( listStruct * list )
- {
- segmentStruct * seg;
- entryStruct * entry, * ecomp;
- short i, j, k, numDec, numDif, countm1;
-
- numDif = list->listNum - 1;
- numDec = 1 << numDif;
- seg = list->segments;
-
- for (i=0; i<list->count; i++, seg++)
- {
- if (seg->count <= 0)
- continue;
-
- // sort all entries in all segments
- entry = seg->entries;
- for (j=0; j<seg->count; j++, entry++)
- {
- if (numDec > 1)
- {
- qsort( entry->decimal, (size_t) numDec, sizeof( unsigned char ),
- ucharSortFunc );
- }
- if (numDif > 1)
- {
- qsort( entry->difference, (size_t) numDif, sizeof( unsigned char ),
- ucharSortFunc );
- }
- }
-
- // remove duplicate entries in segments
- countm1 = seg->count - 1;
- entry = seg->entries;
- for (j=0; j<countm1; j++, entry++)
- {
- ecomp = &(seg->entries[j+1]);
- for (k=j+1; k<seg->count; k++, ecomp++)
- {
- if (memcmp( entry->decimal, ecomp->decimal, (size_t) numDec ))
- continue;
- if (memcmp( entry->difference, ecomp->difference, (size_t) numDif ))
- continue;
-
- // duplicate entry, remove it
- free( ecomp->decimal );
- free( ecomp->difference );
- memcpy( &(seg->entries[k]), &(seg->entries[k+1]),
- (seg->count - k - 1) * sizeof( entryStruct ) );
-
- // update our counters
- (seg->count)--;
- countm1--;
- ecomp--; // decrement "ecomp" since it will be incremented (end of loop)
- k--; // decrement "k" for reason above
- }
- }
- }
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- static int ucharSortFunc( const void * a1, const void * a2 )
- {
- unsigned char v1, v2;
-
- v1 = *((unsigned char *) a1);
- v2 = *((unsigned char *) a2);
- if (v1 < v2)
- return -1;
- if (v1 > v2)
- return 1;
- return 0;
- }
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- #if DEBUG
- static void dumpList( listStruct * list )
- {
- segmentStruct * seg;
- entryStruct * entry;
- short i, j, numDec, numDif;
-
- numDif = list->listNum - 1;
- numDec = 1 << numDif;
- fprintf( fp, "\n ---------------------- Dump List = %d ----------------------\n", list->listNum );
-
- if ((seg = list->segments) == NULL)
- return;
- for (i=0; i<list->count; i++, seg++)
- {
- if (seg->count <= 0)
- continue;
- fprintf( fp, "\nsegment = %d\n", i );
-
- if ((entry = seg->entries) == NULL)
- continue;
- for (j=0; j<seg->count; j++, entry++)
- {
- if (entry->decimal == NULL)
- continue;
-
- fprintf( fp, " " );
- printNumbers( fp, entry->decimal, numDec );
- if (entry->difference != NULL)
- {
- fprintf( fp, " " );
- printNumbers( fp, entry->difference, numDif );
- }
- fprintf( fp, " %c\n", (entry->used) ? 'Y' : 'N' );
- }
- }
- fputc( '\n', fp );
- }
- #endif
-
-
- /* --------------------------------------------------------------------------------------------- */
-
-
- static irredundant * primes2Irredundant( listStruct * list, long count, short actualVars )
- {
- irredundant * ir;
- irElement * elem;
- segmentStruct * seg;
- entryStruct * entry;
- size_t size;
- short i, j, k;
-
- // allocate main buffer to store irredundant info
- ir = (irredundant *) malloc( sizeof( irredundant ) );
- if (ir == NULL)
- lowMemory();
-
- // allocate expected array size
- ir->irArray = calloc( (size_t) count, sizeof( irElement ) );
- if (ir->irArray == NULL)
- lowMemory();
-
- // initialize
- ir->len = 0;
- elem = ir->irArray;
-
- // loop through all segments
- for (i=0; i<actualVars; i++, list++)
- {
- if (list->count <= 0)
- continue;
-
- seg = list->segments;
- for (j=0; j<list->count; j++, seg++)
- {
- if (seg->count <= 0)
- continue;
-
- entry = seg->entries;
- for (k=0; k<seg->count; k++, entry++)
- {
- if (entry->used)
- continue;
-
- // check to see if we need a larger array (should not happen)
- if (count-- < 0)
- {
- size = ((size_t) ir->len + 1) * sizeof( irElement );
- ir->irArray = realloc( ir->irArray, size );
- if (ir->irArray == NULL)
- lowMemory();
- elem = &(ir->irArray[ir->len]);
- memset( &elem, 0, sizeof( irElement ) );
- }
-
- elem->decimal = entry->decimal;
- elem->difference = entry->difference;
- elem->level = i + 1;
- (ir->len)++;
- elem++;
-
- // make sure we don't free the prime implicants
- entry->decimal = NULL;
- entry->difference = NULL;
- }
- }
- }
-
- return ir;
- }
-