Given a set of terms, doc_terms
        We find the doc in training data (calc_id),
        whose LM is more likely to produce those terms
        Then return the data structure calculated back
        doc_length is passed to pr_ngram() and pr_doc()
            it is up to them to use it or not.
            normally, it should be ignored if doc_length == -1
        calculated{
            prob: calculated probability Pr(calc_id/doc_terms)
            calc_id: Document ID in training data.
            actual_id: Just returned back as passed to us.
            seen_unseen_count: Counts for terms seen/unseen in training data
        }

def calculate(self, doc_terms=[], actual_id='', doc_length=-1):
        '''
        Given a set of terms, doc_terms
        We find the doc in training data (calc_id),
        whose LM is more likely to produce those terms
        Then return the data structure calculated back
        doc_length is passed to pr_ngram() and pr_doc()
            it is up to them to use it or not.
            normally, it should be ignored if doc_length == -1
        calculated{
            prob: calculated probability Pr(calc_id/doc_terms)
            calc_id: Document ID in training data.
            actual_id: Just returned back as passed to us.
            seen_unseen_count: Counts for terms seen/unseen in training data
        }  
        ''' 
        calculated = {
            'prob': -1,
            'calc_id': '',
            'actual_id': actual_id,
            'seen_unseen_count': (0,0),
            'all_probs': []
        }
        terms = self.lr_padding(doc_terms)
        ngrams = self.to_ngrams(terms) 
        for doc_id in self.term_count_n:
            #print '\n', doc_id, ':'
            doc_pr = 0
            new_doc = True
            seen_count = 0
            unseen_count = 0
            for ngram in ngrams:
                (ngram_pr, ngram_seen) = self.pr_ngram(doc_id, ngram, 
                        new_doc=new_doc, log=True, logbase=2, doc_length=doc_length)
                doc_pr += ngram_pr
                new_doc = False
                if ngram_seen:
                    seen_count += 1
                else:
                    unseen_count += 1
            doc_pr += self.pr_doc(doc_id, doc_length=doc_length) 
            if self.verbose:            
                print doc_id, actual_id, doc_pr 
            calculated['all_probs'].append(doc_pr) 
            if calculated['prob'] == -1 or doc_pr < calculated['prob']:
                calculated['prob'] = doc_pr
                calculated['calc_id'] = doc_id
                calculated['seen_unseen_count'] = (seen_count, unseen_count)
        self.unseen_counts.per_doc(doc_id=calculated['actual_id'], 
            seen_unseen=calculated['seen_unseen_count'])
        self.unseen_counts.per_cic(calculated_id=calculated['calc_id'], 
            actual_id=calculated['actual_id'],
            seen_unseen=calculated['seen_unseen_count'])
        return calculated