1 /* 2 * Copyright (C) 2016 Alberto Irurueta Carro (alberto@irurueta.com) 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.irurueta.numerical.robust; 17 18 import com.irurueta.sorting.Sorter; 19 import com.irurueta.sorting.SortingException; 20 21 import java.util.Arrays; 22 23 /** 24 * Class containing the selection that was made on a weighted algorithm. 25 * This is used internally by weighted estimators. 26 */ 27 public class WeightSelection { 28 29 /** 30 * Array indicating which correspondences have been selected (i.e. have 31 * a true value), and which ones hasn't (have a false value). 32 */ 33 private boolean[] selected; 34 35 /** 36 * Number of correspondences that have been selected. 37 */ 38 private int numSelected; 39 40 /** 41 * Constructor. 42 */ 43 private WeightSelection() { 44 } 45 46 /** 47 * Returns array indicating which correspondences have been selected 48 * (i.e. have a true value), and which ones hasn't (have a false value). 49 * 50 * @return array indicating which correspondences have been selected. 51 */ 52 public boolean[] getSelected() { 53 return selected; 54 } 55 56 /** 57 * Sets array indicating which correspondences have been selected (i.e. 58 * have a true value), and which ones hasn't (have a false value). 59 * 60 * @param selected array indicating which correspondences have been 61 * selected. 62 */ 63 public void setSelected(final boolean[] selected) { 64 this.selected = selected; 65 } 66 67 /** 68 * Returns number of correspondences that have been selected. 69 * 70 * @return number of correspondences that have been selected. 71 */ 72 public int getNumSelected() { 73 return numSelected; 74 } 75 76 /** 77 * Sets number of correspondences that have been selected. 78 * 79 * @param numSelected number of correspondences that have been selected. 80 */ 81 public void setNumSelected(final int numSelected) { 82 this.numSelected = numSelected; 83 } 84 85 /** 86 * Selects correspondences based on provided weights and creates a 87 * weight selection instance. 88 * 89 * @param weights weights. The larger its value the more important a 90 * correspondence is. 91 * @param sortWeights indicates whether weights must be sorted so that 92 * largest weights are taken into account first. 93 * @param maxPoints maximum number of correspondences to pick 94 * @return instance containing the selection that was made. 95 * @throws SortingException if weights couldn't be sorted. 96 */ 97 public static WeightSelection selectWeights(final double[] weights, final boolean sortWeights, final int maxPoints) 98 throws SortingException { 99 100 final var length = weights.length; 101 102 // instantiate selected array with all its values as unselected 103 var selected = new boolean[length]; 104 int numSelected; 105 106 if (sortWeights) { 107 // sort weights 108 109 // copy weights because this array will be sorted 110 final var weightsCopy = Arrays.copyOf(weights, length); 111 final var sorter = Sorter.<Double>create(); 112 // array that will contain original indices in ascending order of 113 // weights after sorting 114 final var indices = sorter.sortWithIndices(weightsCopy); 115 116 // traverse indices array from the greatest position which corresponds 117 // to the greatest weight value after sorting in decreasing order 118 // up to maxPoints positions 119 var counter = 0; 120 for (var i = length - 1; i >= 0; i--) { 121 selected[indices[i]] = true; 122 counter++; 123 if (counter >= maxPoints) { 124 break; 125 } 126 } 127 numSelected = counter; 128 } else { 129 // weights aren't sorted 130 if (length < maxPoints) { 131 // we select all points 132 Arrays.fill(selected, true); 133 numSelected = length; 134 } else { 135 // weights aren't sorted so we pick the first maxPoints 136 for (var i = 0; i < maxPoints; i++) { 137 selected[i] = true; 138 } 139 numSelected = maxPoints; 140 } 141 } 142 143 final var selection = new WeightSelection(); 144 selection.setSelected(selected); 145 selection.setNumSelected(numSelected); 146 return selection; 147 } 148 }