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 }