/*  itemset search input/output common routines
            25/Nov/2007   by Takeaki Uno  e-mail:uno@nii.jp, 
    homepage:   http://research.nii.ac.jp/~uno/index.html  */
/* This program is available for only academic use, basically.
   Anyone can modify this program, but he/she has to write down 
    the change of the modification on the top of the source code.
   Neither contact nor appointment to Takeaki Uno is needed.
   If one wants to re-distribute this code, please
    refer the newest code, and show the link to homepage of 
    Takeaki Uno, to notify the news about the codes for the users. */

/* routines for itemset mining */

#ifndef _itemset_c_
#define _itemset_c_

#include"itemset.h"
#include"queue.c"
#include"aheap.c"

/* flush the write buffer, available for multi-core mode */
void ITEMSET_flush (ITEMSET *I, FILE2 *fp){
  if ( !(I->flag&ITEMSET_MULTI_OUTPUT) || (fp->buf-fp->buf_org) > FILE2_BUFSIZ/2 ){
    SPIN_LOCK(I->multi_core, I->lock_output);
    FILE2_flush (fp);
    SPIN_UNLOCK(I->multi_core, I->lock_output);
  }
}

/* Output information about ITEMSET structure. flag&1: print frequency constraint */
void ITEMSET_print (ITEMSET *I, int flag){
  if ( I->lb>0 || I->ub<INTHUGE ){
    if ( I->lb > 0 ) print_err ("%d <= ", I->lb);
    print_err ("itemsets ");
    if ( I->ub < INTHUGE ) print_err (" <= %d\n", I->ub);
    print_err ("\n");
  }
  if ( flag&1 ){
    if ( I->frq_lb > -WEIGHTHUGE ) print_err (WEIGHTF" <=", I->frq_lb);
    print_err (" frequency ");
    if ( I->frq_ub < WEIGHTHUGE ) print_err (" <="WEIGHTF, I->frq_ub);
    print_err ("\n");
  }
}

/* ITEMSET initialization */
void ITEMSET_init (ITEMSET *I){
  I->flag = 0;
  I->progress = 0;
  I->iters = I->iters2 = I->iters3 = 0;
  I->solutions = I->solutions2 = I->max_solutions = I->outputs = I->outputs2 = 0;
  I->topk.end = 0;
  I->item_max = I->item_max_org = 0;
  I->ub = I->len_ub = I->gap_ub = INTHUGE;
  I->lb = I->len_lb = I->gap_lb = 0;
  I->frq = I->pfrq = I->total_weight = 0;
  I->ratio = I->prob = 0.0;
  I->posi_ub = I->nega_ub = I->frq_ub = WEIGHTHUGE;
  I->posi_lb = I->nega_lb = I->frq_lb = I->setrule_lb = -WEIGHTHUGE;
  I->dir = 0;
  I->target = INTHUGE;
  I->prob_ub = I->ratio_ub = I->rposi_ub = 1;
  I->prob_lb = I->ratio_lb = I->rposi_lb = 0;
  I->itemflag = NULL;
  I->perm = NULL;
  I->item_frq = NULL;
  I->sc = NULL;
  I->X = NULL;
  I->fp = NULL;
  I->separator = ' ';
  I->topk = INIT_AHEAP;
  I->itemset = I->add = INIT_QUEUE;
  I->set_weight = NULL;
  I->set_occ = NULL;

  I->multi_iters = I->multi_iters2 = I->multi_iters3 = NULL;
  I->multi_outputs = I->multi_outputs2 = NULL;
  I->multi_solutions = I->multi_solutions2 = NULL;
  I->multi_fp = NULL;

  I->multi_core = 0;
}


/* second initialization
   topk.end>0 => initialize heap for topk mining */
