001: package it.unimi.dsi.mg4j.search.score;
002:
003: /*
004: * MG4J: Managing Gigabytes for Java
005: *
006: * Copyright (C) 2004-2007 Paolo Boldi and Sebastiano Vigna
007: *
008: * This library is free software; you can redistribute it and/or modify it
009: * under the terms of the GNU Lesser General Public License as published by the Free
010: * Software Foundation; either version 2.1 of the License, or (at your option)
011: * any later version.
012: *
013: * This library is distributed in the hope that it will be useful, but
014: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
015: * or FITfNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
016: * for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: *
022: */
023:
024: import it.unimi.dsi.fastutil.doubles.DoubleArrays;
025: import it.unimi.dsi.fastutil.objects.Reference2DoubleMap;
026: import it.unimi.dsi.Util;
027: import it.unimi.dsi.lang.FlyweightPrototypes;
028:
029: import java.util.Arrays;
030:
031: import org.apache.log4j.Logger;
032:
033: /** An aggregator that computes a linear combination of the component scorers.
034: *
035: * <p>This class requires, beside the usually array of scorers, a parallel array
036: * of weights (not to be confused with
037: * {@link it.unimi.dsi.mg4j.search.score.Scorer#setWeights(Reference2DoubleMap) index weights}).
038: * The score from each scorer will be multiplied by the respective weight, and the
039: * overal score will be the sum of these values. Equalisation, if necessary, if performed
040: * by maximising over the sample scores and dividing all scores by the resulting value.
041: */
042: public class LinearAggregator extends AbstractAggregator {
043: private final static boolean DEBUG = false;
044: private final static Logger LOGGER = Util
045: .getLogger(LinearAggregator.class);
046:
047: /** The weights of each scorer. */
048: protected final double[] weight;
049: /** The equalisation factors for each scorer (all set to one if no equalisation is required). */
050: protected final double[] equalisationFactor;
051:
052: /** Creates a linear aggregator.
053: *
054: * @param scorer the array of scorers.
055: * @param weight the array of weights.
056: */
057: public LinearAggregator(final Scorer[] scorer, final double[] weight) {
058: super (scorer);
059: if (scorer.length != weight.length)
060: throw new IllegalArgumentException();
061: this .weight = weight.clone();
062: this .equalisationFactor = new double[n];
063: }
064:
065: public synchronized LinearAggregator copy() {
066: final LinearAggregator linearCombinationScorer = new LinearAggregator(
067: FlyweightPrototypes.copy(scorer), weight.clone());
068: linearCombinationScorer.equalize(samples);
069: return linearCombinationScorer;
070: }
071:
072: protected double score(final double score[]) {
073: double total = 0;
074: for (int i = n; i-- != 0;)
075: total += weight[i] * score[i] / equalisationFactor[i];
076: if (DEBUG)
077: LOGGER.debug("Scoring " + Arrays.toString(score) + ": "
078: + total + " (weight: " + Arrays.toString(weight)
079: + "; equalisation factors: "
080: + Arrays.toString(equalisationFactor) + ")");
081: return total;
082: }
083:
084: protected void setupEqualizationFactors() {
085: if (samples == 0)
086: DoubleArrays.fill(equalisationFactor, 1);
087: else {
088: final double sampleScore[][] = this .sampleScore;
089: for (int i = n; i-- != 0;) {
090: double m = 0;
091: for (int j = actualSamples; j-- != 0;)
092: if (m < sampleScore[j][i])
093: m = sampleScore[j][i];
094: equalisationFactor[i] = m == 0 ? 1 : m;
095: }
096: }
097:
098: LOGGER.debug("Equalisation factors: "
099: + Arrays.toString(equalisationFactor));
100: }
101:
102: public String toString() {
103: final StringBuilder s = new StringBuilder();
104: s.append(this .getClass().getName()).append('(');
105: for (int i = 0; i < scorer.length; i++) {
106: if (i != 0)
107: s.append("; ");
108: s.append(scorer[i].toString()).append(":")
109: .append(weight[i]);
110: }
111:
112: return s.append(')').toString();
113: }
114:
115: }
|