View Javadoc
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 }