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

C/C++

  1. /*----------------------------------------------------------------------
  2.   File    : apriori.c
  3.   Contents: apriori algorithm for finding association rules
  4.   Author  : Christian Borgelt
  5.   History : 14.02.1996 file created
  6.             26.07.1996 output precision reduced
  7.             22.11.1996 options -b, -f, and -r added
  8.             24.11.1996 option -e added (add. evaluation measures)
  9.             18.08.1997 normalized chi^2 measure added
  10.                        option -m (minimal rule length) added
  11.             13.10.1997 quiet version (no output to stdout or stderr)
  12.             27.01.1998 adapted to changed ist_create() function
  13.             08.08.1998 optional input file (item appearances) added
  14.             02.09.1998 several assertions added
  15.             07.09.1998 hyperedge mode (option -h) added
  16.             08.12.1998 output of absolute support (option -a) added
  17.                        float changed to double
  18.             09.12.1998 conversion of names to a scanable form added
  19.             05.02.1999 long int changed to int
  20.             09.02.1999 input from stdin, output to stdout added
  21.             09.08.1999 bug in check of support parameter (<= 0) fixed
  22.             05.11.1999 rule evaluation measure EM_AIMP added
  23.             08.11.1999 output of add. rule eval. measure value added
  24.             16.03.2000 optional use of original rule support definition
  25.             01.04.2001 option -h replaced by option -t (target type)
  26.             26.05.2001 extended support output added (option -x)
  27.             09.06.2001 extended support output for item sets added
  28.             15.08.2001 module scan used for output formatting
  29.             18.11.2001 item and transaction functions made a module
  30.             19.11.2001 options -i, -l changed, option -y removed
  31.             28.12.2001 adapted to module tract, some improvements
  32.             11.01.2002 evaluation measures codes changed to letters
  33.             10.02.2002 option -q extended by a direction parameter
  34.             11.02.2002 memory usage minimization option added
  35.             09.06.2002 arbitrary supp./conf. formats made possible
  36.             09.01.2003 option -k (item separator) added
  37.             14.01.2003 check for empty transaction set added
  38.             12.03.2003 output of lift value (conf/prior) added
  39.             17.07.2003 item filtering w.r.t. usage added (option -u)
  40.             17.07.2003 sorting w.r.t. transaction size sum added
  41.             18.07.2003 maximal itemset filter added
  42.             11.08.2003 closed  itemset filter added
  43.             15.08.2003 item filtering for transaction tree added
  44.             16.08.2003 parameter for transaction filtering added
  45.             18.08.2003 dynamic filtering decision based on times added
  46.             21.08.2003 option -j (heap sort for transactions) added
  47.             22.09.2003 meaning of option -j reversed (heapsort default)
  48.             25.03.2004 option -S added (maximal support of a set/rule)
  49.             09.05.2004 additional selection measure for sets added
  50.             28.10.2004 two unnecessary assignments removed
  51.             20.11.2004 bug in evaluation of -j (heap/quicksort) fixed
  52.             23.11.2004 absolute/relative support output changed
  53.             09.12.2004 semantics of option -p changed
  54.             25.01.2005 bug in output of absolute/relative support fixed
  55.             31.01.2005 another bug in this output fixed
  56.             20.06.2005 use of flag for "no item sorting" corrected
  57. ----------------------------------------------------------------------*/
  58. #include <stdio.h>
  59. #include <stdlib.h>
  60. #include <stdarg.h>
  61. #include <string.h>
  62. #include <math.h>
  63. #include <time.h>
  64. #include <assert.h>
  65. #include "scan.h"
  66. #include "tract.h"
  67. #include "istree.h"
  68. #ifdef STORAGE
  69. #include "storage.h"
  70. #endif
  71. /*----------------------------------------------------------------------
  72.   Preprocessor Definitions
  73. ----------------------------------------------------------------------*/
  74. #define PRGNAME     "apriori"
  75. #define DESCRIPTION "find association rules with the apriori algorithm"
  76. #define VERSION     "version 4.27 (2005.06.20)        " 
  77.                     "(c) 1996-2005   Christian Borgelt"
  78. /* --- target types --- */
  79. #define TT_SET        0         /* frequent item sets */
  80. #define TT_MFSET      1         /* maximally frequent item sets */
  81. #define TT_CLSET      2         /* closed item sets */
  82. #define TT_RULE       3         /* association rules */
  83. #define TT_HEDGE      4         /* association hyperedges */
  84. /* --- error codes --- */
  85. #define E_OPTION    (-5)        /* unknown option */
  86. #define E_OPTARG    (-6)        /* missing option argument */
  87. #define E_ARGCNT    (-7)        /* too few/many arguments */
  88. #define E_STDIN     (-8)        /* double assignment of stdin */
  89. #define E_TARGET    (-9)        /* invalid target type */
  90. #define E_SUPP     (-10)        /* invalid support */
  91. #define E_CONF     (-11)        /* invalid confidence */
  92. #define E_MEASURE  (-12)        /* invalid evaluation measure */
  93. #define E_MVAL     (-13)        /* invalid value for measure */
  94. #define E_RULELEN  (-14)        /* invalid rule length */
  95. #define E_NOTAS    (-15)        /* no items or transactions */
  96. #define E_UNKNOWN  (-21)        /* unknown error */
  97. #ifndef QUIET                   /* if not quiet version */
  98. #ifdef FFLUSH
  99. #define MSG(x)        x         /* print messages */
  100. #else                           /* if to flush every output */
  101. #define MSG(x)        x, fflush(stderr)
  102. #endif
  103. #else                           /* if quiet version */
  104. #define MSG(x)                  /* suppress messages */
  105. #endif
  106. #define SEC_SINCE(t)  ((clock()-(t)) /(double)CLOCKS_PER_SEC)
  107. #define RECCNT(s)     (tfs_reccnt(is_tfscan(s)) 
  108.                       + ((tfs_delim(is_tfscan(s)) == TFS_REC) ? 0 : 1))
  109. #define BUFFER(s)     tfs_buf(is_tfscan(s))
  110. /*----------------------------------------------------------------------
  111.   Constants
  112. ----------------------------------------------------------------------*/
  113. #ifndef QUIET                   /* if not quiet version */
  114. /* --- target types --- */
  115. static const char *ttypes[] = {
  116.   /* TT_SET      0 */  "set",
  117.   /* TT_MFSET    1 */  "set",
  118.   /* TT_CLSET    2 */  "set",
  119.   /* TT_RULE     3 */  "rule",
  120.   /* TT_HEDGE    4 */  "hyperedge",
  121. };
  122. /* --- error messages --- */
  123. static const char *errmsgs[] = {
  124.   /* E_NONE      0 */  "no errorn",
  125.   /* E_NOMEM    -1 */  "not enough memoryn",
  126.   /* E_FOPEN    -2 */  "cannot open file %sn",
  127.   /* E_FREAD    -3 */  "read error on file %sn",
  128.   /* E_FWRITE   -4 */  "write error on file %sn",
  129.   /* E_OPTION   -5 */  "unknown option -%cn",
  130.   /* E_OPTARG   -6 */  "missing option argumentn",
  131.   /* E_ARGCNT   -7 */  "wrong number of argumentsn",
  132.   /* E_STDIN    -8 */  "double assignment of standard inputn",
  133.   /* E_TARGET   -9 */  "invalid target type '%c'n",
  134.   /* E_SUPP    -10 */  "invalid minimal support %g%%n",
  135.   /* E_CONF    -11 */  "invalid minimal confidence %g%%n",
  136.   /* E_MEASURE -12 */  "invalid additional evaluation measure %cn",
  137.   /* E_MVAL    -13 */  "invalid value %g%% for evaluation measuren",
  138.   /* E_RULELEN -14 */  "invalid set size/rule length %dn",
  139.   /* E_NOTAS   -15 */  "no items or transactions to work onn",
  140.   /* E_ITEMEXP -16 */  "file %s, record %d: item expectedn",
  141.   /* E_DUPITEM -17 */  "file %s, record %d: duplicate item %sn",
  142.   /* E_APPEXP  -18 */  "file %s, record %d: "
  143.                          "appearance indicator expectedn",
  144.   /* E_UNKAPP  -19 */  "file %s, record %d: "
  145.                          "unknown appearance indicator %sn",
  146.   /* E_FLDCNT  -20 */  "file %s, record %d: too many fieldsn",
  147.   /* E_UNKNOWN -21 */  "unknown errorn"
  148. };
  149. #endif
  150. /*----------------------------------------------------------------------
  151.   Global Variables
  152. ----------------------------------------------------------------------*/
  153. #ifndef QUIET
  154. static char    *prgname;        /* program name for error messages */
  155. #endif
  156. static ITEMSET *itemset = NULL; /* item set */
  157. static TASET   *taset   = NULL; /* transaction set */
  158. static TATREE  *tatree  = NULL; /* transaction tree */
  159. static ISTREE  *istree  = NULL; /* item set tree */
  160. static FILE    *in      = NULL; /* input  file */
  161. static FILE    *out     = NULL; /* output file */
  162. /*----------------------------------------------------------------------
  163.   Main Functions
  164. ----------------------------------------------------------------------*/
  165. static void help (void)
  166. {                               /* --- print help on eval. measures */
  167.   #ifndef QUIET
  168.   fprintf(stderr, "n");        /* terminate startup message */
  169.   printf("additional evaluation measures (option -e#)n");
  170.   printf("frequent item sets:n");
  171.   printf("d or 1: binary logarithm of support quotientn");
  172.   printf("q or 2: difference of support quotient to 1n");
  173.   printf("association rules:n");
  174.   printf("d or 1: absolute confidence difference to priorn");
  175.   printf("q or 2: absolute difference of confidence quotient to 1n");
  176.   printf("a or 3: absolute difference of improvement value to 1n");
  177.   printf("i or 4: information difference to priorn");
  178.   printf("c or 5: normalized chi^2 measuren");
  179.   #endif
  180.   exit(0);                      /* abort the program */
  181. }  /* help() */
  182. /*--------------------------------------------------------------------*/
  183. static void error (int code, ...)
  184. {                               /* --- print an error message */
  185.   #ifndef QUIET                 /* if not quiet version */
  186.   va_list    args;              /* list of variable arguments */
  187.   const char *msg;              /* error message */
  188.   assert(prgname);              /* check the program name */
  189.   if (code < E_UNKNOWN) code = E_UNKNOWN;
  190.   if (code < 0) {               /* if to report an error, */
  191.     msg = errmsgs[-code];       /* get the error message */
  192.     if (!msg) msg = errmsgs[-E_UNKNOWN];
  193.     fprintf(stderr, "n%s: ", prgname);
  194.     va_start(args, code);       /* get variable arguments */
  195.     vfprintf(stderr, msg, args);/* print error message */
  196.     va_end(args);               /* end argument evaluation */
  197.   }
  198.   #endif
  199.   #ifndef NDEBUG                /* if debug version */
  200.   if (istree)  ist_delete(istree);   /* clean up memory */
  201.   if (tatree)  tat_delete(tatree);   /* and close files */
  202.   if (taset)   tas_delete(taset, 0);
  203.   if (itemset) is_delete(itemset);
  204.   if (in  && (in  != stdin))  fclose(in);
  205.   if (out && (out != stdout)) fclose(out);
  206.   #endif
  207.   #ifdef STORAGE                /* if storage debugging */
  208.   showmem("at end of program"); /* check memory usage */
  209.   #endif
  210.   exit(code);                   /* abort the program */
  211. }  /* error() */
  212. /*--------------------------------------------------------------------*/
  213. int main (int argc, char *argv[])
  214. {                               /* --- main function */
  215.   int    i, k = 0, n;           /* loop variables, counters */
  216.   char   *s;                    /* to traverse the options */
  217.   char   **optarg = NULL;       /* option argument */
  218.   char   *fn_in   = NULL;       /* name of input  file */
  219.   char   *fn_out  = NULL;       /* name of output file */
  220.   char   *fn_app  = NULL;       /* name of item appearances file */
  221.   char   *blanks  = NULL;       /* blanks */
  222.   char   *fldseps = NULL;       /* field  separators */
  223.   char   *recseps = NULL;       /* record separators */
  224.   char   *cominds = NULL;       /* comment indicators */
  225.   char   *apps    = NULL;       /* item appearance indicator vector */
  226.   double supp     = 0.1;        /* minimal support    (in percent) */
  227.   double smax     = 1.0;        /* maximal support    (in percent) */
  228.   double conf     = 0.8;        /* minimal confidence (in percent) */
  229.   int    rsdef    = IST_BODY;   /* rule support definition */
  230.   int    target   = 'r';        /* target type (sets/rules/h.edges) */
  231.   int    arem     = 0;          /* additional rule evaluation measure */
  232.   int    lift     = 0;          /* flag for printing the lift */
  233.   double minval   = 0.1;        /* minimal evaluation measure value */
  234.   double lftval   = 0;          /* lift value (confidence/prior) */
  235.   int    minlen   = 1;          /* minimal rule length */
  236.   int    maxlen   = 5;          /* maximal rule length */
  237.   int    load     = 1;          /* flag for loading transactions */
  238.   int    sort     = 2;          /* flag for item sorting and recoding */
  239.   double filter   = 0.1;        /* item usage filtering parameter */
  240.   int    tree     = 1;          /* flag for transaction tree */
  241.   int    heap     = 1;          /* flag for heap sort vs. quick sort */
  242.   int    memopt   = 0;          /* flag for memory usage optimization */
  243.   int    c2scf    = 0;          /* flag for conv. to scanable form */
  244.   char   *sep     = " ";        /* item separator for output */
  245.   char   *fmt     = "%.1f";     /* output format for support/conf. */
  246.   int    sout     = 1;          /* flag for abs./rel. support output */
  247.   int    ext      = 0;          /* flag for extended support output */
  248.   int    aval     = 0;          /* flag for add. eval. measure value */
  249.   int    maxcnt   = 0;          /* maximal number of items per set */
  250.   int    tacnt;                 /* number of transactions */
  251.   int    *map, *set;            /* identifier map, item set */
  252.   const  char *name;            /* buffer for item names */
  253.   static char buf[4*TFS_SIZE+4];/* buffer for formatting */
  254.   clock_t     t, tt, tc, x;     /* timer for measurements */
  255.   #ifndef QUIET                 /* if not quiet version */
  256.   prgname = argv[0];            /* get program name for error msgs. */
  257.   /* --- print usage message --- */
  258.   if (argc > 1) {               /* if arguments are given */
  259.     fprintf(stderr, "%s - %sn", argv[0], DESCRIPTION);
  260.     fprintf(stderr, VERSION); } /* print a startup message */
  261.   else {                        /* if no arguments given */
  262.     printf("usage: %s [options] infile outfile [appfile]n", argv[0]);
  263.     printf("%sn", DESCRIPTION);
  264.     printf("%sn", VERSION);
  265.     printf("-t#      target type (default: association rules)n"
  266.            "         (s: item sets, c: closed item sets,"
  267.                     " m: maximal item sets,n"
  268.            "          r: association rules,"
  269.                     " h: association hyperedges)n");
  270.     printf("-m#      minimal number of items per set/rule/hyperedge "
  271.                     "(default: %d)n", minlen);
  272.     printf("-n#      maximal number of items per set/rule/hyperedge "
  273.                     "(default: %d)n", maxlen);
  274.     printf("-s#      minimal support    of a     set/rule/hyperedge "
  275.                     "(default: %g%%)n", supp *100);
  276.     printf("-S#      maximal support    of a     set/rule/hyperedge "
  277.                     "(default: %g%%)n", smax *100);
  278.     printf("-c#      minimal confidence of a         rule/hyperedge "
  279.                     "(default: %g%%)n", conf *100);
  280.     printf("-o       use original definition of the support of a rule "
  281.                     "(body & head)n");
  282.     printf("-k#      item separator for output "
  283.                     "(default: "%s")n", sep);
  284.     printf("-p#      output format for support/confidence "
  285.                     "(default: "%s")n", fmt);
  286.     printf("-x       extended support output "
  287.                     "(print both rule support types)n");
  288.     printf("-a       print absolute support "
  289.                     "(number of transactions)n");
  290.     printf("-y       print lift value (confidence divided by prior)n");
  291.     printf("-e#      additional evaluation measure (default: none)n");
  292.     printf("-!       print a list of additional evaluation measuresn");
  293.     printf("-d#      minimal value of additional evaluation measure "
  294.                     "(default: %g%%)n", minval *100);
  295.     printf("-v       print value of additional "
  296.                     "rule evaluation measuren");
  297.     printf("-g       write output in scanable form "
  298.                     "(quote certain characters)n");
  299.     printf("-l       do not load transactions into memory "
  300.                     "(work on input file)n");
  301.     printf("-q#      sort items w.r.t. their frequency (default: %d)n"
  302.            "         (1: ascending, -1: descending, 0: do not sort,n"
  303.            "          2: ascending, -2: descending w.r.t. "
  304.                     "transaction size sum)n", sort);
  305.     printf("-u#      filter unused items from transactions "
  306.                     "(default: %g)n", filter);
  307.     printf("         (0: do not filter items w.r.t. usage in sets,n"
  308.            "         <0: fraction of removed items for filtering,n"
  309.            "         >0: take execution times ratio into account)n");
  310.     printf("-h       do not organize transactions as a prefix treen");
  311.     printf("-j       use quicksort to sort the transactions "
  312.                     "(default: heapsort)n");
  313.     printf("-z       minimize memory usage "
  314.                     "(default: maximize speed)n");
  315.     printf("-i#      ignore records starting with a character "
  316.                     "in the given stringn");
  317.     printf("-b/f/r#  blank characters, field and record separatorsn"
  318.            "         (default: " \t\r", " \t", "\n")n");
  319.     printf("infile   file to read transactions fromn");
  320.     printf("outfile  file to write item sets/association rules"
  321.                     "/hyperedges ton");
  322.     printf("appfile  file stating item appearances (optional)n");
  323.     return 0;                   /* print a usage message */
  324.   }                             /* and abort the program */
  325.   #endif  /* #ifndef QUIET */
  326.   /* --- evaluate arguments --- */
  327.   for (i = 1; i < argc; i++) {  /* traverse arguments */
  328.     s = argv[i];                /* get option argument */
  329.     if (optarg) { *optarg = s; optarg = NULL; continue; }
  330.     if ((*s == '-') && *++s) {  /* -- if argument is an option */
  331.       while (*s) {              /* traverse options */
  332.         switch (*s++) {         /* evaluate switches */
  333.           case '!': help();                         break;
  334.           case 't': target = (*s) ? *s++ : 'r';     break;
  335.           case 'm': minlen = (int)strtol(s, &s, 0); break;
  336.           case 'n': maxlen = (int)strtol(s, &s, 0); break;
  337.           case 's': supp   = 0.01*strtod(s, &s);    break;
  338.           case 'S': smax   = 0.01*strtod(s, &s);    break;
  339.           case 'c': conf   = 0.01*strtod(s, &s);    break;
  340.           case 'o': rsdef  = IST_BOTH;              break;
  341.           case 'k': optarg = &sep;                  break;
  342.           case 'p': optarg = &fmt;                  break;
  343.           case 'x': ext    = 1;                     break;
  344.           case 'a': sout  |= 2;                     break;
  345.           case 'y': lift   = 1;                     break;
  346.           case 'e': arem   = (*s) ? *s++ : 0;       break;
  347.           case 'd': minval = 0.01*strtod(s, &s);    break;
  348.           case 'v': aval   = 1;                     break;
  349.           case 'g': c2scf  = 1;                     break;
  350.           case 'l': load   = 0;                     break;
  351.           case 'q': sort   = (int)strtol(s, &s, 0); break;
  352.           case 'u': filter =      strtod(s, &s);    break;
  353.           case 'h': tree   = 0;                     break;
  354.           case 'j': heap   = 0;                     break;
  355.           case 'z': memopt = 1;                     break;
  356.           case 'i': optarg = &cominds;              break;
  357.           case 'b': optarg = &blanks;               break;
  358.           case 'f': optarg = &fldseps;              break;
  359.           case 'r': optarg = &recseps;              break;
  360.           default : error(E_OPTION, *--s);          break;
  361.         }                       /* set option variables */
  362.         if (optarg && *s) { *optarg = s; optarg = NULL; break; }
  363.       } }                       /* get option argument */
  364.     else {                      /* -- if argument is no option */
  365.       switch (k++) {            /* evaluate non-options */
  366.         case  0: fn_in  = s;      break;
  367.         case  1: fn_out = s;      break;
  368.         case  2: fn_app = s;      break;
  369.         default: error(E_ARGCNT); break;
  370.       }                         /* note filenames */
  371.     }
  372.   }
  373.   if (optarg) error(E_OPTARG);  /* check option argument */
  374.   if ((k < 2) || (k > 3))       /* and the number of arguments */
  375.     error(E_ARGCNT);            /* (either in/out or in/out/app) */
  376.   if ((!fn_in || !*fn_in) && (fn_app && !*fn_app))
  377.     error(E_STDIN);             /* stdin must not be used twice */
  378.   switch (target) {             /* check and translate target type */
  379.     case 's': target = TT_SET;               break;
  380.     case 'm': target = TT_MFSET;             break;
  381.     case 'c': target = TT_CLSET;             break;
  382.     case 'r': target = TT_RULE;              break;
  383.     case 'h': target = TT_HEDGE;             break;
  384.     default : error(E_TARGET, (char)target); break;
  385.   }
  386.   if (supp > 1)                 /* check the minimal support */
  387.     error(E_SUPP, supp);        /* (< 0: absolute number) */
  388.   if ((conf  <  0) || (conf > 1))
  389.     error(E_CONF, conf);        /* check the minimal confidence */
  390.   if (minlen <= 0) error(E_RULELEN, minlen);  /* check the limits */
  391.   if (maxlen <= 0) error(E_RULELEN, maxlen);  /* for the rule length */
  392.   switch (arem) {               /* check and translate measure */
  393.     case  0 : case '0': arem = EM_NONE;     break;
  394.     case 'd': case '1': arem = EM_DIFF;     break;
  395.     case 'q': case '2': arem = EM_QUOT;     break;
  396.     case 'a': case '3': arem = EM_AIMP;     break;
  397.     case 'i': case '4': arem = EM_INFO;     break;
  398.     case 'c': case '5': arem = EM_CHI2;     break;
  399.     default : error(E_MEASURE, (char)arem); break;
  400.   }
  401.   if ((minval < 0)              /* check the measure parameter */
  402.   || ((target == TT_RULE) && (arem != EM_AIMP) && (minval > 1)))
  403.     error(E_MVAL, minval);      /* (must usually be between 0 and 1) */
  404.   if      (target == TT_HEDGE){ /* in hyperedge mode */
  405.     minval = conf;    conf = 1;}/* adapt the parameters */
  406.   else if (target <= TT_CLSET){ /* in item set mode neutralize */
  407.     rsdef = IST_BOTH; conf = 1;}/* rule specific settings */
  408.   if (arem == EM_NONE)          /* if no add. rule eval. measure, */
  409.     aval = 0;                   /* clear the corresp. output flag */
  410.   if ((filter <= -1) || (filter >= 1)) filter = 0;
  411.   /* --- create item set and transaction set --- */
  412.   itemset = is_create();        /* create an item set and */
  413.   if (!itemset) error(E_NOMEM); /* set the special characters */
  414.   is_chars(itemset, blanks, fldseps, recseps, cominds);
  415.   if (load) {                   /* if to load the transactions */
  416.     taset = tas_create(itemset);
  417.     if (!taset) error(E_NOMEM); /* create a transaction set */
  418.   }                             /* to store the transactions */
  419.   MSG(fprintf(stderr, "n"));   /* terminate the startup message */
  420.   /* --- read item appearances --- */
  421.   if (fn_app) {                 /* if item appearances are given */
  422.     t = clock();                /* start the timer */
  423.     if (*fn_app)                /* if an app. file name is given, */
  424.       in = fopen(fn_app, "r");  /* open the item appearances file */
  425.     else {                      /* if no app. file name is given, */
  426.       in = stdin; fn_app = "<stdin>"; }   /* read from std. input */
  427.     MSG(fprintf(stderr, "reading %s ... ", fn_app));
  428.     if (!in) error(E_FOPEN, fn_app);
  429.     k = is_readapp(itemset,in); /* read the item appearances */
  430.     if (k  != 0) error(k, fn_app, RECCNT(itemset), BUFFER(itemset));
  431.     if (in != stdin)            /* if not read from standard input, */
  432.       fclose(in);               /* close the input file */
  433.     MSG(fprintf(stderr, "[%d item(s)] done ", is_cnt(itemset)));
  434.     MSG(fprintf(stderr, "[%.2fs].n", SEC_SINCE(t)));
  435.   }                             /* print a log message */
  436.   /* --- read transactions --- */
  437.   t = clock();                  /* start the timer */
  438.   if (fn_in && *fn_in)          /* if an input file name is given, */
  439.     in = fopen(fn_in, "r");     /* open input file for reading */
  440.   else {                        /* if no input file name is given, */
  441.     in = stdin; fn_in = "<stdin>"; }   /* read from standard input */
  442.   MSG(fprintf(stderr, "reading %s ... ", fn_in));
  443.   if (!in) error(E_FOPEN, fn_in);
  444.   for (tacnt = 0; 1; tacnt++) { /* transaction read loop */
  445.     k = is_read(itemset, in);   /* read the next transaction */
  446.     if (k < 0) error(k, fn_in, RECCNT(itemset), BUFFER(itemset));
  447.     if (k > 0) break;           /* check for error and end of file */
  448.     k = is_tsize(itemset);      /* update the maximal */
  449.     if (k > maxcnt) maxcnt = k; /* transaction size */
  450.     if (taset && (tas_add(taset, NULL, 0) != 0))
  451.       error(E_NOMEM);           /* add the loaded transaction */
  452.   }                             /* to the transaction set */
  453.   if (taset) {                  /* if transactions have been loaded */
  454.     if (in != stdin) fclose(in);/* if not read from standard input, */
  455.     in = NULL;                  /* close the input file */
  456.   }                             /* clear the file variable */
  457.   n = is_cnt(itemset);          /* get the number of items */
  458.   MSG(fprintf(stderr, "[%d item(s),", n));
  459.   MSG(fprintf(stderr, " %d transaction(s)] done ", tacnt));
  460.   MSG(fprintf(stderr, "[%.2fs].", SEC_SINCE(t)));
  461.   if ((n <= 0) || (tacnt <= 0)) error(E_NOTAS);
  462.   MSG(fprintf(stderr, "n"));   /* check for at least one transaction */
  463.   if (supp < 0) {               /* if absolute support is given */
  464.     if (!(sout & 2)) sout = 2;  /* switch to absolute support output */
  465.     supp = (-100 *supp -0.25) /tacnt;
  466.     if (supp < 0) supp = 0;     /* compute a proper relative support */
  467.   }                             /* and check it against 0 */
  468.   if (smax < 0) {               /* if absolute support is given */
  469.     smax = (-100 *smax -0.25) /tacnt;
  470.     if (smax < 0) smax = 0;     /* compute a proper relative support */
  471.   }                             /* and check it against 0 */
  472.   /* --- sort and recode items --- */
  473.   MSG(fprintf(stderr, "sorting and recoding items ... "));
  474.   t   = clock();                /* start the timer */
  475.   map = (int*)malloc(is_cnt(itemset) *sizeof(int));
  476.   if (!map) error(E_NOMEM);     /* create an item identifier map */
  477.   if (rsdef == IST_BODY)        /* if rule support = body support */
  478.     k = (int)ceil(tacnt *supp *conf);
  479.   else                          /* if rule supp. = body&head support */
  480.     k = (int)ceil(tacnt *supp); /* compute the absolut support */
  481.   n = is_recode(itemset, k, sort, map);
  482.   if (taset) {                  /* sort and recode the items and */
  483.     tas_recode(taset, map,n);   /* recode the loaded transactions */
  484.     maxcnt = tas_max(taset);    /* get the new maximal t.a. size */
  485.   }                             /* (may be smaller than before) */
  486.   free(map);                    /* delete the item identifier map */
  487.   MSG(fprintf(stderr, "[%d item(s)] ", n));
  488.   MSG(fprintf(stderr, "done [%.2fs].", SEC_SINCE(t)));
  489.   if (n <= 0) error(E_NOTAS);   /* print a log message and */
  490.   MSG(fprintf(stderr, "n"));   /* check the number of items */
  491.   /* --- create a transaction tree --- */
  492.   tt = 0;                       /* init. the tree construction time */
  493.   if (tree && taset) {          /* if transactions were loaded */
  494.     MSG(fprintf(stderr, "creating transaction tree ... "));
  495.     t = clock();                /* start the timer */
  496.     tatree = tat_create(taset, heap); 
  497.     if (!tatree) error(E_NOMEM);/* create a transaction tree */
  498.     if (filter == 0) {          /* if a tree rebuild is not needed, */
  499.       tas_delete(taset, 0); taset = NULL; }  /* delete transactions */
  500.     tt = clock() -t;            /* note the time for the construction */
  501.     MSG(fprintf(stderr, "done [%.2fs].n", SEC_SINCE(t)));
  502.   }                             /* print a log message */
  503.   /* --- create an item set tree --- */
  504.   t = clock(); tc = 0;          /* start the timer */
  505.   apps = (char*)malloc(n *sizeof(char));
  506.   if (!apps) error(E_NOMEM);    /* get the appearance indicators */
  507.   for (apps += i = n; --i >= 0; )
  508.     *--apps = is_getapp(itemset, i);
  509.   istree = ist_create(n, supp, conf, rsdef, apps, memopt);
  510.   if (!istree) error(E_NOMEM);  /* create an item set tree */
  511.   for (k = n; --k >= 0; )       /* set single item frequencies */
  512.     ist_setcnt(istree, k, is_getfrq(itemset, k));
  513.   ist_settac(istree, tacnt);    /* set the number of transactions */
  514.   if (maxlen > maxcnt)          /* clamp the rule length */
  515.     maxlen = maxcnt;            /* to the maximum set size */
  516.   /* --- check item subsets --- */
  517.   MSG(fprintf(stderr, "checking subsets of size 1"));
  518.   while (ist_height(istree) < maxlen) {
  519.     if (filter != 0) {          /* if to filter w.r.t. item usage, */
  520.       i = ist_check(istree, apps);     /* check current item usage */
  521.       if (i < maxlen) maxlen = i;      /* update the maximum size */
  522.       if (ist_height(istree) >= i) break;
  523.     }                           /* check the tree height */
  524.     k = ist_addlvl(istree);     /* while max. height is not reached, */
  525.     if (k <  0) error(E_NOMEM); /* add a level to the item set tree */
  526.     if (k != 0) break;          /* if no level was added, abort */
  527.     MSG(fprintf(stderr, " %d", ist_height(istree)));
  528.     if (tatree) {               /* if a transaction tree was created */
  529.       if (((filter < 0)         /* if to filter w.r.t. item usage */
  530.       &&   (i < -filter *n))    /* and enough items were removed */
  531.       ||  ((filter > 0)         /* or counting time is long enough */
  532.       &&   (i < n) && (i *(double)tt < filter *n *tc))) {
  533.         n = i; x = clock();     /* note the new number of items */
  534.         tas_filter(taset,apps); /* and remove unnecessary items */
  535.         tat_delete(tatree);     /* delete the transaction tree */
  536.         tatree = tat_create(taset, heap);
  537.         if (!tatree) error(E_NOMEM);
  538.         tt = clock() -x;        /* rebuild the transaction tree and */
  539.       }                         /* note the new construction time */
  540.       x  = clock();             /* count the transaction tree */
  541.       ist_countx(istree, tatree);
  542.       tc = clock() -x; }        /* note the new count time */
  543.     else if (taset) {           /* if transactions were loaded */
  544.       if (((filter < 0)         /* if to filter w.r.t. item usage */
  545.       &&   (i <= -filter *n))   /* and enough items were removed */
  546.       ||  ((filter > 0)         /* or counting time is long enough */
  547.       &&   (i *(double)tt <= filter *n *tc))) {
  548.         n = i; x = clock();     /* note the new number of items */
  549.         tas_filter(taset,apps); /* and remove unnecessary items */
  550.         tt = clock() -t;        /* from the transactions */
  551.       }                         /* note the filtering time */
  552.       for (i = tacnt; --i >= 0;)/* traverse and count transactions */
  553.         ist_count(istree, tas_tract(taset, i), tas_tsize(taset, i));
  554.       tc = clock() -t; }        /* note the new count time */
  555.     else {                      /* if to work on the input file, */
  556.       rewind(in);               /* reset the file position */
  557.       for (maxcnt = 0; (i = is_read(itemset, in)) == 0; ) {
  558.         if (filter != 0)        /* (re)read the transactions and */
  559.           is_filter(itemset, apps);  /* remove unnecessary items */
  560.         k = is_tsize(itemset);  /* update the maximum size */
  561.         if (k > maxcnt) maxcnt = k;  /* of a transaction */
  562.         ist_count(istree, is_tract(itemset), k);
  563.       }                         /* count the transaction in the tree */
  564.       if (i < 0) error(i, fn_in, RECCNT(itemset), BUFFER(itemset));
  565.       if (maxcnt < maxlen)      /* update the maximal rule length */
  566.         maxlen = maxcnt;        /* according to the max. t.a. size */
  567.     }                           /* (may be smaller than before) */
  568.   }
  569.   if (!taset && !tatree) {      /* if transactions were not loaded */
  570.     if (in != stdin) fclose(in);/* if not read from standard input, */
  571.     in = NULL;                  /* close the input file */
  572.   }                             /* clear the file variable */
  573.   MSG(fprintf(stderr, " done [%.2fs].n", SEC_SINCE(t)));
  574.   /* --- filter found item sets --- */
  575.   if ((target == TT_MFSET) || (target == TT_CLSET)) {
  576.     MSG(fprintf(stderr, "filtering %s item sets ... ",
  577.         (target == TT_MFSET) ? "maximal" : "closed"));
  578.     t = clock();                /* filter the item sets */
  579.     ist_filter(istree, (target == TT_MFSET) ? IST_MAXFRQ : IST_CLOSED);
  580.     MSG(fprintf(stderr, "done [%.2fs].n", SEC_SINCE(t)));
  581.   }                             /* (filter takes longer than print) */
  582.   /* --- sort transactions --- */
  583.   if (target <= TT_CLSET) {     /* if to find frequent item sets */
  584.     if (!taset)                 /* transactions must be loaded */
  585.       ext = 0;                  /* for extended support output */
  586.     else if (ext) {             /* if extended output is requested */
  587.       MSG(fprintf(stderr, "sorting transactions ... "));
  588.       t = clock();              /* start the timer */
  589.       tas_sort(taset, heap);    /* sort the transactions */
  590.       MSG(fprintf(stderr, "done [%.2fs].n", SEC_SINCE(t)));
  591.     }                           /* (sorting is necessary to find the */
  592.   }                             /* number of identical transactions) */
  593.   /* --- print item sets/rules/hyperedges --- */
  594.   t = clock();                  /* start the timer */
  595.   if (fn_out && *fn_out)        /* if an output file name is given, */
  596.     out = fopen(fn_out, "w");   /* open the output file */
  597.   else {                        /* if no output file name is given, */
  598.     out = stdout; fn_out = "<stdout>"; }    /* write to std. output */
  599.   MSG(fprintf(stderr, "writing %s ... ", fn_out));
  600.   if (!out) error(E_FOPEN, fn_out);
  601.   ist_init(istree, minlen, arem, minval);
  602.   set = is_tract(itemset);      /* get the transaction buffer */
  603.   if (target <= TT_CLSET) {     /* if to find frequent item sets */
  604.     for (n = 0; 1; ) {          /* extract item sets from the tree */
  605.       k = ist_set(istree, set, &supp, &conf);
  606.       if (k <= 0) break;        /* get the next frequent item set */
  607.       if (supp > smax) continue;/* check against maximal support */
  608.       for (i = 0; i < k; i++) { /* traverse the set's items */
  609.         name = is_name(itemset, set[i]);
  610.         if (c2scf) { sc_format(buf, name, 0); name = buf; }
  611.         fputs(name, out);       /* print the name of the next item */
  612.         fputs((i < k-1) ? sep : " ", out);
  613.       }                         /* print a separator */
  614.       fputs(" (", out);         /* print the item set's support */
  615.       if (sout & 1) { fprintf(out, fmt, supp *100);
  616.                       fputs((sout & 2) ? "%/" : "%", out); }
  617.       if (sout & 2) { fprintf(out, "%d", (int)(supp *tacnt +0.5)); }
  618.       if (ext) {                /* if to print the extended support */
  619.         supp = tas_occur(taset, set, k);
  620.         fputs(", ", out);       /* get the number of occurrences */
  621.         fprintf(out, fmt, (supp/tacnt) *100);
  622.         if (sout & 2) fprintf(out, "/%.0f", supp);
  623.       }                         /* print the extended support data */
  624.       if (aval) { fputs(", ", out); fprintf(out, fmt, conf *100); }
  625.       fputs(")n", out);        /* print the add. eval. measure, */
  626.       n++;                      /* terminate the support output, */
  627.     } }                         /* and count the item set */
  628.   else if (target == TT_RULE) { /* if to find association rules, */
  629.     for (n = 0; 1; ) {          /* extract rules from tree */
  630.       k = ist_rule(istree, set, &supp, &conf, &lftval, &minval);
  631.       if (k <= 0) break;        /* get the next association rule */
  632.       if (supp > smax) continue;/* check against maximal support */
  633.       for (i = 0; i < k; i++) { /* traverse the rule's items */
  634.         name = is_name(itemset, set[i]);
  635.         if (c2scf) { sc_format(buf, name, 0); name = buf; }
  636.         fputs(name, out);       /* print the next item */
  637.         fputs((i <= 0) ? " <- " : ((i < k-1) ? sep : " "), out);
  638.       }                         /* print a separator */
  639.       fputs(" (", out);         /* print the rule evaluation */
  640.       if (ext && (rsdef == IST_BODY)) {
  641.         if (sout & 1) { fprintf(out, fmt, supp *conf *100);
  642.                         if (sout & 2) fputc('/', out); }
  643.         if (sout & 2) { fprintf(out, "%d", (int)(supp*conf*tacnt+0.5));}
  644.         fputs(", ", out);       /* print the support of the rule */
  645.       }                         /* from  the support of the body */
  646.       if (sout & 1) { fprintf(out, fmt, supp *100);
  647.                       if (sout & 2) fputc('/', out); }
  648.       if (sout & 2) { fprintf(out, "%d", (int)(supp *tacnt +0.5)); }
  649.       fputs(", ", out);         /* print the rule support */
  650.       if (ext && (rsdef == IST_BOTH)) {
  651.         if (sout & 1) { fprintf(out, fmt, (supp/conf) *100);
  652.                         if (sout & 2) fputc('/', out); }
  653.         if (sout & 2) { fprintf(out,"%d",(int)((supp/conf)*tacnt+0.5));}
  654.         fputs(", ", out);       /* print the support of the body */
  655.       }                         /* from  the support of the rule */
  656.       fprintf(out, fmt, conf *100); /* print the rule confidence */
  657.       if (lift) { fputs(", ", out); fprintf(out, fmt, lftval *100); }
  658.       if (aval) { fputs(", ", out); fprintf(out, fmt, minval *100); }
  659.       fputs(")n", out);        /* print the value of the additional */
  660.       n++;                      /* rule evaluation measure and */
  661.     } }                         /* count the association rule */
  662.   else {                        /* if to find association hyperedges */
  663.     for (n = 0; 1; ) {          /* extract hyperedges from tree */
  664.       k = ist_hedge(istree, set, &supp, &conf);
  665.       if (k <= 0) break;        /* get the next hyperedge */
  666.       if (supp > smax) continue;/* check against maximal support */
  667.       for (i = 0; i < k; i++) { /* traverse the edge's items */
  668.         name = is_name(itemset, set[i]);
  669.         if (c2scf) { sc_format(buf, name, 0); name = buf; }
  670.         fputs(name, out);       /* print the name of the next item */
  671.         fputs((i < k-1) ? sep : " ", out);
  672.       }                         /* print a separator */
  673.       fputs(" (", out);
  674.       if (sout & 1) { fprintf(out, fmt, supp *100);
  675.                       if (sout & 2) fputc('/', out); }
  676.       if (sout & 2) { fprintf(out, "%d", (int)(supp *tacnt +0.5)); }
  677.       fputs(", ", out); fprintf(out, fmt, conf *100);
  678.       fputs(")n", out);        /* print support and confidence */
  679.       n++;                      /* of the hyperedge and */
  680.     }                           /* count the hyperedge */
  681.   }  /* if (target <= TT_MFSET) .. else .. */
  682.   if (fflush(out) != 0) error(E_FWRITE, fn_out);
  683.   if (out != stdout) fclose(out);
  684.   out = NULL;                   /* close the output file */
  685.   MSG(fprintf(stderr, "[%d %s(s)] done ", n, ttypes[target]));
  686.   MSG(fprintf(stderr, "[%.2fs].n", SEC_SINCE(t)));
  687.   #ifdef BENCH
  688.   printf("number of counters      : %dn", istree->cnt);
  689.   printf("necessary counters      : %dn", istree->nec);
  690.   printf("number of child pointers: %dn", istree->chcnt);
  691.   printf("necessary child pointers: %dn", istree->chnec);
  692.   printf("allocated bytes         : %dn", istree->bytes);
  693.   #endif
  694.   /* --- clean up --- */
  695.   #ifndef NDEBUG                /* if this is a debug version */
  696.   free(apps);                   /* delete the item app. vector */
  697.   ist_delete(istree);           /* delete the item set tree, */
  698.   if (tatree) tat_delete(tatree);     /* the transaction tree, */
  699.   if (taset)  tas_delete(taset, 0);   /* the transaction set, */
  700.   is_delete(itemset);                 /* and the item set */
  701.   #endif
  702.   #ifdef STORAGE                /* if storage debugging */
  703.   showmem("at end of program"); /* check memory usage */
  704.   #endif
  705.   return 0;                     /* return 'ok' */
  706. }  /* main() */