-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Develop Python type system to better emulate MATLAB-like syntax and ease code adaptation #20
Comments
Originally posted by @balbasty in #19:
|
Regarding cell indexing:Curly brackets don't exist in Python, so there will always be changes required when adapting code. MATLAB allows item and slice indexing, with the possibility of unpacking the items using the A possible option is to enable these types of indexing: 1. Single item indexing:
|
I agree that bracket indexing does the job in 99% of use cases. Currently, the behaviour is that of numpy arrays, so your examples all work (the only cavehat is The only remaining issue with the absence of curly-like braces occurs when implictly declaring nested structures. Specifically: clear;
a.b(1).c = 'd'; % b is a struct array
clear;
a.b{1}.c = 'd'; % b is a cell that contains a struct In the prototype, I curently do a = StructArray()
a.b[0].c = 'd' # b is a struct array
a = StructArray()
a.b.as_cell[0].c = 'd' # b is a cell that contains a struct Alternatively, I was hoping to get something like this to work (but I am not there yet) a = StructArray()
a.b(0).c = 'd' # b is a cell that contains a struct |
I see, so for multidimensional cell arrays we then need to unpack as Well done for spotting this confusing case -- we do need a way for the user to tell us what type they want. I do prefer the explicit syntax you introduced (with |
In [1]: import numpy as np
In [2]: x = np.arange(16).reshape([4, 4])
In [3]: x
Out[3]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
In [4]: x.strides
Out[4]: (32, 8)
In [5]: y = np.array(x, order="F")
In [6]: y.strides
Out[6]: (8, 32)
In [7]: list(x.flat)
Out[7]:
[np.int64(0),
np.int64(1),
np.int64(2),
np.int64(3),
np.int64(4),
np.int64(5),
np.int64(6),
np.int64(7),
np.int64(8),
np.int64(9),
np.int64(10),
np.int64(11),
np.int64(12),
np.int64(13),
np.int64(14),
np.int64(15)]
In [8]: list(y.flat)
Out[8]:
[np.int64(0),
np.int64(1),
np.int64(2),
np.int64(3),
np.int64(4),
np.int64(5),
np.int64(6),
np.int64(7),
np.int64(8),
np.int64(9),
np.int64(10),
np.int64(11),
np.int64(12),
np.int64(13),
np.int64(14),
np.int64(15)] We might have to transpose if we want the exact same behaviour as matlab (or just not care -- I don't have use cases in mind where this would be a problem).
|
Another option is to override the a{3} = 'c'; to a(3) = 'c' With struct arrays, we would never really do assignment, but rather assign fields, e.g. a.b(3).c = 4 But again, that prevents from doing, e.g., a.b(:).c = d[:] to initialize the fields of a StructArray, which we can do if we use square brackets. Last option is to have a = StructArray()
a.b[0].c = 'd'
# OK! b is a struct array
a = StructArray()
a.b.as_struct[0] = StructArray(c='d')
# OK! b is a struct array
a = StructArray()
a.b(0).c = 'd'
# OK! b is a cell that contains a struct
a = StructArray()
a.b.as_cell[0] = StructArray(c='d')
# OK! b is a cell that contains a struct And two edge cases: a = StructArray()
a.b[0] = StructArray(c='d')
# OK, b is a cell that contains a StructArray???
a = StructArray()
a.b(0) = StructArray(c='d')
# ERROR! |
OK, so I've now made rounded brackets The only differences are:
I've implemented a.b(0).c = 'd' # Instructs that b is a CellArray
a.b(1).c = 'e' # At this point b is already a CellArray, but we can still use `()` If we implement a.b(0).c = 'd' # Instructs that b is a CellArray
a.b[1].c = 'e' # At this point b is already a CellArray, so we cannot use `()` I believe this covers most matlab use cases, except Here are matlab's behaviours for a bunch of cases: %% x.field = array -> struct
clear;
a.b = 1;
%% x(scalar).field = array -> struct
clear;
a(2).b = 1;
%% x(slice).field = array -> ERROR
clear;
a(2:3).b = 1;
%% [x(slice).field] = function() -> struct
clear;
[a(2:3).b] = foo();
%% x(scalar) = struct -> struct
clear;
a.b(2) = struct('c', 1);
%% x(slice) = struct -> struct
clear;
a.b(2:3) = struct('c', 1);
%% x(slice) = struct array -> struct
clear;
a.b(2:3) = struct('c', {1 2});
%% x{scalar} = array -> cell
clear;
a.b{2} = 1;
%% x{scalar} = struct -> cell of struct
clear;
a.b{2} = struct('c', 1);
%% x{slice} = array -> ERROR
clear;
a.b{2:3} = 1;
%% x{slice} = array -> ERROR
clear;
[a.b{2:3}] = foo();
%% x(scalar) = array -> array
clear;
a.b(2) = 1;
%% x(scalar) = cell -> cell
clear;
a.b(2) = {1};
%% x(slice) = cell -> cell
clear;
a.b(2:3) = {1};
%% x(slice) = cell array -> cell
clear;
a.b(2:3) = {1 2};
%% x(slice) = array -> array
clear;
a.b(2:3) = [1 2];
%% x{scalar}.field = array -> cell of struct
clear
a{2}.b = 1;
%% x{slice}.field = array -> ERROR
clear
a{2:3}.b = 1;
%% [x{slice}.field] = function() -> ERROR
clear
[a{2:3}.b] = foo();
%%
function [x,y] = foo(), x = 1; y = 2; end For your non-erroring edge case, I think I would interpret it as a = StructArray()
a.b[0] = StructArray(c='d')
# OK, b is a StructArray so that it matches %% x(scalar) = struct -> struct
a.b(1) = struct('c', 'd'); but I agree that this is the most confusing case. Some other issues:
Going forward:
I think we're converging towards something that makes sense! :) |
Implemented in #21 |
Enabling MATLAB-like syntax on Python data structures is important to reduce the complexity of adapting existing MATLAB code (such as examples or snippets generated by SPM matlabbatch system) to Python. The type system should enable syntax as close as possible to MATLAB's, while behaving in a simple and predictible way.
Current type implementation only mimic the basic syntax of Matlab objects (e.g., dot indexing for structures), but does not allow other existing MATLAB syntactic features (such as indexing an undeclared field in a structure)
In #19, @balbasty proposed a new type system enabling several of these features. This issue is about reviewing and integrating this type system in the code base.
The text was updated successfully, but these errors were encountered: