Python: convert numpy array of signs to int and back
<p>I'm trying to convert from a numpy array of signs (i.e., a numpy array whose entries are either <code>1.</code> or <code>-1.</code>) to an integer and back through a binary representation. I have something that works, but it's not Pythonic, and I expect it'll be slow.</p>

<pre><code>def sign2int(s):
    s[s==-1.] = 0.
    bstr = ''
    for i in range(len(s)):
        bstr = bstr + str(int(s[i]))
    return int(bstr, 2)

def int2sign(i, m):
    bstr = bin(i)[2:].zfill(m)
    s = []
    for d in bstr:
        s.append(float(d))
    s = np.array(s)
    s[s==0.] = -1.
    return s
</code></pre>

<p>Then </p>

<pre><code>&gt;&gt;&gt; m = 4
&gt;&gt;&gt; s0 = np.array([1., -1., 1., 1.])
&gt;&gt;&gt; i = sign2int(s0)
&gt;&gt;&gt; print i
11
&gt;&gt;&gt; s = int2sign(i, m)
&gt;&gt;&gt; print s
[ 1. -1.  1.  1.]
</code></pre>

<p>I'm concerned about (1) the for loops in each and (2) having to build an intermediate representation as a string. </p>

<p>Ultimately, I will want something that works with a 2-d numpy array, too---e.g.,</p>

<pre><code>&gt;&gt;&gt; s = np.array([[1., -1., 1.], [1., 1., 1.]])
&gt;&gt;&gt; print sign2int(s)
[5, 7]
</code></pre>

<p>I'll start with <code>sig2int</code>..  Convert from a sign representation to <em>binary</em></p>

<pre><code>&gt;&gt;&gt; a
array([ 1., -1.,  1., -1.])
&gt;&gt;&gt; (a + 1) / 2
array([ 1.,  0.,  1.,  0.])
&gt;&gt;&gt; 
</code></pre>

<p>Then you can simply create an array of powers of two, multiply it by the <em>binary</em> and sum.</p>

<pre><code>&gt;&gt;&gt; powers = np.arange(a.shape[-1])[::-1]
&gt;&gt;&gt; np.power(2, powers)
array([8, 4, 2, 1])
&gt;&gt;&gt; a = (a + 1) / 2
&gt;&gt;&gt; powers = np.power(2, powers)
&gt;&gt;&gt; a * powers
array([ 8.,  0.,  2.,  0.])
&gt;&gt;&gt; np.sum(a * powers)
10.0
&gt;&gt;&gt; 
</code></pre>

<p>Then make it operate on rows by adding axis information and rely on broadcasting.</p>

<pre><code>def sign2int(a):
    # powers of two
    powers = np.arange(a.shape[-1])[::-1]
    np.power(2, powers, powers)
    # sign to "binary" - add one and divide by two
    np.add(a, 1, a)
    np.divide(a, 2, a)
    # scale by powers of two and sum
    np.multiply(a, powers, a)
    return np.sum(a, axis = -1)
&gt;&gt;&gt; b = np.array([a, a, a, a, a])
&gt;&gt;&gt; sign2int(b)
array([ 11.,  11.,  11.,  11.,  11.])
&gt;&gt;&gt; 
</code></pre>

<p>I tried it on a 4 by 100 bit array and it seemed fast</p>

<pre><code>&gt;&gt;&gt; a = a.repeat(100)
&gt;&gt;&gt; b = np.array([a, a, a, a, a])
&gt;&gt;&gt; b
array([[ 1.,  1.,  1., ...,  1.,  1.,  1.],
       [ 1.,  1.,  1., ...,  1.,  1.,  1.],
       [ 1.,  1.,  1., ...,  1.,  1.,  1.],
       [ 1.,  1.,  1., ...,  1.,  1.,  1.],
       [ 1.,  1.,  1., ...,  1.,  1.,  1.]])
&gt;&gt;&gt; sign2int(b)
array([  2.58224988e+120,   2.58224988e+120,   2.58224988e+120,
         2.58224988e+120,   2.58224988e+120])
&gt;&gt;&gt; 
</code></pre>

<hr>

<p>I'll add the reverse if i can figure it. - the best I could do relies on some plain Python without any numpy vectoriztion magic and I haven't figured how to make it work with a sequence of ints other than to iterate over them and convert them one at a time - but the time still seems acceptable.</p>

<pre><code>def foo(n):
    '''yields bits in increasing powers of two

    bit sequence from lsb --&gt; msb
    '''
    while n &gt; 0:
        n, r = divmod(n, 2)
        yield r

def int2sign(n):
    n = int(n)
    a = np.fromiter(foo(n), dtype = np.int8, count = n.bit_length())
    np.multiply(a, 2, a)
    np.subtract(a, 1, a)
    return a[::-1]
</code></pre>

<p>Works on 1324:</p>

<pre><code>&gt;&gt;&gt; bin(1324)
'0b10100101100'
&gt;&gt;&gt; a = int2sign(1324)
&gt;&gt;&gt; a
array([ 1, -1,  1, -1, -1,  1, -1,  1,  1, -1, -1], dtype=int8)
</code></pre>

<p>Seems to work with 1.2e305:</p>

<pre><code>&gt;&gt;&gt; n = int(1.2e305)
&gt;&gt;&gt; n.bit_length()
1014
&gt;&gt;&gt; a = int2sign(n)
&gt;&gt;&gt; a.shape
(1014,)

&gt;&gt;&gt; s = bin(n)
&gt;&gt;&gt; s = s[2:]
&gt;&gt;&gt; all(2 * int(x) -1 == y for x, y in zip(s, a))
True
&gt;&gt;&gt;
</code></pre>

python arrays numpy binary