1

I am porting some Matlab code to Python. In this code there are many instances of a large matrix being sliced in many different ways, eg M(2:45,13:18), M(:12,:), V(4), V(:27), etc. It is technically possible to convert this to numpy notation manually, by replacing the parentheses with square brackets and substracting 1 to all indices (except after :) but it is incredibly tedious and there is a very high probability that I will make a typo at some point.

I tried automating this but my grep/awk/parsing skills are not good enough. Is there a script out there that will do the job?

Mathieu
  • 241
  • 1
  • 8
  • While `basic` indexing is similar enough, indexing with lists/arrays, what `numpy` docs call `advanced` indexing is different. You have to use `np.ix_` to get similar 'block' indexing. – hpaulj Oct 08 '22 at 15:55
  • Some of your examples are not even valid MATLAB syntax. – Cris Luengo Oct 08 '22 at 16:02
  • Cris Luengo: noted, but whether the input Matlab is valid is not really my issue to solve. I'm confident that my actual inputs will be valid, and I was just wondering hoe to automate the conversion. Thanks anyway. – Mathieu Oct 09 '22 at 18:04
  • Still, it makes no sense to translate `V(:27)` because it means nothing in MATLAB. – Cris Luengo Oct 09 '22 at 21:07

2 Answers2

1

Assuming you have your matlab code in a string, you can format it in Python. You could do this with regex match replacement:

import re

def format_indexers(match):
    # Format any "(x:y:z)" into python format
    ret = match[0].replace("(", "[").replace(")", "]") # replace brackets
    ret = re.sub(r"(\[|,)(\d+)", lambda x: x[1] +  str(int(x[2]) - 1) , ret) # replaces numbers by decremented ones
    return ret    

s = "M(2:45,13:18), M(:12,:), V(4), V(:27)"

# Searches expressions between parenthesis and apply format_indexers to found matches
re.sub(r"\(.*\)", format_indexers, s)

outputs:

'M[1:45,12:18], M[:12,:], V[3], V[:27]'
PlainRavioli
  • 1,127
  • 1
  • 1
  • 10
0

Here is another take based on PlainRavioli's original answer:

INPUT = 'M(2:45,13:18) M(:12,:) V(4) V(:27)'

import re

def my_replace(m):
    m = m.group()
    a, m = m[0], m[2:-1]
    m = m.split(',')
    for k in range(len(m)):
        if ':' in m[k]:
            m[k] = m[k].split(':')
            if m[k][0]:
                m[k][0] = str(int(m[k][0])-1)
            m[k] = ':'.join(m[k])
        else:
            m[k] = str(int(m[k])-1)
    m = ','.join(m)
    m = a + '[' + m + ']'
    return m

OUT = re.sub('\\w\\(\d*:?\d*(,\d*:?\d*)?\\)', my_replace, INPUT)
    
print(OUT)
# yields:  M[1:45,12:18] M[:12,:] V[3] V[:27]
Mathieu
  • 241
  • 1
  • 8
  • You’d have to look for `end` in indexing and translate that correctly too. Some indexing doesn’t translate at all, for example `a(end+1)=1` you can’t do in Python. And special indexing would be translated wrong with this program, `a([1,2,3],[3,5,2])` does something very different from the similar-looking Python code. Be careful! – Cris Luengo Oct 09 '22 at 21:11