Week 11 - Programming IVToday 1. Vectorization to simplify programs 2. Structured software
Definition: array operations versus loops
1. masks (indicator arrays)• math with masks• addressing with masks
2. array functions
Structured Programming
• Manage complexity
• Readable
• Testable
• Reusable
• Maintainable
Structured Programming
• Hierarchical• Modules are divided into smaller and smaller
submodules (functions work well as modules)
• functions contain functions
• Modular• Simple independent modules with well defined
inputs and outputs
• Locality• Minimize inputs and outputs
• Generate values inside the module where possible
Example 1 – clipping a time plot to [-1,1]:
0 20 40 60 80 100 120 140 160 180 200-2
-1
0
1
2
0 20 40 60 80 100 120 140 160 180 200-2
-1
0
1
2
Time (sec.)
Time (sec.)
Method 1 – using a loop and branch:
for k = 1:length(y)if y(k) > 1
y(k) = 1;elseif y(k) < -1
y(k) = -1; end
end
Method 2 – using mask math:
p = y>1;n = y<-1;y = (1-p).*(1-n).*y + p - n;
or
p = y>1;n = y<-1;y = ~p.*~n.*y + p - n;
“mask” arrays to indicate locations with relevant characteristics
use masks either mathematicallyor logically
Method 3 – using mask addressing:
p = y>1; or
n = y<-1;
y(p) = 1; y(y>1) = 1;
y(n) = -1; y(y<-1) = -1;
mask determineswhich elementsto change
Example 2 – reorder quiz scores (by row):
Method 1 – loop and branch:
for k = 1:size(score,1)
if score(k,1) < score(k,2)
score(k,:) = score(k,[2 1]);
end
end
size with second argument 1 returns the number of rows
Method 2 – using mask addressing:
flip = score(:,1)<score(:,2);
score(flip,[1 2]) = score(flip,[2 1])
identify which rows to swap
and reverse them
Example 3: sorting (last week)
Given N numbers (x1,…xN), sort them into increasing order
3 1 4 5 2 7 1
0 1 2 3 4 5 7
3145270
0145273
0145273
0125473
0123475
0123475
0123457
start
done
Original program employed nested loops:
function array = simpsort(array)% function to sort from smallest to largest for k = 1:length(array)-1
loc = k; for k2 = k:length(array)
if array(k2)<array(loc) loc = k2;
end end if loc ~= k
array([k,loc ]) = array([loc,k]); endend
locate the index (loc) of the smallest value
swap values, if necessary
Method 2 – using array functions function array = simpsort(array)
% vectorized version of simpsort
for k = 1:length(array)-1
[ val, loc ] = min( array(k:end) );
array([k,loc+k-1]) = array([loc+k-1,k]);
end
note offset to loc of k-1 since min( ) works on a subarray
Example 4: matrix sorting (HW 7-15)
Sort a 4 by 7 matrix
Method 1 – brute force loop and branch:for r1 = 1:4 for c1 = 1:7 val = inf; for r2 = 1:4 for c2 = 1:7
end end result(r1,c1) = val; mat(rloc,cloc) = inf; endend
if mat(r2,c2) < val val = mat(r2,c2); rloc = r2; cloc = c2; end
outer loops (r1,c1) build resultinner loops (r2,c2) locate minimum
after finding minimum (val, rloc, cloc) “erase” it using infinity
Method 2 – simpler loop and branch using min operator:for r = 1:size(mat,1) for c = 1:size(mat,2) [val,loc] = min(mat(:)); result(r,c) = val; mat(loc) = inf; endend
loops (r,c) still build result
after finding minimum at(loc) erase it using infinityNote scalar addressing into mat
minimum value and locationidentified by array operationNote mat(:)
Example 5: tic-tac-toe winner
• Find the winner in a 3-by-3 tic-tac-toe board. Assume representations:– Empty cell = 0– X = +1– O = – 1
Method 1 – brute force condition testing
if board(1,:)==ones(1,3) disp('X won')elseif board(1,:)==-ones(1,3)
disp('O won')elseif board(2,:)==ones(1,3)
disp('X won')…elseif [board(1,1),board(2,2),board(3,3)] == ……end
16 checks in allProblems: tedious not directly expandable no help on next move
Method 2 – use loops:
for k = 1:3
if board(k,:)==ones(1,3) | board(:,k)==ones(3,1)
disp('X won')
elseif board(k,:)== -ones(1,3) | board(:,k)== -ones(3,1)
disp('O won')
end
end
plus tests for diagonals (no loop advantage here)…
Method 3 – use mask and array operations:
cols = sum(board);rows = sum(board');diag1 = trace(board);diag2 = trace(board(:,[3 2 1]))checks = [ cols, rows, diag1, diag2 ];if any(checks == 3) disp('X won')elseif any(checks == -3) disp('O won')end
–1,0,+1 representationis very useful with summing!
Other array functions simplify the diagonal tests:
diag1 = sum(sum(board.*eye(3,3)));
diag2 = sum(sum(board.*[0 0 1; 0 1 0; 1 0 0]));
diag1 = sum(diag(board));
diag2 = sum(diag(fliplr(board)));
fliplr = flips the array leftto right (also see flipud)
diag grabs just the diagonal elements
Summing allows looking for a potential win:
if any(checks == 3) disp('X won')elseif any(checks == -3) disp('O won')elseif any(checks == -2) disp('X could win now!')elseif any(checks == 2) disp('O could win now')end
function drawgame%DRAWGAME draws the tic-tac-toe boardx = [ -1 -1 4 4]; y = [ -1 4 4 -1];fill(x,y, 'w'); % Use a white box background.hold on
hx1 = [ 0 3 ]; hy1 = [ 1 1 ]; % Horizontal line at y = 1hx2 = [ 0 3 ]; hy2 = [ 2 2 ]; % Horizontal line at y = 2vx1 = [ 1 1 ]; vy1 = [ 0 3 ]; % Vertical line at x = 1vx2 = [ 2 2 ]; vy2 = [ 0 3 ]; % Vertical line at x = 2
plot(hx1,hy1,'k',hx2,hy2,'k',vx1,vy1,'k',vx2,vy2,'k')axis off, axis squarereturn
function [n, m] = getmove(player)%GETMOVE asks a tic-tac-toe player to pick a square.%GETMOVE draws an X on the tic-tac-toe square chosen if player == 1 and a O if player == 2. %GETMOVE returns the indices of the board square selected.
[x y]= ginput(1); % Use cursor to pick a square.m = ceil(x); % m is the column index. It corresponds to x. n = 4 - ceil(y); % n is the row index. It corresponds to 4 - y. % Shift and invert so board does not appear up side down if player == 1 % 1 in the array board, X in figure text(ceil(x)-.5, ceil(y)-0.5, 'X', 'fontsize',20,'horizontalalignment','center', 'color',[0 1 0])endif player == 2 % -1 in the array board, O in figure text(ceil(x)-0.5, ceil(y)-0.5, 'O', 'fontsize',20,'horizontalalignment','center', 'color',[1 0 0])endreturn
[n, m] = getmove(player)
% Lecture 11 demo
board = zeros(3);drawboardplayer = 1;
while any(~all(board)) % Keep going as long as any 0s remain.
[n, m] = getmove(player) player = 3 - player; % player toggles between 1 and 2. board(n,m) = 3 - 2*player; % 3-2*player = either -1 or +1 % 3-2 = 1 if player = 1 and 3-4 = -1 if player = 2endboard
function winner = check4win(board)% CHECK4WIN checks the tic-tac-toe board for a win.
winner = 0;
if any(sum(board)==3) |any(sum(board')==3) | trace(board)==3 |trace(board(:,[3 2 1]))==3 winner = 1; end
if any(sum(board)==-3) |any(sum(board')==-3) | trace(board)==-3 |trace(board(:,[3 2 1]))==-3 winner = 2;end
return
winner = check4win(board)