/* all pointers will be set to 0, but not for */
/* if topK mining, set topk.end to "K" */
void ITEMSET_alloc (ITEMSET *I, char *fname, PERM *perm, QUEUE_INT item_max, size_t item_max_org){
  LONG i;
  size_t siz = (I->flag&ITEMSET_USE_ORG)?item_max_org+2: item_max+2;
  int j;

  I->prob = I->ratio = 1.0;
  I->frq = 0;
  I->perm = perm;
  if ( I->topk.end>0 ){
    AHEAP_alloc (&I->topk, I->topk.end);
    FLOOP (i, 0, I->topk.end) AHEAP_chg (&I->topk, (AHEAP_ID)i, -WEIGHTHUGE);
    I->frq_lb = -WEIGHTHUGE;
  } else I->topk.v = NULL;
  QUEUE_alloc (&I->itemset, (QUEUE_ID)siz); I->itemset.end = (QUEUE_ID)siz;
  if ( I->flag&ITEMSET_ADD ) QUEUE_alloc (&I->add, (QUEUE_ID)siz);
  calloc2 (I->sc, siz+2, goto ERR);
  if ( I->flag&ITEMSET_SET_RULE ){
    calloc2 (I->set_weight, siz, goto ERR);
    if ( I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT) )
        calloc2 (I->set_occ, siz, goto ERR);
  }
  I->iters = I->iters2 = I->solutions = 0;
  I->item_max = item_max;
  I->item_max_org = (QUEUE_INT)item_max_org;
  if ( fname ){
#ifdef _FILE2_LOAD_FROM_MEMORY_
    I->fp = (FILE *)1;
#else 
    if ( strcmp (fname, "-") == 0 ) I->fp = stdout;
    else fopen2 (I->fp, fname, (I->flag&ITEMSET_APPEND)?"a":"w", goto ERR);
#endif
  } else I->fp = 0;
  if ( I->flag&ITEMSET_ITEMFRQ )
    malloc2 (I->item_frq, item_max+2, goto ERR);
  if ( I->flag&ITEMSET_RULE ){
    calloc2 (I->itemflag, item_max+2, goto ERR);
  }
  I->total_weight = 1;
  j = MAX(I->multi_core,1);
  calloc2 (I->multi_iters, j*7, goto ERR);
  I->multi_iters2 = I->multi_iters + j;
  I->multi_iters3 = I->multi_iters2 + j;
  I->multi_outputs = I->multi_iters3 + j;
  I->multi_outputs2 = I->multi_outputs + j;
  I->multi_solutions = I->multi_outputs2 + j;
  I->multi_solutions2 = I->multi_solutions + j;
  
  calloc2 (I->multi_fp, j, goto ERR);
  FLOOP (i, 0, j)
      FILE2_open_ (I->multi_fp[i], I->fp, goto ERR);
#ifdef MULTI_CORE
  if ( I->multi_core > 0 ){
    pthread_spin_init (&I->lock_counter, PTHREAD_PROCESS_PRIVATE);
    pthread_spin_init (&I->lock_sc, PTHREAD_PROCESS_PRIVATE);
    pthread_spin_init (&I->lock_output, PTHREAD_PROCESS_PRIVATE);
  }
#endif
  return;
  ERR:;
  ITEMSET_end (I);
  EXIT;
}

/* sum the counters computed by each thread */
void ITEMSET_merge_counters (ITEMSET *I){
  int i;
  FLOOP (i, 0, MAX(I->multi_core,1)){
    I->iters += I->multi_iters[i];
    I->iters2 += I->multi_iters2[i];
    I->iters3 += I->multi_iters3[i];
    I->outputs += I->multi_outputs[i];
    I->outputs2 += I->multi_outputs2[i];
    I->solutions += I->multi_solutions[i];
    I->solutions2 += I->multi_solutions2[i];
    if ( I->multi_fp[i].buf ) FILE2_flush_last (&I->multi_fp[i]);
  }
  ARY_FILL (I->multi_iters, 0, MAX(I->multi_core,1)*7, 0);
}

/*******************************************************************/
/* termination of ITEMSET */
/*******************************************************************/
void ITEMSET_end (ITEMSET *I){
  int i;
  QUEUE_end (&I->itemset);
  QUEUE_end (&I->add);
  AHEAP_end (&I->topk);
#ifndef _FILE2_LOAD_FROM_MEMORY_
  fclose2 (I->fp);
#endif
  mfree (I->sc, I->item_frq, I->itemflag, I->perm, I->set_weight, I->set_occ);

  if ( I->multi_fp )
      FLOOP (i, 0, MAX(I->multi_core,1)) free2 (I->multi_fp[i].buf_org);
  mfree (I->multi_iters, I->multi_fp);
#ifdef MULTI_CORE
  if ( I->multi_core>0 ){
    pthread_spin_destroy(&I->lock_counter);
    pthread_spin_destroy(&I->lock_sc);
    pthread_spin_destroy(&I->lock_output);
  }
#endif
  ITEMSET_init (I);
}

