1

Given I have an array like this:

array = [Array[8], Array[8], Array[8], ...]
# array.length is 81; each octet represents a point on a 9x9 grid

where each nested array contains 8 numeric elements ranging from -2 to 2, how would I apply the following step to get a vector in Javascript?

Step 5. The signature of an image is simply the concatenation of the 8-element arrays corresponding to the grid points, ordered left-to-right, top-to-bottom. Our signatures are thus vectors of length 648. We store them in 648-byte arrays, but because some of the entries for the first and last rows and columns are known to be zeros and because each byte is used to hold only 5 values, signatures could be represented by as few as ⌈544 log2 5⌉ = 1264 bits.

(Towards the end, those are supposed to be ceiling notations; best I could do given SO's lack of Latex formatting)

I have the array ready to go and ordered properly, but my knowledge of matricies and vectors is a little rusty, so I'm not sure how to tackle this next step. I'd appreciate any clarifications!


Background: I'm trying to create a JS implementation of an image processing algorithm published by the Xerox Palo Alto Research Center for a side-project I'm currently working on.

neezer
  • 19,720
  • 33
  • 121
  • 220
  • Do you need just to concatenate arrays or perform some compression optimization too? – Artem Sobolev Apr 10 '13 at 12:24
  • @Barmaley.exe I'm just looking for concatenation for now, though I would certainly like to add compression optimization at some point too, provided it is not too intensive on system resources to compress/decompress. – neezer Apr 10 '13 at 17:08
  • For just concatenating the 81 8-byte-arrays to one big 648-byte-array, use `bigarray = [].concat.apply([], array);` – Bergi Apr 10 '13 at 18:10
  • @Bergi Yeah, that works, though I guess I thought I would be ending up with a number of some sort--like an integer rather than an array. I ultimately want to store this in a database of some sort... MvG's approach (below) to use a 32 bit signed integer was appealing for that reason, but if I understand the math, it's not large enough to accomodate the vector. Do I have that right, or am I missing something? – neezer Apr 10 '13 at 20:24
  • You want to compute that 1264-bit integer in JavaScript? Good luck :-) You might want to have a look at [typed arrays](https://developer.mozilla.org/en-US/docs/JavaScript/Typed_arrays) then. – Bergi Apr 10 '13 at 20:28
  • @Bergi Haha, fair enough. How might I persist this vector in a database then? Make it a string or something? – neezer Apr 10 '13 at 21:26

1 Answers1

0

Conceptually you could convert this to a single 1264 bit number using the following algorithm:

  1. Initialize an accumulator variable to zero
  2. Iterate over all elements, but skipt those which you know to be zero
  3. For the other elements, add 2 to obtain values in the range [0,1,2,3,4]
  4. For each such value, multiply the accumulator by 5 then add the corresponding value
  5. When you have processed all elements, the accumulator will encode your arrays

To reverse that encoding, youd do this:

  1. Read the encoded value into the accumulator
  2. Iterate over all elements, in reverse order, but skipt those which you know to be zero
  3. For each element, you obtain the corresponding value as the accumulator modulo 5
  4. Subtract 2 from that value
  5. Divide the accumulator by 5 using a truncating division

The problem with all of this is the fact that JS doesn't provide 1264 bit numbers out of the box. You might try one of the libraries suggested in How to deal with big numbers in javascript.

But unless you absolutely requre an extremely small representation, I'd suggest an alternative approach: you can encode up to 13 such values in a 32 bit signed integer, since 513=1,220,703,125 < 2,147,483,648=231. So after encoding 13 values I'd write out the result using such a number, then reset the accumulator to zero. This way you'll need ⌈544/13⌉∙32=1376 bits, which is not that much worse in terms of space requirements, but will be a lot faster to implement.

Instead of iterating once in forward and once in reverse direction, it might be easier to not multiply the accumulator by 5, but instead multiply the value you add to that by a suitable power of 5. In other words, you maintain a factor which you initialize to 1, and multiply by 5 every time you add a value. So in this case, first data values will have less significant positions than later data values, both for encoding and decoding, which means you can use the same iteration order for both.

See the ideone link mentioned in my comment below for an example of this latter approach. It encodes the full 9*9*8 values in 50 integers, each of them using no more than 31 bits. It then decodes the original matrix from that encoded form, to show that all the information is still present. The example does not use any fixed zeros, in your case ⌈544/13⌉=42 integers should be enough.

Community
  • 1
  • 1
MvG
  • 57,380
  • 22
  • 148
  • 276
  • Ok, I think I understand this. What I'm not clear on is "you can encode up to 13 such values in a 32 bit signed integer"... I should've mentioned that the array above holds 81 octet sets (each representing a point on a 9x9 grid), so that means I can't use a 32 bit signed integer, right? Also a little unclear on "the accumulator will encode your arrays" (as part of step 5 in your original algorithm)--is there additional logic that happens there, or are you just saying that at that point the value of the accumulator will be the encoded vector? – neezer Apr 10 '13 at 17:04
  • @neezer: At the end, the accumulator will encode the vector without additional steps required. When you switch to 32 bits for every 13 values, you'd executes steps 1 and 5 once for every such set of 13, not only once for all 544 values together. See http://ideone.com/CgeDDj for an example. – MvG Apr 10 '13 at 23:38