0

I'm not sure if I've used to correct wording in the Title to describe the problem. Please do feel free to edit it to reflect the description below.

Suppose I have a sudoku solver program and lets say the input matrix is the following,

A = randi(10,[9,9])-1;

I index the 3x3 sub-matrices columnwise from 1 to 9. Let's say the variable nSubMat representing this index can take any values between 1 to 9.

I index the submatrices in the following way,

SubMat(nSubMat) = A((1:3)+(3*floor((nSubMat-1)/3)),(1:3)+(3*mod(nSubMat-1,3)));

Now, I want to access and modify the value in the (2x3) position of SubMat without having to create SubMat in the first place(say to avoid unnecessary copies).

To elaborate, if I were to have a function submatrix() which would implement the above, my statement would look something like the following,

submatrix(A((1:3)+(3*floor((nSubMat-1)/3)),(1:3)+(3*mod(nSubMat-1,3))),[2,3]) = 5;

or even,

submatrix(A((1:3)+(3*floor((nSubMat-1)/3)),(1:3)+(3*mod(nSubMat-1,3))),[2:3,2:3]) = [1 2;3 4];

I know that Matlab interpreter automatically optimizes LHS=RHS type assignments for speed, but the above matrix operation is important for more reasons (algorithmically) than just reducing copies and speeding up the code which I will not dwell into here. I have seen the required syntax in a C++ library called Armadillo, but I'm not sure if the same can be done with MATLAB.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Naveen
  • 458
  • 1
  • 10
  • 29
  • Did you find any of the answer useful? If yes, then please accept it so that it gets off the unanswered list. – Autonomous May 31 '15 at 21:28

2 Answers2

1

You could do this using simple linear indexing. The following code is self-explanatory.

matrixRows=9;
matrixCols=9;
blockRows=3;
blockCols=3;
accessRow=2;
accessCol=3;

A = randi(10,[matrixRows,matrixCols])-1;
allPos=allcomb(accessRow:blockRows:matrixRows,accessCol:blockCols:matrixCols);
linPos=sub2ind(size(A),allPos(:,1),allPos(:,2));

% access them as usual and put any value
A(linPos)=-100;

Result:

A =

 8     9     7     3     6     4     1     6     8
 9     1     9     6     3     4     4     8     2
 1     9     6     1     9     6     9     9     9
 9     9     0     7     0     7     3     5     3
 6     4     8     0     4     7     5     1     1
 0     8     9     2     3     2     2     1     2
 2     1     6     0     7     6     7     2     6
 5     4     7     0     7     6     2     8     4
 9     9     7     8     1     1     5     2     3

After running above code:

A =

 8     9     7     3     6     4     1     6     8
 9     1  -100     6     3  -100     4     8  -100
 1     9     6     1     9     6     9     9     9
 9     9     0     7     0     7     3     5     3
 6     4  -100     0     4  -100     5     1  -100
 0     8     9     2     3     2     2     1     2
 2     1     6     0     7     6     7     2     6
 5     4  -100     0     7  -100     2     8  -100
 9     9     7     8     1     1     5     2     3

Note: allcomb generates all possible combinations of the input arguments. You can also use this which is faster than allcomb (according to the answer).

Community
  • 1
  • 1
Autonomous
  • 8,935
  • 1
  • 38
  • 77
  • An armadillo [submat views](http://arma.sourceforge.net/docs.html#submat) type access is what I was looking for, but linear indexing should do. Also, how efficient is allcomb() for large square matrices, larger access region or large number of iterations in sudoku? – Naveen May 31 '15 at 23:29
  • I think it will be pretty efficient. As I mentioned, you can also test out the alternative which is apparently faster. – Autonomous Jun 01 '15 at 03:12
1

This is a general function for any size Sudoku puzzle.

function index = SudukoIndex(varargin)
%%%SudukoIndex provides the index or indicies of a sub-block of any n*n
%%%Suduko puzzle

%Possible inputs
%   One (1) number (i) between 1 and n will provide a sqrt(n) * sqrt(n) set of
%      indicies from the i-th block. Note this is counted using Matlab
%      syntax going from top to bottom then left to right, a simple check
%      for this can be found by typing the command 'reshape(1:n, sqrt(n),
%      sqrt(n))' into the command window.
%   Two (2) numbers between 1 and n will provide the single number index of
%       the row, column combination
%   Three (3) numbers the first (i) between 1 and n and the second (j) and 
%       third (k) between 1 and sqrt(n) will provide the index of the (j,k)
%       point in the i-th cell
n = 9;

if nargin == 1
    sM = varargin{1};
    majorColumn = floor((sM-1)/sqrt(n)) + 1;
    majorRow = mod(sM-1, sqrt(n)) + 1;

    x = (1:sqrt(n))';
    y = (1:n:n^1.5);
    [x, y] = meshgrid(x, y);
    m = (x + y - 1)';

    index = (n^1.5)*(majorColumn - 1) + sqrt(n)*(majorRow - 1) + m;
elseif nargin == 2
    index = n*(varargin{2} - 1) + varargin{1};
elseif nargin == 3
    m = nsm(varargin{1});
    index = m(varargin{2}, varargin{3});
end
end
user1543042
  • 3,422
  • 1
  • 17
  • 31