/*******************************************************************/
/* output at the termination of the algorithm */
/* print #of itemsets of size k, for each k */
/*******************************************************************/
void ITEMSET_last_output (ITEMSET *I){
  QUEUE_ID i;
  LONG n=0, nn=0;

  ITEMSET_merge_counters (I);
  if ( !(I->flag&SHOW_MESSAGE) ) return;  // "no message" is specified
  if ( I->topk.end > 0 ){
    i = AHEAP_findmin_head (&I->topk);
    fprint_WEIGHT (stdout, AHEAP_H (I->topk, i));
    printf ("\n");
    return;
  }
  FLOOP (i, 0, I->itemset.end+1){
    n += I->sc[i];
    if ( I->sc[i] != 0 ) nn = i;
  }
  if ( n!=0 ){
    printf (LONGF "\n", n);
    FLOOP (i, 0, nn+1) printf (LONGF "\n", I->sc[i]);
  }
  print_err ("iters=" LONGF, I->iters);
  if ( I->flag&ITEMSET_ITERS2 ) print_err (", iters2=" LONGF, I->iters2);
  print_err ("\n");
}

/* output frequency, coverage */
void ITEMSET_output_frequency (ITEMSET *I, int core_id){
  FILE2 *fp = &I->multi_fp[core_id];
  if ( I->flag&(ITEMSET_FREQ+ITEMSET_PRE_FREQ) ){
    if ( I->flag&ITEMSET_FREQ ) FILE2_putc (fp, ' ');
    FILE2_print_WEIGHT (fp, I->frq, 4, '(');
    FILE2_putc (fp, ')');
    if ( I->flag&ITEMSET_PRE_FREQ ) FILE2_putc (fp, ' ');
  }
  if ( I->flag&ITEMSET_OUTPUT_POSINEGA ){ // output positive sum, negative sum in the occurrence
    FILE2_putc (fp, ' ');
    FILE2_print_WEIGHT (fp, I->pfrq, 4, '(');
    FILE2_print_WEIGHT (fp, I->pfrq-I->frq, 4, ',');
    FILE2_print_WEIGHT (fp, I->pfrq/(2*I->pfrq-I->frq), 4, ',');
    FILE2_putc (fp, ')');
  }
}

#ifdef _trsact_h_
void ITEMSET_output_occ (ITEMSET *I, QUEUE *occ, int core_id){
  QUEUE_ID i;
  QUEUE_INT *x;
  FILE2 *fp = &I->multi_fp[core_id];
  TRSACT *TT = (TRSACT *)(I->X);
  VEC_ID j, ee = TT->rows_org;
  int flag = I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT);

  i=0; MQUE_FLOOP_ (*occ, x, TT->occ_unit){
    if ( (I->flag&ITEMSET_RM_DUP_TRSACT)==0 || *x != ee ){
      FILE2_print_int (fp, TT->trperm? TT->trperm[*x]: *x, I->separator);
      if (flag == ITEMSET_MULTI_OCC_PRINT ){
        FLOOP (j, 1, (VEC_ID)(TT->occ_unit/sizeof(QUEUE_INT)))
            FILE2_print_int (fp, *(x+j), I->separator);
      } else if ( flag == (ITEMSET_MULTI_OCC_PRINT+ITEMSET_TRSACT_ID) ){
         FILE2_print_int (fp, *(x+1), I->separator);
      }
    }
    ee = *x;
    if ( (++i)%256==0 ) ITEMSET_flush (I, fp);
  }
#ifdef _FILE2_LOAD_FROM_MEMORY_
  *((int *)__write_to_memory__) = INTHUGE;
  __write_to_memory__ = (char *)(((int *)__write_to_memory__) + 1);
#else
  FILE2_putc (fp, '\n');
#endif
}
#endif

