#include "LCDisjunctionSumScorer.h" #include "LCPriorityQueue.h" #include "GNUstep.h" @interface LCScorerQueue: LCPriorityQueue @end @interface LCDisjunctionSumScorer (LCPrivate) - (void) initScorerQueue; @end @implementation LCDisjunctionSumScorer - (id) init { self = [super init]; scorerQueue = nil; currentDoc = -1; nrMatchers = -1; currentScore = -1; return self; } - (id) initWithSubScorers: (NSArray *) s minimumNrMatchers: (int) m { self = [self initWithSimilarity: nil]; nrScorers = [s count]; if (m <= 0) { NSLog(@"Minimum nr of matchers must be positive"); return nil; } if (nrScorers <= 1) { NSLog(@"There must be at least 2 subScorers"); return nil; } minimumNrMatchers = m; ASSIGN(subScorers, s); return self; } - (id) initWithSubScorers: (NSArray *) sub { return [self initWithSubScorers: sub minimumNrMatchers: 1]; } - (void) initScorerQueue { NSEnumerator *si = [subScorers objectEnumerator]; scorerQueue = [(LCScorerQueue *)[LCScorerQueue alloc] initWithSize: nrScorers]; LCScorer *se; while ((se = [si nextObject])) { if ([se next]) { // doc() method will be used in scorerQueue [scorerQueue insert: se]; } } } - (void) dealloc { DESTROY(subScorers); [super dealloc]; } - (BOOL) next { if (scorerQueue == nil) { [self initScorerQueue]; } if ([scorerQueue size] < minimumNrMatchers) { return NO; } else { return [self advanceAfterCurrent]; } } - (BOOL) advanceAfterCurrent { do { // repeat until minimum nr of matchers LCScorer *top = [scorerQueue top]; currentDoc = [top document]; currentScore = [top score]; nrMatchers = 1; do { // Until all subscorers are after currentDoc if ([top next]) { [scorerQueue adjustTop]; } else { [scorerQueue pop]; if ([scorerQueue size] < (minimumNrMatchers - nrMatchers)) { // Nor enough subscorers left for a match on this document, // and also no more chance of any further match. return NO; } if ([scorerQueue size] == 0) { break; // nothing more to advance, check for last match. } } top = [scorerQueue top]; if ([top document] != currentDoc) { break; // All remaining subscorers are after currentDoc. } else { currentScore += [top score]; nrMatchers++; } } while (1); if (nrMatchers >= minimumNrMatchers) { return YES; } else if ([scorerQueue size] < minimumNrMatchers) { return NO; } } while (1); } - (float) score { return currentScore; } - (int) document { return currentDoc; } - (int) nrMatchers { return nrMatchers; } - (BOOL) skipTo: (int) target { if (scorerQueue == nil) { [self initScorerQueue]; } if ([scorerQueue size] < minimumNrMatchers) { return NO; } if (target <= currentDoc) { //target = currentDoc + 1; return YES; } do { LCScorer *top = [scorerQueue top]; if ([top document] >= target) { return [self advanceAfterCurrent]; } else if ([top skipTo: target]) { [scorerQueue adjustTop]; } else { [scorerQueue pop]; if ([scorerQueue size] < minimumNrMatchers) { return NO; } } } while (1); } - (LCExplanation *) explain: (int) doc { LCExplanation *res = [[LCExplanation alloc] init]; [res setRepresentation: [NSString stringWithFormat: @"At least %d of", minimumNrMatchers]]; NSEnumerator *ssi = [subScorers objectEnumerator]; LCScorer *sr; while ((sr = [ssi nextObject])) { [res addDetail: [sr explain: doc]]; } return AUTORELEASE(res); } @end @implementation LCScorerQueue - (BOOL) lessThan: (id) o1 : (id) o2 { if ([(LCScorer *)o1 document] < [(LCScorer *)o2 document]) return YES; else return NO; } @end