package gr.iti.mklab.visual.examples; import gr.iti.mklab.visual.datastructures.AbstractSearchStructure; import gr.iti.mklab.visual.datastructures.IVFPQ; import gr.iti.mklab.visual.datastructures.Linear; import gr.iti.mklab.visual.datastructures.PQ; import gr.iti.mklab.visual.utilities.Normalization; import java.util.Arrays; /** * This class can be used for transforming an existing {@link Linear} index (BDB store) of unit length vectors * into a different type. The following transformations are supported: * * <ol> * <li>Transform into a {@link Linear} index of lower-dimensional unit length vectors by truncating and * re-normalizing.</li> * <li>Transform into a {@link PQ} index using the supplied product quantizer and parameters.</li> * <li>Transform into an {@link IVFPQ} index using the supplied coarse and product quantizers and parameters.</li> * </ol> * * @author Eleftherios Spyromitros-Xioufis * */ public class IndexTransformation { /** * @param args * [0] Full path to the original index. * @param args * [1] Full path to the target index. * @param args * [2] Length of the original index vectors. * @param args * [3] Length of the target index vectors. * @param args * [4] Number of vectors to transform. * @param args * [5] The type of transformation to be applied, one of small/pq/ivfpq. * <p> * The following parameters are used only if pq transformation is selected. * </p> * @param args * [6] Full path to the product quantizer file. * @param args * [7] m parameter (number of subquantizers) of the product quantizer. * @param args * [8] k_s parameter (centroids of each subquantizer) of the product quantizer. * @param args * [9] the type of transformation to perform on the vectors prior to product quantization, one * of no/rr/rp. * <p> * The following parameters are used only if ivfpq transformation is selected. * </p> * @param args * [10] Full path to the coarse quantizer file. * @param args * [11] k_c parameter (number of centroids) of the coarse quantizer. * @throws Exception */ public static void main(String[] args) throws Exception { String initialIndexFolder = args[0]; String targetIndexFolder = args[1]; int initialVectorLength = Integer.parseInt(args[2]); int targetVectorLength = Integer.parseInt(args[3]); int maxNumIndexedVectors = Integer.parseInt(args[4]); String transfomationType = args[5].toLowerCase(); // load existing index Linear fromIndex = new Linear(initialVectorLength, maxNumIndexedVectors, true, initialIndexFolder, false, true, 0); // initialize target index AbstractSearchStructure toIndex = null; if (transfomationType.equals("small")) { // === re-index to a smaller plain index === toIndex = new Linear(targetVectorLength, maxNumIndexedVectors, false, targetIndexFolder, false, true, 0); } else if (transfomationType.equals("pq") || transfomationType.equals("ivfpq")) { String productQuantizerFile = args[6]; int m = Integer.parseInt(args[7]); int k_s = Integer.parseInt(args[8]); String transformationTypeString = args[9]; PQ.TransformationType transformation; if (transformationTypeString.equals("no")) { transformation = PQ.TransformationType.None; } else if (transformationTypeString.equals("rr")) { transformation = PQ.TransformationType.RandomRotation; } else if (transformationTypeString.equals("rp")) { transformation = PQ.TransformationType.RandomPermutation; } else { throw new Exception("Wrong transformation type given!"); } if (transfomationType.equals("pq")) {// pq // === re-index to an PQ index === toIndex = new PQ(targetVectorLength, maxNumIndexedVectors, false, targetIndexFolder, m, k_s, transformation, 512); ((PQ) toIndex).loadProductQuantizer(productQuantizerFile); } else { // ivfpq String coarseQuantizerFile = args[10]; int k_c = Integer.parseInt(args[11]); // === re-index to an IVFPQ index === toIndex = new IVFPQ(targetVectorLength, maxNumIndexedVectors, false, targetIndexFolder, m, k_s, transformation, k_c, 512); ((IVFPQ) toIndex).loadCoarseQuantizer(coarseQuantizerFile); ((IVFPQ) toIndex).loadProductQuantizer(productQuantizerFile); } } else { throw new Exception("Unsupported index transformation type!"); } for (int i = 0; i < maxNumIndexedVectors; i++) { String id = fromIndex.getId(i); double[] vector = fromIndex.getVector(i); // truncate vector to the target length and re-normalize double[] newVector = Arrays.copyOf(vector, targetVectorLength); if (newVector.length < vector.length) { Normalization.normalizeL2(newVector); } toIndex.indexVector(id, newVector); } toIndex.close(); } }