/* output an itemset to the output file */
void ITEMSET_output_itemset (ITEMSET *I, QUEUE *occ, int core_id){
  QUEUE_ID i;
  QUEUE_INT e;
#ifdef _agraph_h_
  QUEUE_INT ee;
#endif

  FLOOP (i, 0, I->itemset.t){ // add by NYSOL
    if( I->itemset.v[i]==0) return; // add by NYSOL
  } // add by NYSOL

  FILE2 *fp = &I->multi_fp[core_id];
  
  I->multi_outputs[core_id]++;
  if ( (I->flag&SHOW_PROGRESS ) && (I->multi_outputs[core_id]%(ITEMSET_INTERVAL) == 0) )
      print_err ("---- " LONGF " solutions in " LONGF " candidates\n",
                  I->multi_solutions[core_id], I->multi_outputs[core_id]);
  if ( I->itemset.t < I->lb || I->itemset.t > I->ub ) return;
  if ( (I->flag&ITEMSET_IGNORE_BOUND)==0 && (I->frq < I->frq_lb || I->frq > I->frq_ub) ) return;
  if ( (I->flag&ITEMSET_IGNORE_BOUND)==0 && (I->pfrq < I->posi_lb || I->pfrq > I->posi_ub || (I->frq - I->pfrq) > I->nega_ub || (I->frq - I->pfrq) < I->nega_lb) ) return;

  I->multi_solutions[core_id]++;
  if ( I->max_solutions>0 && I->multi_solutions[core_id] > I->max_solutions ){
    ITEMSET_last_output (I);
    ERROR_MES = "reached to maximum number of solutions";
    EXIT;
  }
  if ( I->topk.v ){
    e = AHEAP_findmin_head (&(I->topk));
    if ( I->frq > AHEAP_H (I->topk, e) ){
      AHEAP_chg (&(I->topk), e, I->frq);
      e = AHEAP_findmin_head (&(I->topk));
      I->frq_lb = AHEAP_H (I->topk, e);
    }
  } else if ( I->fp ){
    if ( I->flag&ITEMSET_PRE_FREQ ) ITEMSET_output_frequency (I, core_id);
    if ( (I->flag & ITEMSET_NOT_ITEMSET) == 0 ){
#ifdef _agraph_h_
      if ( I->flag&ITEMSET_OUTPUT_EDGE ){
        FLOOP (i, 0, I->itemset.t){
          e = I->itemset.v[i];
          ee = AGRAPH_INC_FROM(*((AGRAPH *)(I->X)), e, I->dir);
          FILE2_print_int (fp, I->perm? I->perm[ee]: ee, '(' );
          ee = AGRAPH_INC_TO(*((AGRAPH *)(I->X)), e, I->dir);
          FILE2_print_int (fp, I->perm? I->perm[ee]: ee, I->separator);
#ifdef _FILE2_LOAD_FROM_MEMORY_
          FILE2_putc (fp, ')');
#endif
          if ( i<I->itemset.t-1 ) FILE2_putc (fp, I->separator);
          if ( (i+1)%256==0 ) ITEMSET_flush (I, fp);
        }
        goto NEXT;
      }
#endif
      FLOOP (i, 0, I->itemset.t){
        e = I->itemset.v[i];
        FILE2_print_int (fp,  I->perm? I->perm[e]: e, i==0? 0: I->separator);
        if ( (i+1)%256==0 ) ITEMSET_flush (I, fp);
      }
#ifdef _agraph_h_
      NEXT:;
#endif
    }
    if ( !(I->flag&ITEMSET_PRE_FREQ) ) ITEMSET_output_frequency (I, core_id);
    if ( ((I->flag & ITEMSET_NOT_ITEMSET) == 0) || (I->flag&ITEMSET_FREQ) || (I->flag&ITEMSET_PRE_FREQ) ){
#ifdef _FILE2_LOAD_FROM_MEMORY_
  FILE2_WRITE_MEMORY (QUEUE_INT, FILE2_LOAD_FROM_MEMORY_END);
#else
      FILE2_putc (fp, '\n');
#endif
    }
#ifdef _trsact_h_
    if (I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT)) ITEMSET_output_occ (I, occ, core_id);
#endif
  }
  I->sc[I->itemset.t]++;
  ITEMSET_flush (I, fp);
}

/* output itemsets with adding all combination of "add"
   at the first call, i has to be "add->t" */
void ITEMSET_solution_iter (ITEMSET *I, QUEUE *occ, int core_id){
  QUEUE_ID t=I->add.t;
  if ( I->itemset.t > I->ub ) return;
  ITEMSET_output_itemset (I, occ, core_id);
if ( ERROR_MES ) return;
  BLOOP (I->add.t, I->add.t, 0){
    QUE_INS (I->itemset, I->add.v[I->add.t]);
    ITEMSET_solution_iter (I, occ, core_id);
if ( ERROR_MES ) return;
    I->itemset.t--;
  }
  I->add.t = t;
}

