tract.c
上传用户:lengbin
上传日期:2010-03-31
资源大小:121k
文件大小:35k
开发平台:

C/C++

  1. /*----------------------------------------------------------------------
  2.   File    : tract.c
  3.   Contents: item and transaction management
  4.   Author  : Christian Borgelt
  5.   History : 14.02.1996 file created as apriori.c
  6.             24.06.1996 function _get_item optimized
  7.             01.07.1996 adapted to modified symtab module
  8.             04.01.1998 scan functions moved to module 'tfscan'
  9.             09.06.1998 vector enlargement modified
  10.             20.06.1998 adapted to changed st_create function
  11.             07.08.1998 bug in function _get_tract (is_read) fixed
  12.             08.08.1998 item appearances added
  13.             17.08.1998 item sorting and recoding added
  14.             02.09.1998 several assertions added
  15.             05.02.1999 long int changed to int
  16.             22.10.1999 bug in item appearances reading fixed
  17.             11.11.1999 adapted to name/identifier maps
  18.             01.12.1999 check of item appearance added to sort function
  19.             15.03.2000 removal of infrequent items added
  20.             14.07.2001 adapted to modified module tfscan
  21.             27.12.2001 item functions made a separate module
  22.             18.11.2001 transaction functions made a separate module
  23.             28.12.2001 first version of this module completed
  24.             12.01.2002 empty field at end of record reported as error
  25.             06.02.2002 item sorting reversed (ascending order)
  26.             19.02.2002 transaction tree functions added
  27.             17.07.2003 functions is_filter, ta_filter, tas_filter added
  28.             15.08.2003 bug in function tat_delete fixed
  29.             21.08.2003 parameter 'heap' added to tas_sort, tat_create
  30.             20.09.2003 empty transactions in input made possible
  31.             18.12.2003 padding for 64 bit architecture added
  32.             26.02.2004 item frequency counting moved to is_read
  33.             20.11.2004 function tat_mark added
  34.             20.06.2005 function _nocmp added for neutral sorting
  35. ----------------------------------------------------------------------*/
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <limits.h>
  40. #include <assert.h>
  41. #include "tract.h"
  42. #include "vecops.h"
  43. #ifdef STORAGE
  44. #include "storage.h"
  45. #endif
  46. /*----------------------------------------------------------------------
  47.   Preprocessor Definitions
  48. ----------------------------------------------------------------------*/
  49. #define BLKSIZE  256            /* block size for enlarging vectors */
  50. /*----------------------------------------------------------------------
  51.   Constants
  52. ----------------------------------------------------------------------*/
  53. /* --- item appearance indicators --- */
  54. static const char *i_body[] = { /* item to appear in bodies only */
  55.   "i",  "in",  "a", "ante", "antecedent", "b", "body", NULL };
  56. static const char *i_head[] = { /* item to appear in heads only */
  57.   "o",  "out", "c", "cons", "consequent", "h", "head", NULL };
  58. static const char *i_both[] = { /* item to appear in both */
  59.   "io", "inout", "ac", "bh", "both",                   NULL };
  60. static const char *i_ignore[] ={/* item to ignore */
  61.   "n", "neither", "none", "ign", "ignore", "-",        NULL };
  62. /*----------------------------------------------------------------------
  63.   Auxiliary Functions
  64. ----------------------------------------------------------------------*/
  65. static int _appcode (const char *s)
  66. {                               /* --- get appearance indicator code */
  67.   const char **p;               /* to traverse indicator list */
  68.   assert(s);                    /* check the function argument */
  69.   for (p = i_body;   *p; p++)   /* check 'body' indicators */
  70.     if (strcmp(s, *p) == 0) return APP_BODY;
  71.   for (p = i_head;   *p; p++)   /* check 'head' indicators */
  72.     if (strcmp(s, *p) == 0) return APP_HEAD;
  73.   for (p = i_both;   *p; p++)   /* check 'both' indicators */
  74.     if (strcmp(s, *p) == 0) return APP_BOTH;
  75.   for (p = i_ignore; *p; p++)   /* check 'ignore' indicators */
  76.     if (strcmp(s, *p) == 0) return APP_NONE;
  77.   return -1;                    /* if none found, return error code */
  78. }  /* _appcode() */
  79. /*--------------------------------------------------------------------*/
  80. static int _get_item (ITEMSET *iset, FILE *file)
  81. {                               /* --- read an item */
  82.   int  d;                       /* delimiter type */
  83.   char *buf;                    /* read buffer */
  84.   ITEM *item;                   /* pointer to item */
  85.   int  *vec;                    /* new item vector */
  86.   int  size;                    /* new item vector size */
  87.   assert(iset && file);         /* check the function arguments */
  88.   d   = tfs_getfld(iset->tfscan, file, NULL, 0);
  89.   buf = tfs_buf(iset->tfscan);  /* read the next field (item name) */
  90.   if ((d < 0) || (buf[0] == '')) return d;
  91.   item = nim_byname(iset->nimap, buf);
  92.   if (!item) {                  /* look up the name in name/id map */
  93.     if (iset->app == APP_NONE)  /* if new items are to be ignored, */
  94.       return d;                 /* do not register the item */
  95.     item = nim_add(iset->nimap, buf, sizeof(ITEM));
  96.     if (!item) return E_NOMEM;  /* add the new item to the map, */
  97.     item->frq = item->xfq = 0;  /* initialize the frequency counters */
  98.     item->app = iset->app;      /* (occurrence and sum of t.a. sizes) */
  99.   }                             /* and set the appearance indicator */
  100.   size = iset->vsz;             /* get the item vector size */
  101.   if (iset->cnt >= size) {      /* if the item vector is full */
  102.     size += (size > BLKSIZE) ? (size >> 1) : BLKSIZE;
  103.     vec   = (int*)realloc(iset->items, size *sizeof(int));
  104.     if (!vec) return E_NOMEM;   /* enlarge the item vector */
  105.     iset->items = vec; iset->vsz = size;
  106.   }                             /* set the new vector and its size */
  107.   iset->items[iset->cnt++] = item->id;
  108.   return d;                     /* add the item to the transaction */
  109. }  /* _get_item() */            /* and return the delimiter type */
  110. /*--------------------------------------------------------------------*/
  111. static int _nocmp (const void *p1, const void *p2, void *data)
  112. {                               /* --- compare item frequencies */
  113.   if (((const ITEM*)p1)->app == APP_NONE)
  114.     return (((const ITEM*)p2)->app == APP_NONE) ? 0 : 1;
  115.   if (((const ITEM*)p2)->app == APP_NONE) return -1;
  116.   if (((const ITEM*)p1)->frq < (int)data)
  117.     return (((const ITEM*)p2)->frq < (int)data) ? 0 : 1;
  118.   if (((const ITEM*)p2)->frq < (int)data) return -1;
  119.   if (((const ITEM*)p1)->id  > ((const ITEM*)p2)->id) return  1;
  120.   if (((const ITEM*)p1)->id  < ((const ITEM*)p2)->id) return -1;
  121.   return 0;                     /* return sign of identifier diff. */
  122. }  /* _nocmp() */
  123. /*--------------------------------------------------------------------*/
  124. static int _asccmp (const void *p1, const void *p2, void *data)
  125. {                               /* --- compare item frequencies */
  126.   if (((const ITEM*)p1)->app == APP_NONE)
  127.     return (((const ITEM*)p2)->app == APP_NONE) ? 0 : 1;
  128.   if (((const ITEM*)p2)->app == APP_NONE) return -1;
  129.   if (((const ITEM*)p1)->frq < (int)data)
  130.     return (((const ITEM*)p2)->frq < (int)data) ? 0 : 1;
  131.   if (((const ITEM*)p2)->frq < (int)data) return -1;
  132.   if (((const ITEM*)p1)->frq > ((const ITEM*)p2)->frq) return  1;
  133.   if (((const ITEM*)p1)->frq < ((const ITEM*)p2)->frq) return -1;
  134.   return 0;                     /* return sign of frequency diff. */
  135. }  /* _asccmp() */
  136. /*--------------------------------------------------------------------*/
  137. static int _descmp (const void *p1, const void *p2, void *data)
  138. {                               /* --- compare item frequencies */
  139.   if (((const ITEM*)p1)->app == APP_NONE)
  140.     return (((const ITEM*)p2)->app == APP_NONE) ? 0 : 1;
  141.   if (((const ITEM*)p2)->app == APP_NONE) return -1;
  142.   if (((const ITEM*)p1)->frq > ((const ITEM*)p2)->frq) return -1;
  143.   if (((const ITEM*)p1)->frq < ((const ITEM*)p2)->frq) return  1;
  144.   return 0;                     /* return sign of frequency diff. */
  145. }  /* _descmp() */
  146. /*--------------------------------------------------------------------*/
  147. static int _asccmpx (const void *p1, const void *p2, void *data)
  148. {                               /* --- compare item frequencies */
  149.   if (((const ITEM*)p1)->app == APP_NONE)
  150.     return (((const ITEM*)p2)->app == APP_NONE) ? 0 : 1;
  151.   if (((const ITEM*)p2)->app == APP_NONE) return -1;
  152.   if (((const ITEM*)p1)->frq < (int)data)
  153.     return (((const ITEM*)p2)->frq < (int)data) ? 0 : 1;
  154.   if (((const ITEM*)p2)->frq < (int)data) return -1;
  155.   if (((const ITEM*)p1)->xfq > ((const ITEM*)p2)->xfq) return  1;
  156.   if (((const ITEM*)p1)->xfq < ((const ITEM*)p2)->xfq) return -1;
  157.   return 0;                     /* return sign of frequency diff. */
  158. }  /* _asccmpx() */
  159. /*--------------------------------------------------------------------*/
  160. static int _descmpx (const void *p1, const void *p2, void *data)
  161. {                               /* --- compare item frequencies */
  162.   if (((const ITEM*)p1)->app == APP_NONE)
  163.     return (((const ITEM*)p2)->app == APP_NONE) ? 0 : 1;
  164.   if (((const ITEM*)p2)->app == APP_NONE) return -1;
  165.   if (((const ITEM*)p1)->frq < (int)data)
  166.     return (((const ITEM*)p2)->frq < (int)data) ? 0 : 1;
  167.   if (((const ITEM*)p2)->frq < (int)data) return -1;
  168.   if (((const ITEM*)p1)->xfq > ((const ITEM*)p2)->xfq) return -1;
  169.   if (((const ITEM*)p1)->xfq < ((const ITEM*)p2)->xfq) return  1;
  170.   return 0;                     /* return sign of frequency diff. */
  171. }  /* _descmpx() */
  172. /*----------------------------------------------------------------------
  173.   Item Set Functions
  174. ----------------------------------------------------------------------*/
  175. ITEMSET* is_create (void)
  176. {                               /* --- create an item set */
  177.   ITEMSET *iset;                /* created item set */
  178.   iset = malloc(sizeof(ITEMSET));
  179.   if (!iset) return NULL;       /* create an item set */
  180.   iset->tfscan = tfs_create();  /* and its components */
  181.   iset->nimap  = nim_create(0, 0, (HASHFN*)0, (SYMFN*)0);
  182.   iset->items  = (int*)malloc(BLKSIZE *sizeof(int));
  183.   if (!iset->tfscan || !iset->nimap || !iset->items) {
  184.     is_delete(iset); return NULL; }
  185.   iset->app    = APP_BOTH;      /* initialize the other fields */
  186.   iset->vsz    = BLKSIZE;
  187.   iset->cnt    = 0;
  188.   iset->chars[0] = ' ';  iset->chars[1] = ' ';
  189.   iset->chars[2] = 'n'; iset->chars[3] = '';
  190.   return iset;                  /* return the created item set */
  191. }  /* is_create() */
  192. /*--------------------------------------------------------------------*/
  193. void is_delete (ITEMSET *iset)
  194. {                               /* --- delete an item set */
  195.   assert(iset);                 /* check the function argument */
  196.   if (iset->items)  free(iset->items);
  197.   if (iset->nimap)  nim_delete(iset->nimap);
  198.   if (iset->tfscan) tfs_delete(iset->tfscan);
  199.   free(iset);                   /* delete the components */
  200. }  /* is_delete() */            /* and the item set body */
  201. /*--------------------------------------------------------------------*/
  202. void is_chars (ITEMSET *iset, const char *blanks,  const char *fldseps,
  203.                               const char *recseps, const char *cominds)
  204. {                               /* --- set special characters */
  205.   assert(iset);                 /* check the function argument */
  206.   if (blanks)                   /* set blank characters */
  207.     iset->chars[0] = tfs_chars(iset->tfscan, TFS_BLANK,  blanks);
  208.   if (fldseps)                  /* set field separators */
  209.     iset->chars[1] = tfs_chars(iset->tfscan, TFS_FLDSEP, fldseps);
  210.   if (recseps)                  /* set record separators */
  211.     iset->chars[2] = tfs_chars(iset->tfscan, TFS_RECSEP, recseps);
  212.   if (cominds)                  /* set comment indicators */
  213.     tfs_chars(iset->tfscan, TFS_COMMENT, cominds);
  214. }  /* is_chars() */
  215. /*--------------------------------------------------------------------*/
  216. int is_item (ITEMSET *iset, const char *name)
  217. {                               /* --- get an item identifier */
  218.   ITEM *item = nim_byname(iset->nimap, name);
  219.   return (item) ? item->id :-1; /* look up the given name */
  220. }  /* is_item() */              /* in the name/identifier map */
  221. /*--------------------------------------------------------------------*/
  222. int is_readapp (ITEMSET *iset, FILE *file)
  223. {                               /* --- read appearance indicators */
  224.   int  d;                       /* delimiter type */
  225.   char *buf;                    /* read buffer */
  226.   ITEM *item;                   /* to access the item data */
  227.   assert(iset && file);         /* check the function arguments */
  228.   if (tfs_skip(iset->tfscan, file) < 0)
  229.     return E_FREAD;             /* skip leading comments */
  230.   buf = tfs_buf(iset->tfscan);  /* read the first record (one field) */
  231.   d   = tfs_getfld(iset->tfscan, file, NULL, 0);
  232.   if (d <  0)           return E_FREAD;
  233.   if (d >= TFS_FLD)     return E_FLDCNT;
  234.   iset->app = _appcode(buf);    /* get default appearance code */
  235.   if (iset->app < 0)    return E_UNKAPP;
  236.   while (d > TFS_EOF) {         /* read item/indicator pairs */
  237.     if (tfs_skip(iset->tfscan, file) < 0)
  238.       return E_FREAD;           /* skip more comments */
  239.     d = tfs_getfld(iset->tfscan, file, NULL, 0);
  240.     if (d <= TFS_EOF)           /* read the next item */
  241.       return (d < 0) ? E_FREAD : 0;
  242.     if (buf[0] == '')         /* check for end of file */
  243.       return E_ITEMEXP;         /* and for a missing item */
  244.     item = nim_add(iset->nimap, buf, sizeof(ITEM));
  245.     if (item == EXISTS) return E_DUPITEM;  /* add the new item */
  246.     if (item == NULL)   return E_NOMEM;    /* to the name/id map */
  247.     item->frq = 0;              /* clear the frequency counters */
  248.     item->xfq = 0;              /* (occurrence and sum of t.a. sizes) */
  249.     if (d < TFS_FLD)    return E_APPEXP;
  250.     d = tfs_getfld(iset->tfscan, file, NULL, 0);
  251.     if (d <  0)         return E_FREAD;
  252.     if (d >= TFS_FLD)   return E_FLDCNT;
  253.     item->app = _appcode(buf);  /* get the appearance indicator */
  254.     if (item->app <  0)  return E_UNKAPP;
  255.   }
  256.   return 0;                     /* return 'ok' */
  257. }  /* is_readapp() */
  258. /*--------------------------------------------------------------------*/
  259. int is_read (ITEMSET *iset, FILE *file)
  260. {                               /* --- read a transaction */
  261.   int  i, d;                    /* loop variable, delimiter type */
  262.   char *buf;                    /* read buffer */
  263.   ITEM *item;                   /* pointer to item */
  264.   assert(iset && file);         /* check the function arguments */
  265.   iset->cnt = 0;                /* initialize the item counter */
  266.   if (tfs_skip(iset->tfscan, file) < 0)
  267.     return E_FREAD;             /* skip leading comments */
  268.   d   = _get_item(iset, file);  /* read the first item and */
  269.   buf = tfs_buf(iset->tfscan);  /* get the read buffer */
  270.   if ((d      == TFS_EOF)       /* if at the end of the file */
  271.   &&  (buf[0] == ''))         /* and no item has been read, */
  272.     return 1;                   /* return 'end of file' */
  273.   while ((d      == TFS_FLD)    /* read the other items */
  274.   &&     (buf[0] != ''))      /* of the transaction */
  275.     d = _get_item(iset, file);  /* up to the end of the record */
  276.   if (d < TFS_EOF) return d;    /* check for a read error */
  277.   if ((buf[0] == '') && (d == TFS_FLD) && (iset->cnt > 0))
  278.     return E_ITEMEXP;           /* check for an empty field */
  279.   ta_sort(iset->items, iset->cnt); /* prepare the transaction */
  280.   iset->cnt = ta_unique(iset->items, iset->cnt);
  281.   for (i = iset->cnt; --i >= 0; ) {
  282.     item = nim_byid(iset->nimap, iset->items[i]);
  283.     item->frq += 1;             /* count the item and */
  284.     item->xfq += iset->cnt;     /* sum the transaction sizes */
  285.   }                             /* as an importance indicator */
  286.   return 0;                     /* return 'ok' */
  287. }  /* is_read() */
  288. /*--------------------------------------------------------------------*/
  289. int is_recode (ITEMSET *iset, int minfrq, int dir, int *map)
  290. {                               /* --- recode items w.r.t. frequency */
  291.   int      i, k, n, t;          /* loop variables, buffer */
  292.   ITEM     *item;               /* to traverse the items */
  293.   SYMCMPFN *cmp;                /* comparison function */
  294.   assert(iset);                 /* check the function arguments */
  295.   if      (dir >  1) cmp = _asccmpx;  /* get the appropriate */
  296.   else if (dir >  0) cmp = _asccmp;   /* comparison function */
  297.   else if (dir >= 0) cmp = _nocmp;    /* (ascending/descending) */
  298.   else if (dir > -2) cmp = _descmp;   /* and sort the items */
  299.   else               cmp = _descmpx;  /* w.r.t. their frequency */
  300.   nim_sort(iset->nimap, cmp, (void*)minfrq, map, 1);
  301.   for (n = nim_cnt(iset->nimap); --n >= 0; ) {
  302.     item = (ITEM*)nim_byid(iset->nimap, n);
  303.     if (item->frq < minfrq)     /* determine frequent items and */
  304.       item->app = APP_NONE;     /* set all others to 'ignore' */
  305.     else if (item->app != APP_NONE)
  306.       break;                    /* in addition, skip all items */
  307.   }                             /* that have been set to 'ignore' */
  308.   if (map) {                    /* if a map vector is provided */
  309.     for (i = k = 0; i < iset->cnt; i++) {
  310.       t = map[iset->items[i]];  /* traverse the current transaction */
  311.       if (t <= n) iset->items[k++] = t;
  312.     }                           /* recode all items and */
  313.     iset->cnt = k;              /* delete all items to ignore */
  314.     ta_sort(iset->items, k);    /* resort the items */
  315.   }
  316.   return n+1;                   /* return number of frequent items */
  317. }  /* is_recode() */
  318. /*--------------------------------------------------------------------*/
  319. int is_filter (ITEMSET *iset, const char *marks)
  320. {                               /* --- filter items in transaction */
  321.   return iset->cnt = ta_filter(iset->items, iset->cnt, marks);
  322. }  /* is_filter() */
  323. /*----------------------------------------------------------------------
  324.   Transaction Functions
  325. ----------------------------------------------------------------------*/
  326. int ta_unique (int *items, int n)
  327. {                               /* --- remove duplicate items */
  328.   int *s, *d;                   /* to traverse the item vector */
  329.   assert(items && (n >= 0));    /* check the function arguments */
  330.   if (n <= 1) return n;         /* check for 0 or 1 item */
  331.   for (d = s = items; --n > 0;) /* traverse the sorted vector */
  332.     if (*++s != *d) *++d = *s;  /* and remove duplicate items */ 
  333.   return (int)(++d -items);     /* return the new number of items */
  334. }  /* ta_unique() */
  335. /*--------------------------------------------------------------------*/
  336. int ta_filter (int *items, int n, const char *marks)
  337. {                               /* --- filter items in a transaction */
  338.   int i, k;                     /* loop variables */
  339.   assert(items && (n >= 0));    /* check the function arguments */
  340.   for (i = k = 0; i < n; i++)   /* remove all unmarked items */
  341.     if (marks[items[i]]) items[k++] = items[i];
  342.   return k;                     /* return the new number of items */
  343. }  /* ta_filter() */
  344. /*--------------------------------------------------------------------*/
  345. static int ta_cmp (const void *p1, const void *p2, void *data)
  346. {                               /* --- compare transactions */
  347.   int       k, k1, k2;          /* loop variable, counters */
  348.   const int *i1, *i2;           /* to traverse the item identifiers */
  349.   assert(p1 && p2);             /* check the function arguments */
  350.   i1 = ((const TRACT*)p1)->items;
  351.   i2 = ((const TRACT*)p2)->items;
  352.   k1 = ((const TRACT*)p1)->cnt; /* get the item vectors */
  353.   k2 = ((const TRACT*)p2)->cnt; /* and the numbers of items */
  354.   for (k  = (k1 < k2) ? k1 : k2; --k >= 0; i1++, i2++) {
  355.     if (*i1 > *i2) return  1;   /* compare corresponding items */
  356.     if (*i1 < *i2) return -1;   /* and abort the comparison */
  357.   }                             /* if one of them is greater */
  358.   if (k1 > k2) return  1;       /* if one of the transactions */
  359.   if (k1 < k2) return -1;       /* is not empty, it is greater */
  360.   return 0;                     /* otherwise the two trans. are equal */
  361. }  /* ta_cmp() */
  362. /*--------------------------------------------------------------------*/
  363. static int ta_cmpx (const TRACT *ta, const int *items, int n)
  364. {                               /* --- compare transactions */
  365.   int       k, m;               /* loop variable, counter */
  366.   const int *p;                 /* to traverse the item identifiers */
  367.   assert(ta && items);          /* check the function arguments */
  368.   p = ta->items; m = ta->cnt;   /* traverse the item vector */
  369.   m = ta->cnt;
  370.   for (k = (n < m) ? n : m; --k >= 0; p++, items++) {
  371.     if (*p > *items) return  1; /* compare corresponding items */
  372.     if (*p < *items) return -1; /* and abort the comparison */
  373.   }                             /* if one of them is greater */
  374.   if (m > n) return  1;         /* if one of the transactions */
  375.   if (m < n) return -1;         /* is not empty, it is greater */
  376.   return 0;                     /* otherwise the two trans. are equal */
  377. }  /* ta_cmpx() */
  378. /*----------------------------------------------------------------------
  379.   Transaction Set Functions
  380. ----------------------------------------------------------------------*/
  381. TASET* tas_create (ITEMSET *itemset)
  382. {                               /* --- create a transaction set */
  383.   TASET *taset;                 /* created transaction set */
  384.   assert(itemset);              /* check the function argument */
  385.   taset = malloc(sizeof(TASET));
  386.   if (!taset) return NULL;      /* create a transaction set */
  387.   taset->itemset = itemset;     /* and store the item set */
  388.   taset->cnt     = taset->vsz = taset->max = taset->total = 0;
  389.   taset->tracts  = NULL;        /* initialize the other fields */
  390.   return taset;                 /* return the created t.a. set */
  391. }  /* tas_create() */
  392. /*--------------------------------------------------------------------*/
  393. void tas_delete (TASET *taset, int delis)
  394. {                               /* --- delete a transaction set */
  395.   assert(taset);                /* check the function argument */
  396.   if (taset->tracts) {          /* if there are loaded transactions */
  397.     while (--taset->cnt >= 0)   /* traverse the transaction vector */
  398.       free(taset->tracts[taset->cnt]);
  399.     free(taset->tracts);        /* delete all transactions */
  400.   }                             /* and the transaction vector */
  401.   if (delis && taset->itemset) is_delete(taset->itemset);
  402.   free(taset);                  /* delete the item set and */
  403. }  /* tas_delete() */           /* the transaction set body */
  404. /*--------------------------------------------------------------------*/
  405. int tas_add (TASET *taset, const int *items, int n)
  406. {                               /* --- add a transaction */
  407.   TRACT *ta;                    /* new transaction */
  408.   int   *p;                     /* to traverse the transaction */
  409.   TRACT **vec;                  /* new transaction vector */
  410.   int   size;                   /* new transaction vector size */
  411.   assert(taset);                /* check the function arguments */
  412.   size = taset->vsz;            /* get the transaction vector size */
  413.   if (taset->cnt >= size) {     /* if the transaction vector is full */
  414.     size += (size > BLKSIZE) ? (size >> 1) : BLKSIZE;
  415.     vec   = (TRACT**)realloc(taset->tracts, size *sizeof(TRACT*));
  416.     if (!vec) return -1;        /* enlarge the transaction vector */
  417.     taset->tracts = vec; taset->vsz = size;
  418.   }                             /* set the new vector and its size */
  419.   if (!items) {                 /* if no transaction is given */
  420.     items = is_tract(taset->itemset);
  421.     n     = is_tsize(taset->itemset);
  422.   }                             /* get it from the item set */
  423.   ta = (TRACT*)malloc(sizeof(TRACT) +(n-1) *sizeof(int));
  424.   if (!ta) return -1;           /* create a new transaction */
  425.   taset->tracts[taset->cnt++]  = ta;
  426.   if (n > taset->max)           /* store the transaction and */
  427.     taset->max = n;             /* update maximal transaction size */
  428.   taset->total += n;            /* sum the number of items */
  429.   for (p = ta->items +(ta->cnt = n); --n >= 0; )
  430.     *--p = items[n];            /* copy the items of the t.a. */
  431.   return 0;                     /* return 'ok' */
  432. }  /* tas_add() */
  433. /*--------------------------------------------------------------------*/
  434. void tas_recode (TASET *taset, int *map, int cnt)
  435. {                               /* --- recode items */
  436.   int   i, k, n, x;             /* loop variables, buffer */
  437.   TRACT *t;                     /* to traverse the transactions */
  438.   int   *p;                     /* to traverse the item identifiers */
  439.   assert(taset && map);         /* check the function arguments */
  440.   taset->max = taset->total = 0;/* clear the maximal size and total */
  441.   for (n = taset->cnt; --n >= 0; ) {
  442.     t = taset->tracts[n];       /* traverse the transactions and */
  443.     p = t->items;               /* the items of each transaction */
  444.     for (i = k = 0; i < t->cnt; i++) {
  445.       x = map[p[i]];            /* recode the items and */
  446.       if (x < cnt) p[k++] = x;  /* remove superfluous items */
  447.     }                           /* from the transaction */
  448.     if (k > taset->max)         /* update the max. transaction size */
  449.       taset->max = k;           /* with the new size of the t.a. */
  450.     taset->total += k;          /* sum the number of items */
  451.     ta_sort(t->items, t->cnt = k);
  452.   }                             /* resort the item identifiers */
  453. }  /* tas_recode() */
  454. /*--------------------------------------------------------------------*/
  455. int tas_filter (TASET *taset, const char *marks)
  456. {                               /* --- filter items in a trans. set */
  457.   int   i, max = 0;             /* loop variable, max. num. of items */
  458.   TRACT *t;                     /* to traverse the transactions */
  459.   assert(taset && marks);       /* check the function arguments */
  460.   taset->total = 0;             /* clear the total number of items */
  461.   for (i = taset->cnt; --i >= 0; ) {
  462.     t = taset->tracts[i];       /* traverse the transactions */
  463.     t->cnt = ta_filter(t->items, t->cnt, marks);
  464.     if (t->cnt > max) max = t->cnt;
  465.     taset->total += t->cnt;     /* filter each transaction and */
  466.   }                             /* update maximal size and total */
  467.   return max;                   /* return maximum number of items */
  468. }  /* tas_filter() */
  469. /*--------------------------------------------------------------------*/
  470. void tas_sort (TASET *taset, int heap)
  471. {                               /* --- sort a transaction set */
  472.   assert(taset);                /* check the function argument */
  473.   if (heap) v_heapsort(taset->tracts, taset->cnt, ta_cmp, NULL);
  474.   else      v_sort    (taset->tracts, taset->cnt, ta_cmp, NULL);
  475. }  /* tas_sort() */
  476. /*--------------------------------------------------------------------*/
  477. int tas_occur (TASET *taset, const int *items, int n)
  478. {                               /* --- count transaction occurrences */
  479.   int l, r, m, k = taset->cnt;  /* index variables */
  480.   assert(taset && items);       /* check the function arguments */
  481.   for (r = m = 0; r < k; ) {    /* find right boundary */
  482.     m = (r + k) >> 1;           /* by a binary search */
  483.     if (ta_cmpx(taset->tracts[m], items, n) > 0) k = m;
  484.     else                                         r = m+1;
  485.   }
  486.   for (l = m = 0; l < k; ) {    /* find left boundary */
  487.     m = (l + k) >> 1;           /* by a binary search */
  488.     if (ta_cmpx(taset->tracts[m], items, n) < 0) l = m+1;
  489.     else                                         k = m;
  490.   }
  491.   return r -l;                  /* compute the number of occurrences */
  492. }  /* tas_occur() */
  493. /*--------------------------------------------------------------------*/
  494. #ifndef NDEBUG
  495. void tas_show (TASET *taset)
  496. {                               /* --- show a transaction set */
  497.   int   i, k;                   /* loop variables */
  498.   TRACT *t;                     /* to traverse the transactions */
  499.   assert(taset);                /* check the function argument */
  500.   for (i = 0; i < taset->cnt; i++) {
  501.     t = taset->tracts[i];       /* traverse the transactions */
  502.     for (k = 0; k < t->cnt; k++) {  /* traverse the items */
  503.       if (k > 0) putc(' ', stdout); /* print a separator */
  504.       printf(is_name(taset->itemset, t->items[k]));
  505.     }                           /* print the next item */
  506.     putc('n', stdout);         /* terminate the transaction */
  507.   }                             /* finally print the number of t.a. */
  508.   printf("%d transaction(s)n", taset->cnt);
  509. }  /* tas_show() */
  510. #endif
  511. /*----------------------------------------------------------------------
  512.   Transaction Tree Functions
  513. ----------------------------------------------------------------------*/
  514. TATREE* _create (TRACT **tracts, int cnt, int index)
  515. {                               /* --- recursive part of tat_create() */
  516.   int    i, k, t;               /* loop variables, buffer */
  517.   int    item, n;               /* item and item counter */
  518.   TATREE *tat;                  /* created transaction tree */
  519.   TATREE **vec;                 /* vector of child pointers */
  520.   assert(tracts                 /* check the function arguments */
  521.      && (cnt >= 0) && (index >= 0));
  522.   if (cnt <= 1) {               /* if only one transaction left */
  523.     n   = (cnt > 0) ? (*tracts)->cnt -index : 0;
  524.     tat = (TATREE*)malloc(sizeof(TATREE) +(n-1) *sizeof(int));
  525.     if (!tat) return NULL;      /* create a transaction tree node */
  526.     tat->cnt  = cnt;            /* and initialize its fields */
  527.     tat->size = -n;
  528.     tat->max  =  n;
  529.     while (--n >= 0) tat->items[n] = (*tracts)->items[index +n];
  530.     return tat;
  531.   }
  532.   for (k = cnt; (--k >= 0) && ((*tracts)->cnt <= index); )
  533.     tracts++;                   /* skip t.a. that are too short */
  534.   n = 0; item = -1;             /* init. item and item counter */
  535.   for (tracts += i = ++k; --i >= 0; ) {
  536.     t = (*--tracts)->items[index]; /* traverse the transactions */
  537.     if (t != item) { item = t; n++; }
  538.   }                             /* count the different items */
  539.   #ifdef ARCH64                 /* adapt to even item number */
  540.   i = (n & 1) ? n : (n+1);      /* so that pointer addresses are */
  541.   #else                         /* multiples of 8 on 64 bit systems */
  542.   i = n;                        /* on 32 bit systems, however, */
  543.   #endif                        /* use the exact number of items */
  544.   tat = (TATREE*)malloc(sizeof(TATREE) + (i-1) *sizeof(int)
  545.                                        + n     *sizeof(TATREE*));
  546.   if (!tat) return NULL;        /* create a transaction tree node */
  547.   tat->cnt  = cnt;              /* and initialize its fields */
  548.   tat->size = n;
  549.   tat->max  = 0;
  550.   if (n <= 0) return tat;       /* if t.a. are fully captured, abort */
  551.   vec  = (TATREE**)(tat->items +i);
  552.   item = tracts[--k]->items[index];
  553.   for (tracts += i = k; --i >= 0; ) {
  554.     t = (*--tracts)->items[index];     /* traverse the transactions, */
  555.     if (t == item) continue;    /* but skip those with the same item */
  556.     tat->items[--n] = item; item = t;
  557.     vec[n] = _create(tracts+1, k-i, index+1);
  558.     if (!vec[n]) break;         /* note the item identifier */
  559.     t = vec[n]->max +1; if (t > tat->max) tat->max = t;
  560.     k = i;                      /* recursively create subtrees */
  561.   }                             /* and adapt the section end index */
  562.   if (i < 0) {                  /* if child creation was successful */
  563.     tat->items[--n] = item;     /* note the last item identifier */
  564.     vec[n] = _create(tracts, k+1, index+1);
  565.     if (vec[n]) {               /* create the last child */
  566.       t = vec[n]->max +1; if (t > tat->max) tat->max = t;
  567.       return tat;               /* return the created */
  568.     }                           /* transaction tree */
  569.   }                             
  570.   for (i = tat->size; --i > n; ) tat_delete(vec[i]);
  571.   free(tat);                    /* on error delete created subtrees */
  572.   return NULL;                  /* and the transaction tree node */
  573. }  /* _create() */
  574. /*--------------------------------------------------------------------*/
  575. TATREE* tat_create (TASET *taset, int heap)
  576. {                               /* --- create a transactions tree */
  577.   assert(taset);                /* check the function argument */
  578.   if (heap) v_heapsort(taset->tracts, taset->cnt, ta_cmp, NULL);
  579.   else      v_sort    (taset->tracts, taset->cnt, ta_cmp, NULL);
  580.   return _create(taset->tracts, taset->cnt, 0);
  581. }  /* tat_create() */
  582. /*--------------------------------------------------------------------*/
  583. void tat_delete (TATREE *tat)
  584. {                               /* --- delete a transaction tree */
  585.   int    i;                     /* loop variable */
  586.   TATREE **vec;                 /* vector of child nodes */
  587.   assert(tat);                  /* check the function argument */
  588.   #ifdef ARCH64                 /* if 64 bit architecture */
  589.   i = (tat->size & 1) ? tat->size : (tat->size+1);
  590.   #else                         /* address must be a multiple of 8 */
  591.   i = tat->size;                /* on 32 bit systems, however, */
  592.   #endif                        /* use the number of items directly */
  593.   vec = (TATREE**)(tat->items +i);
  594.   for (i = tat->size; --i >= 0; )
  595.     tat_delete(vec[i]);         /* recursively delete the subtrees */
  596.   free(tat);                    /* and the tree node itself */
  597. }  /* tat_delete() */
  598. /*--------------------------------------------------------------------*/
  599. #ifdef ARCH64
  600. TATREE* tat_child (TATREE *tat, int index)
  601. {                               /* --- go to a child node */
  602.   int s;                        /* padded size of the node */
  603.   assert(tat                    /* check the function arguments */
  604.      && (index >= 0) && (index < tat->size));
  605.   s = (tat->size & 1) ? tat->size : (tat->size +1);
  606.   return ((TATREE**)(tat->items +s))[index];
  607. }  /* tat_child */              /* return the child node/subtree */
  608. #endif
  609. /*--------------------------------------------------------------------*/
  610. void tat_mark (TATREE *tat)
  611. {                               /* --- mark end of transactions */
  612.   int i;                        /* loop variable */
  613.   assert(tat);                  /* check the function argument */
  614.   if      (tat->size < 0)       /* if there is a transaction, */
  615.     tat->items[tat->max-1] |= INT_MIN;  /* mark end of trans. */
  616.   else {                        /* if there are subtrees */
  617.     for (i = tat->size; --i >= 0; )
  618.       tat_mark(tat_child(tat, i));
  619.   }                             /* recursively mark the subtrees */
  620. }  /* tat_mark() */
  621. /*--------------------------------------------------------------------*/
  622. #ifndef NDEBUG
  623. void _show (TATREE *tat, int ind)
  624. {                               /* --- rekursive part of tat_show() */
  625.   int    i, k;                  /* loop variables */
  626.   TATREE **vec;                 /* vector of child nodes */
  627.   assert(tat && (ind >= 0));    /* check the function arguments */
  628.   if (tat->size <= 0) {         /* if this is a leaf node */
  629.     for (i = 0; i < tat->max; i++)
  630.       printf("%d ", tat->items[i] & ~INT_MIN);
  631.     printf("n"); return;       /* print the items in the */
  632.   }                             /* (rest of) the transaction */
  633.   vec = (TATREE**)(tat->items +tat->size);
  634.   for (i = 0; i < tat->size; i++) {
  635.     if (i > 0) for (k = ind; --k >= 0; ) printf("  ");
  636.     printf("%d ", tat->items[i]);
  637.     _show(vec[i], ind+1);       /* traverse the items, print them, */
  638.   }                             /* and show the children recursively */
  639. }  /* _show() */
  640. /*--------------------------------------------------------------------*/
  641. void tat_show (TATREE *tat)
  642. {                               /* --- show a transaction tree */
  643.   assert(tat);                  /* check the function argument */
  644.   _show(tat, 0);                /* just call the recursive function */
  645. }  /* tat_show() */
  646. #endif