• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

numenta / htm.java / #1205

26 Jan 2015 12:57PM UTC coverage: 14.409% (+0.005%) from 14.404%
#1205

push

David Ray
Merge pull request #168 from cogmission/network_api_work

testing the RNG is not part of the scope

718 of 4983 relevant lines covered (14.41%)

0.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.27
/src/main/java/org/numenta/nupic/encoders/LogEncoder.java
1
/* ---------------------------------------------------------------------
2
 * Numenta Platform for Intelligent Computing (NuPIC)
3
 * Copyright (C) 2014, Numenta, In  Unless you have an agreement
4
 * with Numenta, In, for a separate license for this software code, the
5
 * following terms and conditions apply:
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License version 3 as
9
 * published by the Free Software Foundation.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 * See the GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see http://www.gnu.org/licenses.
18
 *
19
 * http://numenta.org/licenses/
20
 * ---------------------------------------------------------------------
21
 */
22

23
package org.numenta.nupic.encoders;
24

25
import gnu.trove.list.TDoubleList;
26
import gnu.trove.list.array.TDoubleArrayList;
27

28
import java.util.ArrayList;
29
import java.util.Arrays;
30
import java.util.HashMap;
31
import java.util.List;
32
import java.util.Map;
33

34
import org.numenta.nupic.Connections;
35
import org.numenta.nupic.FieldMetaType;
36
import org.numenta.nupic.util.MinMax;
37
import org.numenta.nupic.util.Tuple;
38

39

40
/**
41
 * DOCUMENTATION TAKEN DIRECTLY FROM THE PYTHON VERSION:
42
 * 
43
 * This class wraps the ScalarEncoder class.
44
 * A Log encoder represents a floating point value on a logarithmic scale.
45
 * valueToEncode = log10(input) 
46
 * 
47
 *   w -- number of bits to set in output
48
 *   minval -- minimum input value. must be greater than 0. Lower values are
49
 *             reset to this value
50
 *   maxval -- maximum input value (input is strictly less if periodic == True)
51
 *   periodic -- If true, then the input value "wraps around" such that minval =
52
 *             maxval For a periodic value, the input must be strictly less than
53
 *             maxval, otherwise maxval is a true upper bound.
54
 *   
55
 *   Exactly one of n, radius, resolution must be set. "0" is a special
56
 *   value that means "not set".
57
 *   n -- number of bits in the representation (must be > w)
58
 *   radius -- inputs separated by more than this distance in log space will have
59
 *             non-overlapping representations
60
 *   resolution -- The minimum change in scaled value needed to produce a change
61
 *                 in encoding. This should be specified in log space. For
62
 *                 example, the scaled values 10 and 11 will be distinguishable
63
 *                 in the output. In terms of the original input values, this
64
 *                 means 10^1 (1) and 10^1.1 (1.25) will be distinguishable.
65
 *   name -- an optional string which will become part of the description
66
 *   verbosity -- level of debugging output you want the encoder to provide.
67
 *   clipInput -- if true, non-periodic inputs smaller than minval or greater
68
 *                 than maxval will be clipped to minval/maxval
69
 *   forced -- (default False), if True, skip some safety checks
70
 */