void ITEMSET_solution (ITEMSET *I, QUEUE *occ, int core_id){
  QUEUE_ID i;
  LONG s;
  if ( I->itemset.t > I->ub ) return;
  if ( I->flag & ITEMSET_ALL ){
    if ( I->fp || I->topk.v ) ITEMSET_solution_iter (I, occ, core_id);
    else {
      s=1; FLOOP (i, 0, I->add.t+1){
        I->sc[I->itemset.t+i] += s;
        s = s*(I->add.t-i)/(i+1);
      }
    }
  } else {
    FLOOP (i, 0, I->add.t) QUE_INS (I->itemset, I->add.v[i]);
    ITEMSET_output_itemset (I, occ, core_id);
    I->itemset.t -= I->add.t;
  }
}

/*************************************************************************/
/* ourput a rule */
/*************************************************************************/
void ITEMSET_output_rule (ITEMSET *I, QUEUE *occ, double p1, double p2, size_t item, int core_id){
  FILE2 *fp = &I->multi_fp[core_id];
  if ( fp->fp && !(I->topk.v) ){
    FILE2_print_real (fp, p1, 4, '(');
    FILE2_print_real (fp, p2, 4, ',');
    FILE2_putc (fp, ')');
    FILE2_print_int (fp, I->perm[item], I->separator);
    FILE2_puts (fp, " <= ");
  }
  if ( I->flag & ITEMSET_RULE ){
    if ( I->flag & ITEMSET_RULE_ADD ) ITEMSET_solution (I, occ, core_id);
    else ITEMSET_output_itemset (I, occ, core_id);
  } else ITEMSET_solution (I, occ, core_id);
}
/*************************************************************************/
/* check all rules for a pair of itemset and item */
/*************************************************************************/
void ITEMSET_check_rule (ITEMSET *I, WEIGHT *w, QUEUE *occ, size_t item, int core_id){
  double p = w[item]/I->frq, pp, ff;
//  printf ("[ratio] %f, p=%f, (%f/ %f), %d(%d) <= ", I->ratio_lb, p, w[item], I->frq, I->perm[item], I->itemflag[item]);
  if ( I->itemflag[item]==1 ) return;
  if ( w[item] <= -WEIGHTHUGE ) p = 0;
  pp = p; ff = I->item_frq[item];
  if ( I->flag & ITEMSET_RULE_SUPP ){ pp = w[item]; ff *= I->total_weight; }

  if ( I->flag & (ITEMSET_RULE_FRQ+ITEMSET_RULE_INFRQ)){
    if ( (I->flag & ITEMSET_RULE_FRQ) && p < I->ratio_lb ) return;
    if ( (I->flag & ITEMSET_RULE_INFRQ) && p > I->ratio_ub ) return;
    ITEMSET_output_rule (I, occ, p, ff, item, core_id);
  } else if ( I->flag & (ITEMSET_RULE_RFRQ+ITEMSET_RULE_RINFRQ) ){
    if ( (I->flag & ITEMSET_RULE_RFRQ) && (1-p) > I->ratio_lb * (1-I->item_frq[item]) ) return;
    if ( (I->flag & ITEMSET_RULE_RINFRQ) && p > I->ratio_ub * I->item_frq[item] ) return;
    ITEMSET_output_rule (I, occ, pp, ff, item, core_id);
  }
}

