internal double calculateKwdRank(InverseList list, DocumentOccurrences d, int[] occ)
            {
                int    frequency = occ.Length;
                int    totalNumberOfDocuments = impl.documents.Count;
                int    nRelevantDocuments     = list.Count;
                int    totalNumberOfWords     = impl.inverseIndex.Count;
                double idf          = System.Math.Log((double)totalNumberOfDocuments / nRelevantDocuments);
                double averageWords = (double)totalNumberOfWords / totalNumberOfDocuments;
                double density      = frequency * System.Math.Log(1 + (DENSITY_MAGIC * averageWords / d.nWordsInDocument));
                double wordWeight   = (density * idf);
                double wordScore    = 1;

                for (int i = 0; i < frequency; i++)
                {
                    wordScore += wordWeight * occurrenceKindWeight[(uint)occ[i] >> OCC_KIND_OFFSET];
                }
                return(System.Math.Log(wordScore));
            }
            internal virtual FullTextQuery optimize(FullTextQuery query)
            {
                switch (query.op)
                {
                case FullTextQuery.Operator.And:
                case FullTextQuery.Operator.Near:
                {
                    FullTextQuery.Operator op = query.op;
                    int           nConjuncts  = 1;
                    FullTextQuery q           = query;
                    while ((q = ((FullTextQueryBinaryOp)q).right).op == op)
                    {
                        nConjuncts += 1;
                    }
                    ExpressionWeight[] conjuncts = new ExpressionWeight[nConjuncts + 1];
                    q = query;
                    for (int i = 0; i < nConjuncts; i++)
                    {
                        FullTextQueryBinaryOp and = (FullTextQueryBinaryOp)q;
                        conjuncts[i]        = new ExpressionWeight();
                        conjuncts[i].expr   = optimize(and.left);
                        conjuncts[i].weight = calculateWeight(conjuncts[i].expr);
                        q = and.right;
                    }
                    conjuncts[nConjuncts]        = new ExpressionWeight();
                    conjuncts[nConjuncts].expr   = optimize(q);
                    conjuncts[nConjuncts].weight = calculateWeight(conjuncts[nConjuncts].expr);
                    Array.Sort(conjuncts);
                    if (op == FullTextQuery.Operator.And)
                    {
                        // eliminate duplicates
                        int         n = 0, j = -1;
                        InverseList list = null;
                        for (int i = 0; i <= nConjuncts; i++)
                        {
                            q = conjuncts[i].expr;
                            if (q is FullTextQueryMatchOp)
                            {
                                FullTextQueryMatchOp match = (FullTextQueryMatchOp)q;
                                if (n == 0 || kwds[match.wno].list != list)
                                {
                                    j              = match.wno;
                                    list           = kwds[j].list;
                                    conjuncts[n++] = conjuncts[i];
                                }
                                else
                                {
                                    kwds[match.wno].sameAs = j;
                                }
                            }
                            else
                            {
                                conjuncts[n++] = conjuncts[i];
                            }
                        }
                        nConjuncts = n - 1;
                    }
                    else
                    {
                        // calculate distance between keywords
                        int kwdPos = 0;
                        for (int i = 0; i <= nConjuncts; i++)
                        {
                            q = conjuncts[i].expr;
                            if (q is FullTextQueryMatchOp)
                            {
                                FullTextQueryMatchOp match = (FullTextQueryMatchOp)q;
                                kwds[match.wno].kwdOffset = match.pos - kwdPos;
                                kwdPos = match.pos;
                            }
                        }
                    }
                    if (nConjuncts == 0)
                    {
                        return(conjuncts[0].expr);
                    }
                    else
                    {
                        q = query;
                        int i = 0;
                        while (true)
                        {
                            FullTextQueryBinaryOp and = (FullTextQueryBinaryOp)q;
                            and.left = conjuncts[i].expr;
                            if (++i < nConjuncts)
                            {
                                q = and.right;
                            }
                            else
                            {
                                and.right = conjuncts[i].expr;
                                break;
                            }
                        }
                    }
                    break;
                }

                case FullTextQuery.Operator.Or:
                {
                    FullTextQueryBinaryOp or = (FullTextQueryBinaryOp)query;
                    or.left  = optimize(or.left);
                    or.right = optimize(or.right);
                    break;
                }

                case FullTextQuery.Operator.Not:
                {
                    FullTextQueryUnaryOp not = (FullTextQueryUnaryOp)query;
                    not.opd = optimize(not.opd);
                }
                break;

                default:;
                    break;
                }
                return(query);
            }
 internal InverstListEnumerator(InverseList list, int pos)
 {
     this.list = list;
     this.pos  = pos;
     Reset();
 }