001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 *  image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause 
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 
006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 
007 * Visit http://imagingbook.com for additional details.
008 *******************************************************************************/
009
010package imagingbook.lib.math;
011
012public abstract class VectorNorm {
013
014        public abstract double magnitude(double[] x);
015        public abstract double magnitude(int[] x);
016
017        /**
018         * Calculates the distance between two vectors.
019         * 
020         * @param a first vector
021         * @param b second vector
022         * @return the distance between vectors a and b
023         */
024        public abstract double distance(double[] a, double[] b);
025        public abstract double distance(float[] a, float[] b);
026        public abstract double distance(int[] a, int[] b);
027
028        /**
029         * 
030         * @param a first vector
031         * @param b second vector
032         * @return the squared distance between vectors a and b
033         */
034        public abstract double distance2(double[] a, double[] b);
035        public abstract double distance2(float[] a, float[] b);
036        public abstract double distance2(int[] a, int[] b);
037
038
039        /**
040         * Returns a factor to scale magnitude and distance values 
041         * to the range of the vector components of dimensionality
042         * n. This is prim. used for scaling color distances (n = 3).
043         * E.g., if components are distributed in [0,255], the distances
044         * multiplied by this factor should again be in [0,255].
045         * 
046         * @param n dimensionality
047         * @return scale factor
048         */
049        public abstract double getScale(int n);
050
051        private interface Creator {
052                public VectorNorm create();
053        }
054
055        public enum NormType implements Creator {
056                L1       {public VectorNorm create() {return new VectorNorm.L1();}},
057                L2       {public VectorNorm create() {return new VectorNorm.L2();}}, 
058                Linf {public VectorNorm create() {return new VectorNorm.Linf();}
059                };
060        }
061
062        static String wrongLengthMessage = "feature vectors must be of same length";
063
064        // ------------------------------------------------------------------------------
065
066        public static class L1 extends VectorNorm {
067
068                public double magnitude(double[] X) {
069                        double sum = 0.0;
070                        for (int i = 0; i < X.length; i++) {
071                                sum = sum + Math.abs(X[i]);
072                        }
073                        return sum;
074                }
075
076                public double magnitude(int[] X) {
077                        long sum = 0;
078                        for (int i = 0; i < X.length; i++) {
079                                sum = sum + Math.abs(X[i]);
080                        }
081                        return (double) sum;
082                }
083
084                public double distance(final double[] X, final double[] Y) {
085                        if (X.length != Y.length) {
086                                throw new IllegalArgumentException(wrongLengthMessage);
087                        }
088                        double sum = 0.0;
089                        for (int i = 0; i < X.length; i++) {
090                                double d = X[i] - Y[i];
091                                sum = sum + Math.abs(d);
092                        }
093                        return sum;
094                }
095
096                public double distance(final int[] X, final int[] Y) {
097                        if (X.length != Y.length) {
098                                throw new IllegalArgumentException(wrongLengthMessage);
099                        }
100                        int sum = 0;
101                        for (int i = 0; i < X.length; i++) {
102                                sum = sum + Math.abs(X[i] - Y[i]);
103                        }
104                        return sum;
105                }
106
107                public double distance2(double[] a, double[] b) {
108                        double d = distance(a, b);
109                        return d * d;
110                }
111
112                public double distance2(int[] a, int[] b) {
113                        double d = distance(a, b);
114                        return d * d;
115                }
116
117                public double getScale(int n) {
118                        return 1.0 / n;
119                }
120
121                @Override
122                public double distance2(float[] a, float[] b) {
123                        double d = distance(a, b);
124                        return d * d;
125                }
126
127                @Override
128                public double distance(float[] X, float[] Y) {
129                        if (X.length != Y.length) {
130                                throw new IllegalArgumentException(wrongLengthMessage);
131                        }
132                        double sum = 0;
133                        for (int i = 0; i < X.length; i++) {
134                                sum = sum + Math.abs(X[i] - Y[i]);
135                        }
136                        return sum;
137                }
138        }
139
140        // ------------------------------------------------------------------------------
141
142        public static class L2 extends VectorNorm {
143
144                public double magnitude(double[] X) {
145                        double sum = 0.0;
146                        for (int i = 0; i < X.length; i++) {
147                                sum = sum + X[i] * X[i];
148                        }
149                        return Math.sqrt(sum);
150                }
151
152                public double magnitude(int[] X) {
153                        long sum = 0;
154                        for (int i = 0; i < X.length; i++) {
155                                sum = sum + X[i] * X[i];
156                        }
157                        return Math.sqrt(sum);
158                }
159
160                public double distance(double[] a, double[] b) {
161                        return Math.sqrt(distance2(a, b));
162                }
163
164                public double distance2(final double[] X, final double[] Y) {
165                        if (X.length != Y.length) {
166                                throw new IllegalArgumentException(wrongLengthMessage);
167                        }
168                        double sum = 0.0;
169                        for (int i = 0; i < X.length; i++) {
170                                double d = X[i] - Y[i];
171                                sum = sum + d * d;
172                        }
173                        return sum;
174                }
175
176                public double distance(int[] a, int[] b) {
177                        return Math.sqrt(distance2(a, b));
178                }
179
180                public double distance2(final int[] X, final int[] Y) {
181                        if (X.length != Y.length) {
182                                throw new IllegalArgumentException(wrongLengthMessage);
183                        }
184                        int sum = 0;
185                        for (int i = 0; i < X.length; i++) {
186                                int d = X[i] - Y[i];
187                                sum = sum + d * d;
188                        }
189                        return sum;
190                }
191
192                public double getScale(int n) {
193                        return Math.sqrt(1.0 / n);
194                }
195
196                @Override
197                public double distance(float[] a, float[] b) {
198                        return Math.sqrt(distance2(a, b));
199                }
200                
201                @Override
202                public double distance2(float[] X, float[] Y) {
203                        if (X.length != Y.length) {
204                                throw new IllegalArgumentException(wrongLengthMessage);
205                        }
206                        double sum = 0.0;
207                        for (int i = 0; i < X.length; i++) {
208                                double d = X[i] - Y[i];
209                                sum = sum + d * d;
210                        }
211                        return sum;
212                }
213        }
214
215        // ------------------------------------------------------------------------------
216
217        public static class Linf extends VectorNorm {
218
219                public double magnitude(double[] X) {
220                        double dmax = 0.0;
221                        for (int i = 0; i < X.length; i++) {
222                                dmax = Math.max(dmax, Math.abs(X[i]));
223                        }
224                        return dmax;
225                }
226
227                public double magnitude(int[] X) {
228                        int dmax = 0;
229                        for (int i = 0; i < X.length; i++) {
230                                dmax = Math.max(dmax, Math.abs(X[i]));
231                        }
232                        return dmax;
233                }
234
235                public double distance(final double[] X, final double[] Y) {
236                        if (X.length != Y.length) {
237                                throw new IllegalArgumentException(wrongLengthMessage);
238                        }
239                        double dmax = 0.0;
240                        for (int i = 0; i < X.length; i++) {
241                                double d = X[i] - Y[i];
242                                dmax = Math.max(dmax, Math.abs(d));
243                        }
244                        return dmax;
245                }
246
247                public double distance(final int[] X, final int[] Y) {
248                        if (X.length != Y.length) {
249                                throw new IllegalArgumentException(wrongLengthMessage);
250                        }
251                        int dmax = 0;
252                        for (int i = 0; i < X.length; i++) {
253                                int d = Math.abs(X[i] - Y[i]);
254                                dmax = Math.max(dmax, d);
255                        }
256                        return dmax;
257                }
258
259                public double distance2(double[] a, double[] b) {
260                        double d = distance(a, b);
261                        return d * d;
262                }
263
264                public double distance2(int[] a, int[] b) {
265                        double d = distance(a, b);
266                        return d * d;
267                }
268
269                public double getScale(int n) {
270                        return 1.0;
271                }
272
273                @Override
274                public double distance2(float[] a, float[] b) {
275                        double d = distance(a, b);
276                        return d * d;
277                }
278
279                @Override
280                public double distance(float[] X, float[] Y) {
281                        if (X.length != Y.length) {
282                                throw new IllegalArgumentException(wrongLengthMessage);
283                        }
284                        float dmax = 0;
285                        for (int i = 0; i < X.length; i++) {
286                                float d = Math.abs(X[i] - Y[i]);
287                                dmax = Math.max(dmax, d);
288                        }
289                        return dmax;
290                }
291        }
292
293}
294