/*************************************************************************/
/* check all rules for an itemset and all items */
/*************************************************************************/
void ITEMSET_check_all_rule (ITEMSET *I, WEIGHT *w, QUEUE *occ, QUEUE *jump, WEIGHT total, int core_id){
  QUEUE_ID i, t;
  QUEUE_INT e, f=0, *x;
  WEIGHT d = I->frq/total;

    // checking out of range for itemset size and (posi/nega) frequency
  if ( I->itemset.t+I->add.t < I->lb || I->itemset.t>I->ub || (!(I->flag&ITEMSET_ALL) && I->itemset.t+I->add.t>I->ub)) return;
  if ( !(I->flag&ITEMSET_IGNORE_BOUND) && (I->frq < I->frq_lb || I->frq > I->frq_ub) ) return;
  if ( !(I->flag&ITEMSET_IGNORE_BOUND) && (I->pfrq < I->posi_lb || I->pfrq > I->posi_ub || (I->frq - I->pfrq) > I->nega_ub || (I->frq - I->pfrq) < I->nega_lb) ) return;

  if ( I->flag&ITEMSET_SET_RULE ){  // itemset->itemset rule for sequence mining
    FLOOP (i, 0, I->itemset.t-1){
      if ( I->frq/I->set_weight[i] >= I->setrule_lb && I->fp ){
        I->sc[i]++;
        if ( I->flag&ITEMSET_PRE_FREQ ) ITEMSET_output_frequency (I, core_id);
        FLOOP (t, 0, I->itemset.t){
          FILE2_print_int (&I->multi_fp[core_id], I->itemset.v[t], t?I->separator:0);
          if ( t == i ){
            FILE2_putc (&I->multi_fp[core_id], ' ');
            FILE2_putc (&I->multi_fp[core_id], '=');
            FILE2_putc (&I->multi_fp[core_id], '>');
          }
        }
        if ( !(I->flag&ITEMSET_PRE_FREQ) ) ITEMSET_output_frequency ( I, core_id);
        FILE2_putc (&I->multi_fp[core_id], ' ');
        FILE2_print_real (&I->multi_fp[core_id], I->frq/I->set_weight[i], 4, '(');
        FILE2_putc (&I->multi_fp[core_id], ')');
#ifdef _FILE2_LOAD_FROM_MEMORY_
  FILE2_WRITE_MEMORY (QUEUE_INT, FILE2_LOAD_FROM_MEMORY_END);
#else
        FILE2_putc (&I->multi_fp[core_id], '\n');
#endif
#ifdef _trsact_h_
        if ( I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT) ){
            ITEMSET_output_occ (I, I->set_occ[i], core_id);
        }
#endif
        ITEMSET_flush (I, &I->multi_fp[core_id]);
      }
    }
  }
    // constraint of relational frequency
  if ( ((I->flag&ITEMSET_RFRQ)==0 || d >= I->prob_lb * I->prob ) 
      && ((I->flag&ITEMSET_RINFRQ)==0 || d <= I->prob * I->prob_ub) ){
    if ( I->flag&ITEMSET_RULE ){  //  rule mining routines
      if ( I->itemset.t == 0 ) return;
      if ( I->target < I->item_max ){
        MQUE_FLOOP (*jump, x){
          if ( *x == I->target ){ 
              ITEMSET_check_rule (I, w, occ, *x, core_id);   if (ERROR_MES) return;
          }
        }
//        ITEMSET_check_rule (I, w, occ, I->target, core_id);    if (ERROR_MES) return;
      } else {
        if ( I->flag & (ITEMSET_RULE_FRQ + ITEMSET_RULE_RFRQ) ){
          if ( I->add.t>0 ){
//            if ( I->itemflag[I->add.v[0]] ) // for POSI_EQUISUPP (occ_w[e] may not be 100%, in the case)
            f = I->add.v[I->add.t-1]; t = I->add.t; I->add.t--;
            FLOOP (i, 0, t){
              e = I->add.v[i];
              I->add.v[i] = f;
              ITEMSET_check_rule (I, w, occ, e, core_id);    if (ERROR_MES) return;
              I->add.v[i] = e;
            }
            I->add.t++;
          }
          MQUE_FLOOP (*jump, x)
              ITEMSET_check_rule (I, w, occ, *x, core_id);   if (ERROR_MES) return;
        } else {
          if ( I->flag & (ITEMSET_RULE_INFRQ + ITEMSET_RULE_RINFRQ) ){
//          ARY_FLOOP ( *jump, i, e ) I->itemflag[e]--;
            FLOOP (i, 0, I->item_max){
              if ( I->itemflag[i] != 1 ){
                ITEMSET_check_rule (I, w, occ, i, core_id);     if (ERROR_MES) return;
              }
            }
//          ARY_FLOOP ( *jump, i, e ) I->itemflag[e]++;
//        } 
//        ARY_FLOOP ( *jump, i, e ) ITEMSET_check_rule (I, w, occ, e);
          }
        }
      }
    } else {  // usual mining (not rule mining)
      if ( I->fp && (I->flag&(ITEMSET_RFRQ+ITEMSET_RINFRQ))){
        FILE2_print_real (&I->multi_fp[core_id], d, 4, '[');
        FILE2_print_real (&I->multi_fp[core_id], I->prob, 4, ',');
        FILE2_putc (&I->multi_fp[core_id], ']');
      }
      ITEMSET_solution (I, occ, core_id);
    }
  }
}

#endif
