001    /*
002     * Copyright (c) 1998-2014 ChemAxon Ltd. All Rights Reserved.
003     *
004     * This software is the confidential and proprietary information of
005     * ChemAxon. You shall not disclose such Confidential Information
006     * and shall use it only in accordance with the terms of the agreements
007     * you entered into with ChemAxon.
008     *
009     */
010    package com.chemaxon.overlap.bruteforce;
011    
012    import com.chemaxon.overlap.concurrent.ResultHandler;
013    import com.chemaxon.overlap.unguarded.UnguardedDissimilarityCalculator;
014    import com.google.common.base.Function;
015    import com.google.common.collect.ImmutableList;
016    import java.util.List;
017    
018    /**
019     * Self kNN calculator for unguarded paged storage.
020     *
021     * @author Gabor Imre
022     */
023    final class SelfKnn {
024    
025        /**
026         * No constructor exposed for utility classes.
027         */
028        private SelfKnn() {
029        }
030    
031        /**
032         * Calculator function.
033         *
034         * <p>
035         * Function to calculate the knn lists of query structures.</p>
036         *
037         * @param <T> Type of unguarded descriptors
038         *
039         */
040        static class Calc<T> implements Function<ImmutableList<T>, Dissimilarities[]> {
041    
042            /**
043             * List of queries.
044             */
045            private final List<T> queries;
046    
047            /**
048             * Comparator of dissimilarity values.
049             */
050            private final UnguardedDissimilarityCalculator<T> calc;
051    
052            /**
053             * Number of nearest neighbors to store.
054             */
055            private final int k;
056    
057            /**
058             * Construct.
059             *
060             * @param k Number of nearest neighbors to store
061             * @param queries List of queries
062             * @param calc Calculator of dissimilarity
063             */
064            public Calc(final int k, final List<T> queries, final UnguardedDissimilarityCalculator<T> calc) {
065                if (queries.isEmpty()) {
066                    throw new IllegalArgumentException("No query specified");
067                }
068                if (k < 1) {
069                    throw new IllegalArgumentException("Invalid nearest neighbor count " + k);
070                }
071                this.k = k;
072                this.queries = queries;
073                this.calc = calc;
074            }
075    
076            @Override
077            public Dissimilarities[] apply(ImmutableList<T> targets) {
078                if (targets.isEmpty()) {
079                    throw new IllegalArgumentException("No targets specified");
080                }
081    
082                final Dissimilarities[] ret = new Dissimilarities[this.queries.size()];
083    
084                // Run through queries
085                for (int qi = 0; qi < this.queries.size(); qi++) {
086                    // Current query
087                    final T qd = this.queries.get(qi);
088    
089                    // Allocate results
090                    final Dissimilarities dissim = new Dissimilarities(this.k);
091                    ret[qi] = dissim;
092    
093                    // Run through targets
094                    for (int ti = 0; ti < targets.size(); ti++) {
095    
096                        // Target descriptor
097                        final T td = targets.get(ti);
098    
099                        // Calculate dissimilarity
100                        final double d = this.calc.dissimilarity(td, qd);
101    
102                        // Insert result
103                        dissim.insertSorted(d, ti);
104                    }
105    
106                }
107    
108                return ret;
109            }
110        }
111    
112        /**
113         * Report dissimilarity vectors.
114         *
115         * <p>
116         * Note that according to the {@link ResultHandler} API contracts results are expected to be reported in correct
117         * ordering.</p>
118         */
119        static class Report<T> implements ResultHandler<ImmutableList<T>, Dissimilarities[]> {
120    
121            /**
122             * Next target ID.
123             */
124            // private int nextTarget = 0;
125    
126            /**
127             * Final results for each query.
128             */
129            private final Dissimilarities[] res;
130    
131            /**
132             * Construct.
133             *
134             * <p>
135             * Parameters must be consistent with the processing functions {@link SelfKnn.Calc} parametrization.</p>
136             *
137             * @param queryCount Number of represented queries
138             * @param k Number of nearest neighbors to record
139             */
140            Report(int queryCount, int k) {
141                if (queryCount < 1) {
142                    throw new IllegalArgumentException("Invalid query count: " + queryCount);
143                }
144                if (k < 1) {
145                    throw new IllegalArgumentException("Invalid k: " + k);
146                }
147                this.res = new Dissimilarities[queryCount];
148                for (int i = 0; i < queryCount; i++) {
149                    this.res[i] = new Dissimilarities(k);
150                }
151            }
152    
153    
154            @Override
155            public long result(int sourceIndex, ImmutableList<T> s, Dissimilarities[] t) {
156    
157                throw new UnsupportedOperationException();
158    //            if (t.length != this.res.length) {
159    //                throw new IllegalArgumentException("Illegal query count. Expected: " + this.res.length + ", got: "
160    //                        + t.length);
161    //            }
162    //
163    //            // Note that t is indexed as [query][target page]
164    //            final int pagesize = t[0].length;
165    //            for (int qi = 0; qi < t.length; qi++) {
166    //                //for (int ri = 0; ri < pagesize; ri++) {
167    //                //    this.res[qi][this.nextTarget + ri] = t[qi][ri];
168    //                //}
169    //                System.arraycopy(t[qi], 0, this.res[qi], this.nextTarget, pagesize);
170    //            }
171    //            this.nextTarget += pagesize;
172    //            return (long) pagesize * t.length;
173            }
174        }
175    
176    }