71
public class LogEncoder extends Encoder<Double> {
72
        private ScalarEncoder encoder;
73
        private double minScaledValue, maxScaledValue;
74
        /**
75
         * Constructs a new {@code LogEncoder}
76
         */
77
        LogEncoder() {}
1✔
78
        
79
        /**
80
         * Returns a builder for building LogEncoders. 
81
         * This builder may be reused to produce multiple builders
82
         * 
83
         * @return a {@code LogEncoder.Builder}
84
         */
85
        public static Encoder.Builder<LogEncoder.Builder, LogEncoder> builder() {
86
                return new LogEncoder.Builder();
1✔
87
        }
88
        
89
        /**
90
         *   w -- number of bits to set in output
91
         *   minval -- minimum input value. must be greater than 0. Lower values are
92
         *             reset to this value
93
         *   maxval -- maximum input value (input is strictly less if periodic == True)
94
         *   periodic -- If true, then the input value "wraps around" such that minval =
95
         *             maxval For a periodic value, the input must be strictly less than
96
         *             maxval, otherwise maxval is a true upper bound.
97
         *   
98
         *   Exactly one of n, radius, resolution must be set. "0" is a special
99
         *   value that means "not set".
100
         *   n -- number of bits in the representation (must be > w)
101
         *   radius -- inputs separated by more than this distance in log space will have
102
         *             non-overlapping representations
103
         *   resolution -- The minimum change in scaled value needed to produce a change
104
         *                 in encoding. This should be specified in log space. For
105
         *                 example, the scaled values 10 and 11 will be distinguishable
106
         *                 in the output. In terms of the original input values, this
107
         *                 means 10^1 (1) and 10^1.1 (1.25) will be distinguishable.
108
         *   name -- an optional string which will become part of the description
109
         *   verbosity -- level of debugging output you want the encoder to provide.
110
         *   clipInput -- if true, non-periodic inputs smaller than minval or greater
111
         *                 than maxval will be clipped to minval/maxval
112
         *   forced -- (default False), if True, skip some safety checks
113
         */
114
        public void init() {
115
                double lowLimit = 1e-07;
1✔
116

117
                // w defaults to 5
118
                if (getW() == 0) {
1✔
119
                        setW(5);
1✔
120
                }
121
                
122
                // maxVal defaults to 10000.
123
                if (getMaxVal() == 0.0) {
1✔
124
                        setMaxVal(10000.);
1✔
125
                }
126
                
127
                if (getMinVal() < lowLimit) {
1✔
128
                        setMinVal(lowLimit);
1✔
129
                }
130
                
131
                if (getMinVal() >= getMaxVal()) {
1✔
132
                        throw new IllegalStateException("Max val must be larger than min val or the lower limit " + 
1✔
133
                       "for this encoder " + String.format("%.7f", lowLimit));
1✔
134
                }
135
                
136
                minScaledValue = Math.log10(getMinVal());
1✔
137
                maxScaledValue = Math.log10(getMaxVal());
1✔
138
                
139
                if(minScaledValue >= maxScaledValue) {
1✔
140
                        throw new IllegalStateException("Max val must be larger, in log space, than min val.");
×
141
                }
142
                
143
                // There are three different ways of thinking about the representation. Handle
144
            // each case here.
145
                encoder = ScalarEncoder.builder()
1✔
146
                                .w(getW())
1✔
147
                                .minVal(minScaledValue)
1✔
148
                                .maxVal(maxScaledValue)
1✔
149
                                .periodic(false)
1✔
150
                                .n(getN())
1✔
151
                                .radius(getRadius())
1✔
152
                                .resolution(getResolution())
1✔
153
                                .verbosity(getVerbosity())
1✔
154
                                .clipInput(clipInput())
1✔
155
                                .forced(isForced())
1✔
156
                                .name(getName())
1✔
157
                                .build();
1✔
158
                
159
                setN(encoder.getN());
1✔
160
                setResolution(encoder.getResolution());
1✔
161
                setRadius(encoder.getRadius());
1✔
162
        }
1✔
163
        
164

165
        @Override
166
        public int getWidth() {
167
                return encoder.getWidth();
1✔
168
        }
169

170
        @Override
171
        public boolean isDelta() {
172
                return encoder.isDelta();
×
173
        }
174

175
        @Override
176
        public List<Tuple> getDescription() {
177
                return encoder.getDescription();
1✔
178
        }
179
                
180
        /**
181
         * {@inheritDoc}
182
         */
183
        @Override
184
        public List<FieldMetaType> getDecoderOutputFieldTypes() {
185
                return encoder.getDecoderOutputFieldTypes();
1✔
186
        }
187
        
188
        /**
189
         * Convert the input, which is in normal space, into log space
190
         * @param input Value in normal space.
191
         * @return Value in log space.
192
         */
193
        private Double getScaledValue(double input) {
194
                if(input == SENTINEL_VALUE_FOR_MISSING_DATA) {
1✔
195
                        return null;
×
196
                } else {
197
                        double val = input;
1✔
198
                        if (val < getMinVal()) {
1✔
199
                                val = getMinVal();
×
200
                        } else if (val > getMaxVal()) {
1✔
201
                                val = getMaxVal();
×
202
                        }
203

204
                        return Math.log10(val);
1✔
205
                }
206
        }
207
        
208
        /**
209
         * Returns the bucket indices.
210
         * 
211
         * @param        input         
212
         */
213
        @Override
214
        public int[] getBucketIndices(double input) {
215
                Double scaledVal = getScaledValue(input);
1✔
216
                
217
                if (scaledVal == null) {
1✔
218
                        return new int[]{};
×
219
                } else {
220
                        return encoder.getBucketIndices(scaledVal);
1✔
221
                }
222
        }
223
        
224
        /**
225
         * Encodes inputData and puts the encoded value into the numpy output array,
226
     * which is a 1-D array of length returned by {@link Connections#getW()}.
227
         *
228
     * Note: The numpy output array is reused, so clear it before updating it.
229
         * @param inputData Data to encode. This should be validated by the encoder.
230
         * @param output 1-D array of same length returned by {@link Connections#getW()}
231
     * 
232
         * @return
233
         */
234
        public void encodeIntoArray(Double input, int[] output) {
235
                Double scaledVal = getScaledValue(input);
1✔
236
                
237
                if (scaledVal == null) {
1✔
238
                        Arrays.fill(output, 0);
×
239
                        return;
×
240
                } else {
241
                        encoder.encodeIntoArray(scaledVal, output);
1✔
242
                        
243
                        if (getVerbosity() >= 2) {
1✔
244
                                System.out.print("input: " + input);
×
245
                                System.out.print(" scaledVal: " + scaledVal);
×
246
                                System.out.println(" output: " + Arrays.toString(output));
×
247
                        }
248
                }
249
        }
1✔
250

251
        /**
252
         * {@inheritDoc}
253
         */
254
        public DecodeResult decode(int[] encoded, String parentFieldName) {
255
                // Get the scalar values from the underlying scalar encoder
256
                DecodeResult decodeResult = encoder.decode(encoded, parentFieldName);
1✔
257
                
258
                Map<String, RangeList> fields = decodeResult.getFields();
1✔
259
                
260
                if (fields.keySet().size() == 0) {
1✔
261
                        return decodeResult;
×
262
                }
263
                
264
                // Convert each range into normal space
265
                RangeList inRanges = (RangeList) fields.values().toArray()[0];
1✔
266
                RangeList outRanges = new RangeList(new ArrayList<MinMax>(), "");
1✔
267
                for (MinMax minMax : inRanges.getRanges()) {
1✔
268
                        MinMax scaledMinMax = new MinMax( Math.pow(10, minMax.min()), 
1✔
269
                                                                                          Math.pow(10, minMax.max()));
1✔
270
                        outRanges.add(scaledMinMax);
1✔
271
                }
1✔
272
                
273
                // Generate a text description of the ranges
274
                String desc = "";
1✔
275
                int numRanges = outRanges.size();
1✔
276
                for (int i = 0; i < numRanges; i++) {
1✔
277
                        MinMax minMax = (MinMax) outRanges.getRange(i);
1✔
278
                        if (minMax.min() != minMax.max()) {
1✔
279
                                desc += String.format("%.2f-%.2f", minMax.min(), minMax.max());
×
280
                        } else {
281
                                desc += String.format("%.2f", minMax.min());
1✔
282
                        }
283
                        if (i < numRanges - 1) {
1✔
284
                                desc += ", ";
×
285
                        }
286
                }
287
                outRanges.setDescription(desc);
1✔
288
                
289
                String fieldName;
290
                if (!parentFieldName.equals("")) {
1✔
291
                        fieldName = String.format("%s.%s", parentFieldName, getName());
×
292
                } else {
293
                        fieldName = getName();
1✔
294
                }
295
                
296
                Map<String, RangeList> outFields = new HashMap<String, RangeList>();
1✔
297
                outFields.put(fieldName,  outRanges);
1✔
298
                
299
                List<String> fieldNames = new ArrayList<String>();
1✔
300
                fieldNames.add(fieldName);
1✔
301
                
302
                return new DecodeResult(outFields, fieldNames);
1✔
303
        }
304

305
        /**
306
         * {@inheritDoc}
307
         */
308
        @SuppressWarnings("unchecked")
309
        @Override
310
        public <S> List<S> getBucketValues(Class<S> t) {
311
                // Need to re-create?        
312
                if(bucketValues == null) {
1✔
313
                        List<S> scaledValues = encoder.getBucketValues(t);
1✔
314
                        bucketValues = new ArrayList<S>();
1✔
315
                        
316
                        for (S scaledValue : scaledValues) {
1✔
317
                                double value = Math.pow(10, (Double)scaledValue);
1✔
318
                                ((List<Double>)bucketValues).add(value);
1✔
319
                        }
1✔
320
                }
321
                return (List<S>)bucketValues;
1✔
322
        }
323
        
324
        /**
325
         * {@inheritDoc}
326
         */
327
        @Override
328
        public List<EncoderResult> getBucketInfo(int[] buckets) {
329
                EncoderResult scaledResult = encoder.getBucketInfo(buckets).get(0);
1✔
330
                double scaledValue = (Double)scaledResult.getValue();
1✔
331
                double value = Math.pow(10, scaledValue);
1✔
332
                
333
                return Arrays.asList(
1✔
334
                        new EncoderResult[] { 
335
                                new EncoderResult(value, value, scaledResult.getEncoding()) });
1✔
336
        }
337
        
338
        /**
339
         * {@inheritDoc}
340
         */
341
        @Override
342
        public List<EncoderResult> topDownCompute(int[] encoded) {
343
                EncoderResult scaledResult = encoder.topDownCompute(encoded).get(0);
1✔
344
                double scaledValue = (Double)scaledResult.getValue();
1✔
345
                double value = Math.pow(10, scaledValue);
1✔
346
                
347
                return Arrays.asList(
1✔
348
                        new EncoderResult[] { 
349
                                new EncoderResult(value, value, scaledResult.getEncoding()) });
1✔
350
        }
351
        
352
        /**
353
         * {@inheritDoc}
354
         */
355
        public TDoubleList closenessScores(TDoubleList expValues, TDoubleList actValues, boolean fractional) {
356
                TDoubleList retVal = new TDoubleArrayList();
1✔
357
                
358
                double expValue, actValue;
359
                if (expValues.get(0) > 0) {
1✔
360
                        expValue = Math.log10(expValues.get(0));
1✔
361
                } else {
362
                        expValue = minScaledValue;
×
363
                }
364
                if (actValues.get(0) > 0) {
1✔
365
                        actValue = Math.log10(actValues.get(0));
1✔
366
                } else {
367
                        actValue = minScaledValue;
1✔
368
                }
369
                
370
                double closeness;
371
                if (fractional) {
1✔
372
                        double err = Math.abs(expValue - actValue);
1✔
373
                        double pctErr = err / (maxScaledValue - minScaledValue);
1✔
374
                        pctErr = Math.min(1.0,  pctErr);
1✔
375
                        closeness = 1.0 - pctErr;
1✔
376
                } else {
1✔
377
                        double err = Math.abs(expValue - actValue);
×
378
                        closeness = err;
×
379
                }
380
                
381
                retVal.add(closeness);
1✔
382
                return retVal;
1✔
383
        }
384
        
385
        /**
386
         * Returns a {@link EncoderBuilder} for constructing {@link ScalarEncoder}s
387
         * 
388
         * The base class architecture is put together in such a way where boilerplate
389
         * initialization can be kept to a minimum for implementing subclasses, while avoiding
390
         * the mistake-proneness of extremely long argument lists.
391
         * 
392
         * @see ScalarEncoder.Builder#setStuff(int)
393
         */
394
        public static class Builder extends Encoder.Builder<LogEncoder.Builder, LogEncoder> {
395
                private Builder() {}
1✔
396

397
                @Override
398
                public LogEncoder build() {
399
                        //Must be instantiated so that super class can initialize 
400
                        //boilerplate variables.
401
                        encoder = new LogEncoder();
1✔
402
                        
403
                        //Call super class here
404
                        super.build();
1✔
405
                        
406
                        ////////////////////////////////////////////////////////
407
                        //  Implementing classes would do setting of specific //
408
                        //  vars here together with any sanity checking       //
409
                        ////////////////////////////////////////////////////////
410
                        
411
                        ((LogEncoder)encoder).init();
1✔
412
                        
413
                        return (LogEncoder)encoder;
1✔
414
                }
415
                
416
                /**
417
                 * Never called - just here as an example of specialization for a specific 
418
                 * subclass of Encoder.Builder
419
                 * 
420
                 * Example specific method!!
421
                 * 
422
                 * @param stuff
423
                 * @return
424
                 */
425
                public LogEncoder.Builder setStuff(int stuff) {
426
                        return this;
×
427
                }
428
        }
429
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc