001/* 002 AUTOMATICALLY GENERATED BY jTemp FROM 003 /Users/jsh2/Work/openimaj/target/checkout/core/core-feature/src/main/jtemp/org/openimaj/feature/Multidimensional#T#FV.jtemp 004*/ 005/** 006 * Copyright (c) 2011, The University of Southampton and the individual contributors. 007 * All rights reserved. 008 * 009 * Redistribution and use in source and binary forms, with or without modification, 010 * are permitted provided that the following conditions are met: 011 * 012 * * Redistributions of source code must retain the above copyright notice, 013 * this list of conditions and the following disclaimer. 014 * 015 * * Redistributions in binary form must reproduce the above copyright notice, 016 * this list of conditions and the following disclaimer in the documentation 017 * and/or other materials provided with the distribution. 018 * 019 * * Neither the name of the University of Southampton nor the names of its 020 * contributors may be used to endorse or promote products derived from this 021 * software without specific prior written permission. 022 * 023 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 024 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 025 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 026 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 027 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 028 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 029 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 030 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 032 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 033 */ 034package org.openimaj.feature; 035 036import java.io.DataInput; 037import java.io.DataOutput; 038import java.io.IOException; 039import java.io.PrintWriter; 040import java.io.Serializable; 041import java.util.Scanner; 042 043/** 044 * Basic long multidimensional feature vector implementation 045 * 046 * @author Jonathon Hare 047 */ 048public class MultidimensionalLongFV extends LongFV implements Serializable, Cloneable, FeatureVector { 049 private static final long serialVersionUID = 1L; 050 051 /** 052 * Array containing the number of bins in each dimension 053 */ 054 public int nbins[]; 055 056 /** 057 * Construct an empty feature vector 058 */ 059 public MultidimensionalLongFV() {} 060 061 /** 062 * Construct empty FV with given dimensions 063 * @param nbins the number of bins in each dimension 064 */ 065 public MultidimensionalLongFV(int... nbins) { 066 super(); 067 068 if(nbins.length == 0) throw new IllegalArgumentException("must be at least one dimension"); 069 070 this.nbins = nbins; 071 int sz=nbins[0]; 072 for (int i=1; i<nbins.length; i++) sz *= nbins[i]; 073 values = new long[sz]; 074 } 075 076 /** 077 * Construct from flattened values array and dimensions 078 * @param values the flat array of values 079 * @param nbins the number of bins in each dimension 080 */ 081 public MultidimensionalLongFV(long [] values, int...nbins) { 082 super(); 083 084 if(nbins.length == 0) throw new IllegalArgumentException("must be at least one dimension"); 085 this.values = values; 086 this.nbins = nbins; 087 } 088 089 /** 090 * Construct from 2-dimensional array 091 * @param values the 2d array 092 */ 093 public MultidimensionalLongFV(long [][] values) { 094 this((values.length == 0 ? 0 : values[0].length), values.length); 095 096 for (int j=0; j<values.length; j++) { 097 for (int i=0; i<values[0].length; i++) { 098 this.values[i + j*values[0].length] = values[j][i]; 099 } 100 } 101 } 102 103 /** 104 * Construct from 3-dimensional array 105 * @param values the 3d array 106 */ 107 public MultidimensionalLongFV(long [][][] values) { 108 this(values[0][0].length, values[0].length, values.length); 109 110 for (int k=0; k<values.length; k++) { 111 for (int j=0; j<values[0].length; j++) { 112 for (int i=0; i<values[0][0].length; i++) { 113 this.values[i + j*values[0][0].length + k*values[0][0].length*values[0].length] = values[k][j][i]; 114 } 115 } 116 } 117 } 118 119 /** 120 * Get the underlying flat-vector representation 121 * @return a flat 1d representation of the feature 122 */ 123 @Override 124 public long [] getVector() { 125 return values; 126 } 127 128 /** 129 * Get the element at the given flat index 130 * @param x the flattened element index 131 * @return the value corresponding to x 132 */ 133 @Override 134 public long get(int x) { 135 return values[x]; 136 } 137 138 /** 139 * Set the element at the given flat index 140 * @param value the value to set 141 * @param x the flattened element index 142 */ 143 @Override 144 void set(long value, int x) { 145 values[x] = value; 146 } 147 148 /** 149 * Convert the given coordinate into a flat index value 150 * @param coords the coordinate 151 * @return the flattened index 152 */ 153 public int getIndex(int... coords) { 154 if (coords.length != nbins.length) 155 throw new IllegalArgumentException("given dimensions mismatch"); 156 157 int idx = coords[0]; 158 for (int i=1; i<coords.length; i++) { 159 int mult = nbins[0]; 160 for (int j=1; j<i; j++) 161 mult *= nbins[j]; 162 163 idx += coords[i] * mult; 164 } 165 166 return idx; 167 } 168 169 /** 170 * Set the the element at the given n-dimensional coordinate 171 * @param value the value to set 172 * @param coords the coordinates 173 */ 174 public void set(long value, int... coords) { 175 values[getIndex(coords)] = value; 176 } 177 178 /** 179 * Get the element at the given n-dimensional coordinate 180 * @param coords the coordinates 181 * @return the value at the given coordinates 182 */ 183 public long get(int... coords) { 184 int idx = getIndex(coords); 185 186 return values[idx]; 187 } 188 189 @Override 190 public MultidimensionalLongFV clone() { 191 MultidimensionalLongFV model = (MultidimensionalLongFV) super.clone(); 192 model.nbins = nbins.clone(); 193 return model; 194 } 195 196 @Override 197 public String toString() { 198 String ret = this.getClass().getName(); 199 for (int dim : nbins) ret += "[" + dim + "]"; 200 ret += " {"; 201 202 if (nbins.length == 2) { 203 ret += "\n"; 204 for (int i=0; i<nbins[1]; i++) { 205 for (int j=0; j<nbins[0]; j++) { 206 ret += String.format("%2.4f", values[j + i*nbins[0]]); 207 // if (j != nbins[0]) { 208 ret += ", "; 209 // } 210 } 211 ret += "\n"; 212 } 213 } else { 214 for (int i=0; i<values.length; i++) { 215 ret += String.format("%2.3f", values[i]); 216 if (i != values.length-1) ret += ", "; 217 } 218 } 219 220 ret += "}"; 221 222 return ret; 223 } 224 225 /** 226 * Convert the FV to a DoubleFV representation 227 * @return the DoubleFV representation 228 */ 229 @Override 230 public MultidimensionalDoubleFV asDoubleFV() { 231 return new MultidimensionalDoubleFV(asDoubleVector(), nbins.clone()); 232 } 233 234 /** 235 * Compare this FV to another with the given method. 236 * 237 * @param h the feature to compare against. 238 * @param method the method to compare with. 239 * @return a score determined by the comparison method. 240 */ 241 public double compare(MultidimensionalLongFV h, LongFVComparison method) { 242 return method.compare(this, h); 243 } 244 245 @Override 246 public void writeBinary(DataOutput out) throws IOException { 247 out.writeInt(nbins.length); 248 for (int i=0; i<nbins.length; i++) out.writeInt(nbins[i]); 249 for (int i=0; i<values.length; i++) out.writeLong(values[i]); 250 } 251 252 @Override 253 public void writeASCII(PrintWriter out) throws IOException { 254 out.print(nbins.length + " "); 255 for (int i=0; i<nbins.length; i++) out.print(nbins[i] + " "); 256 out.println(); 257 for (int i=0; i<values.length; i++) out.print( values[i] + " "); 258 out.println(); 259 } 260 261 @Override 262 public void readBinary(DataInput in) throws IOException { 263 int len = in.readInt(); 264 265 if (nbins == null || nbins.length!=len) nbins = new int[len]; 266 for (int i=0; i<len; i++) nbins[i] = in.readInt(); 267 268 int sz=nbins[0]; 269 for (int i=1; i<nbins.length; i++) sz *= nbins[i]; 270 values = new long[sz]; 271 for (int i=0; i<sz; i++) values[i] = in.readLong(); 272 } 273 274 @Override 275 public void readASCII(Scanner in) throws IOException { 276 String [] line = in.nextLine().trim().split(" "); 277 int len = Integer.parseInt(line[0]); 278 279 if (nbins == null || nbins.length!=len) nbins = new int[len]; 280 for (int i=0; i<len; i++) nbins[i] = Integer.parseInt(line[i+1]); 281 282 int sz=nbins[0]; 283 for (int i=1; i<nbins.length; i++) sz *= nbins[i]; 284 values = new long[sz]; 285 line = in.nextLine().trim().split(" "); 286 for (int i=0; i<sz; i++) values[i] = Long.parseLong(line[i]); 287 } 288 289 @Override 290 public byte[] binaryHeader() { 291 return (this.getClass().getName().substring(0,2) + "MDFV").getBytes(); 292 } 293 294 @Override 295 public String asciiHeader() { 296 return this.getClass().getName() + " "; 297 } 298 299 /** 300 * Given an index, calculate the coordinate which would map to that index using {@link #getIndex(int...)} 301 * @param index 302 * @return the coordinates 303 */ 304 public int[] getCoordinates(int index){ 305 int ndims = nbins.length; 306 int[] start = new int[ndims]; 307 float multiply = 1; 308 for (int i : nbins) multiply *= i; 309 310 if(index >= multiply) throw new IllegalArgumentException(); 311 if(index < 0) throw new IllegalArgumentException(); 312 313 for (int i=ndims-1; i>=0; i--) { 314 multiply/=nbins[i]; // divide the multiplier by the current slice 315 int numberOfSlices = (int) Math.floor(index / multiply); 316 start[i] = numberOfSlices; 317 318 index = (int) (index - (numberOfSlices * multiply)); 319 } 320 return start; 321 } 322}