* Bug 7293 fixed: circshift() introduced
[scilab.git] / scilab / modules / elementary_functions / macros / circshift.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) 2017 - Samuel GOUGEON
3 //
4 // This file is hereby licensed under the terms of the GNU GPL v2.0,
5 // pursuant to article 5.3.4 of the CeCILL v.2.1.
6 // This file was originally licensed under the terms of the CeCILL v2.1,
7 // and continues to be available under such terms.
8 // For more information, see the COPYING file which you should have received
9 // along with this program.
10
11 function R = circshift(M, sh, d)
12
13     // SPECIAL SIMPLE CASES
14     // --------------------
15     if argn(2) == 0 then
16         R = []
17         return
18     end
19
20     Fname = "circshift"
21
22     // M must be sizeable (including for custom types)
23     try
24         s = size(M)
25         n = size(M,"*")
26     catch
27         msg = _("%s: Argument #%d: Wrong type. A sizeable type expected.\n");
28         error(msprintf(msg, Fname, 1));
29     end
30
31     if or(n == [0, 1]) then
32         R = M
33         return
34     end
35
36     nd = length(s)    // Number of Dimensions (without using ndims())
37
38     // CHECKING INPUT ARGUMENTS. DEFAULTS
39     // ----------------------------------
40     if ~isdef("sh", "l") then
41         msg = _("%s: Wrong number of input arguments: %d to %d expected.\n");
42         error(msprintf(msg, Fname, 2, 3));
43     end
44     if and(type(sh) ~= [1 8]) | ~and(sh == int(sh)) then
45         msg = _("%s: Argument #%d: Integer(s) expected.\n");
46         error(msprintf(msg, Fname, 2));
47     end
48     if length(sh) > nd then
49         msg = _("%s: Argument #%d: Must be in the interval [%s, %s].\n");
50         error(msprintf(msg, Fname, 2, "1", msprintf("%s\n", nd)));
51     end
52     sh = double(sh);
53     //
54     if ~isdef("d", "l") then
55         if length(sh) == 1 then
56             d = find(s > 1, 1)
57             if d == [] then
58                 d = 1
59             end
60         else
61             d = 1:length(sh)
62         end
63     else
64         if and(type(d) ~= [1 8]) | ~and(d == int(d)) then
65             msg = _("%s: Argument #%d: Integer(s) expected.\n");
66             error(msprintf(msg, Fname, 3));
67         end
68         d = double(d);
69         if (length(d) == 1 & (d < 0 | d > nd)) | (length(d) > 1 & or(d < 1 | d > nd)) then
70             msg = _("%s: Argument #%d: Must be in the interval [%s, %s].\n");
71             error(msprintf(msg, Fname, 3, "1", msprintf("%d\n", nd)));
72         end
73     end
74
75     // PROCESSING
76     // ----------
77     R = M
78
79     // Shift of linearized indices
80     if length(d) == 1 & d == 0 then
81         if sh > 0 then
82             R(:) = M([n-sh+1:n 1:(n-sh)]);
83         else
84             R(:) = M([1-sh:n 1:-sh]);
85         end
86         return
87     end
88
89     // Shifts of ranges:
90     for i = 1:length(sh)
91         si = s(d(i));
92         if si > 1 then
93             D = pmodulo(sh(i), si)
94             if D ~= 0 then
95                 S = emptystr(1, nd) + ":"
96                 S(d(i)) = "[si-D+1:si 1:si-D]"
97                 S = strcat(S, ",")
98                 execstr("R = R("+S+")")
99             end
100         end
101     end
102 endfunction