Visit http://www.mapleprimes.com/questions/35644-Multiply-2-Matrices-In-Maple-Using-A-Procedure
restart:
mmm:=proc(a::Matrix,b::Matrix)
local c, i, j, k, m, n, p;
(m,n,p):=op([1,1],a), op([1,2],b), op([1,2],a);
if op([1,1],b) <> p then error "incompatible dimensions"; end if;
c:=Matrix(m,n);
for i from 1 to m do
for j from 1 to n do
c[i,j] := add(a[i,k]*b[k,j],k=1..p);
end do;
end do:
c;
end proc:
a:=LinearAlgebra:-RandomMatrix(2,3):
b:=LinearAlgebra:-RandomMatrix(3,5):
mmm(a,b);
a.b; # check
mmm(a,a^%T);
a.a^%T; # check
mmm(b,a); # test for dimension mismatch
b.a; # test for dimension mismatch
a:=LinearAlgebra:-RandomMatrix(33,33):
b:=LinearAlgebra:-RandomMatrix(33,33):
LinearAlgebra:-Norm(a.b - mmm(a,b));
Related
While studying for Matlab, I came up with this problem: given an integer 1<d<15 find the smallest p,q (positive integers) such that abs(p/q-pi)<=10^-d.
So here's my attempt: I first thought that I need to bound p,q in order to create loops, so I put as input data some M,Nupper bounds for p,q respectively. So here is my algorithm:
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
break
end
end
end
What is wrong about it?
Thank you in advance.
The problem lies in the the way you chose to terminate the for loops: break only stops the inner loop. Try this code instead, and check the value of p and q at which the execution stops:
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
[p,q]
error('Found!') % Arrest the program when condition is met
end
end
end
which gives the following output:
Of course, there are better ways of capturing all the possible pairs of integers that meet the condition (e.g. by using disp instead of error). That goes beyond the scope of this answer, but I shall provide a couple of examples here:
clear; clc;
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
pairs = []; % p,q pairs are stored here
k = 1; % counter
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
pairs(k,1) = p;
pairs(k,2) = q;
k = k + 1; % increment the counter
end
end
end
The script above will end quietly: the (p,q) pairs will be stored in the pair matrix.
The following one will print directly the pairs:
clear; clc;
M=input('Give an upper bound for p:')
N=input('Give an upper bound for q:')
d=input('Give a positive integer between 1 and 15:')
for q=1:N
for p=1:M
if abs(pi-p/q)<=10^(-d)
out = sprintf("(%d, %d)", p,q);
disp(out);
end
end
end
For the sake of the experiment, and following up on #Cris Luengo's comment, here's a slightly more elaborate version of the script: the for loops are encapsulated in a dedicated function and a while loop keeps good track of the progress and populates the res matrix with the (p,q) pairs:
clear; clc;
M=input('Give an upper bound for p:');
N=input('Give an upper bound for q:');
d=input('Give a positive integer between 1 and 15:');
close_to_pi = #(px,qx) abs(pi-px/qx)<=10^(-d); % returns true/false
p = 1; q = 1;
count = 0;
res = nan(N*M,2) ; % (p,q) pairs are stored here; preallocate for speed!
tic % starts the timer
while (q <= N)
[p,q, found] = approx_pi(p, q, N, M, close_to_pi);
if found
count = count + 1;
res(count,:) = [p,q]; % populates output var
end
if p<M % we aren't done with p
p = p + 1;
else % reset p and increment q
p = 1;
q = q + 1;
end
end
res(isnan(res(:,1)),:) = []; % gets rid of the empty elements
disp(count)
toc % stops the timer and prints elapsed time
function [p, q, found] = approx_pi(p0, q0, N, M, fun)
for q=q0:N
for p=p0:M
if fun(p,q)
found = 1;
return
end % if
end % for p
p0 = 1;
end % for q
found = 0;
end % approx_pi
If you are interested in continuous fraction approximations of pi, try rat(pi, Tol) where Tol is the tolerance. Further details here.
I'M TRYIN TO CREATE A PROGRAM USING MAPLE FOR GAUSSING ELIMINATION BUT I KEEP GETTING THIS ERROR
Gauss := proc (n::posint, A::matrix, c::Vector)
local a, i, k, j, p;
with(MTM):
n := linalg[rowdim](A);
if det(A) = 0 then print('matrice*doit*etre*caree')
else if det(A) <> 0
then a := `<|>`(A, c);
for k to n-1 do
for i from k+1 to n do
if a[i, i] = 0 then swaprow(a, k, i)
else p = a[i, k]/a[k, k];
for j from k+1 to n+1 do a[i, j] = a[i, j]-p*a[k, j]
end do;
end if;
end do;
end do;
else print('rien')
end if; end if; end proc;
Error, (in Gauss) illegal use of a formal parameter
restart;
Gauss := proc(A::Matrix, c::Vector)
local a, i, k, j, m, n, p;
n := linalg[rowdim](A);
m := linalg[coldim](A);
if m <> n then
print("matrice doit etre caree");
else
a := `<|>`(A, c);
for k to n-1 do
for i from k+1 to n do
if a[i, i] = 0 then
a := linalg[swaprow](a, k, i);
else
p := a[i, k]/a[k, k];
for j from k to n+1 do
a[i, j] := a[i, j]-p*a[k, j];
end do;
end if;
end do;
end do;
end if;
return a;
end proc:
c := Vector([2, 3, 4]);
A := Matrix(3, 3, [4, 1, 2, 3, 6, 5, 2, 1, 9]);
Gauss(A, c);
LinearAlgebra:-LUDecomposition(<A|c>, output=U);
There were quite a few mistakes, so let's hope I get most of them.
I didn't bother doing 7. You should do it.
You cannot use with inside a procedure.
Your code uses commands from thelinalg
package, not the MTM package.
Ideally you'd use Matrix&Vector&LinearAlgebra
(instead of your mix of matrix&Vector&linalg(.
Your procedure has n as one of its
parameters, but inside it you also try to
assign a value to n, the argument for which
you passed in as the number 3. That's where
your error message is coming from. You can't
do that.
Several of you lines have just = instead of
:= for assignments. The = does nothing.
The test against det(A)=0 is wrong is wrong
in several ways. I'll just say that it doesn't
actually test whether the A is square.
Compare the row & column dimensions if you
want to test that A is square.
You should be using LinearAlgebra
equivalents instead of the linalg commands
commands swaprow, coldim.
You forgot to have your procedure actually
return the Matrix a.
When your code calls swaprow is was not
actually updating a. It was just throwing
way the result.
It's a sin to not indent your code. It will
lead you to overlook mistakes.
How is it going guys ?
I've written a program that "draws" diamond in the command line (it's a part of my homework). For spaces inside the diamond I was given a formula "1 + 2(k-2) or 2k -3 , where k is line number", but I don't understand how this formula was created. Could anyone explain it ?
program diamond;
var
n, k, h, i: integer;
begin
repeat
write('Enter the diamond''s height (positive odd): ');
readln(h);
until (h > 0) and (h mod 2 = 1);
n := h div 2;
for k := 1 to n + 1 do
begin
for i := 1 to n + 1 - k do
write(' ');
write('*');
if k > 1 then
begin
for i := 1 to 2*k - 3 do
write(' ');
write('*')
end;
writeln
end;
for k := n downto 1 do
begin
for i := 1 to n + 1 - k do
write(' ');
write('*');
if k > 1 then
begin
for i := 1 to 2*k - 3 do
write(' ');
write('*')
end;
writeln
end
end.
I've already figured it out. It's a simple, but modified arithmetic progression An=A1-d(n-2). Usually we would use (n-1), but because we need to substract 2 stars from each line (starting from the second one, as this formula works for k>1), we use (n-2)
I have been working on a fortran code to convert it into the matlab. I am facing some issues with dimensioning! Following is the code which is giving me error
do 10 p = 1,m
d(p) = 0.d0
d(p) = x - x1(i,p) - x2(i,p) -
& double_sum(i,p,n,m,str,mot)
10 continue
double_sum = 0.d0
do 10 j = 1,m
do 20 k = 1,n
if (k .eq. i) then
else
double_sum = double_sum + mot(k,j,i,p)*str(k,j)
endif
20 continue
10 continue
to which I converted it into matlab as:
for p=1:m
d(p)=0;
double_sum = 0;
for j=1:m
for k=1:n
if k==i
else
double_sum = double_sum + mot(k,j,i,p)*str(k,j);
end
end
end
d(p)=x - x1(i,p) - x2(i,p)-double_sum(i,p,n,m,str,mot);
end
I am getting error of "index exceeding matrix".
The error line is for this part of my code:
d(p)=x - x1(i,p) - x2(i,p)-double_sum(i,p,n,m,str,mot);
So if I ignore double_sum(i,p,n,m,str,mot); this part, code runs perfectly.
I know the double_sum matrix is of 6D which looks suspicious to me, but I would like to have your support to successfully port this piece of fortran code.
Note:Asked the same question on matlab forum. But stackoverflow have more chances of people worked on fortran 77. Hence asking it here.
If the Fortran code in the Question is really everything, it may be a very rough snippet that explains how to calculate array d(:)
do 10 p = 1, m
d( p ) = x - x1( i, p ) - x2( i, p ) - double_sum( i, p, n, m, str, mot )
10 continue
with a function double_sum() defined by
double precision function double_sum( i, p, n, m, str, mot )
implicit none
integer, intent(in) :: i, p, n, m
double precision, intent(in) :: str( n, m ), mot( n, m, ?, ? )
integer j, k
double_sum = 0.d0
do 10 j = 1, m
do 20 k = 1, n
if (k .eq. i) then
else
double_sum = double_sum + mot( k, j, i, p ) * str( k, j )
endif
20 continue
10 continue
end
though it is definitely better to find the original Fortran source to check the context...(including how i and d(:) are used outside this code). Nevertheless, if we use the above interpretation, the corresponding Matlab code may look like this:
for p = 1:m
double_sum = 0;
for j = 1:m
for k = 1:n
if k == i
else
double_sum = double_sum + mot( k, j, i, p ) * str( k, j );
end
end
end
d( p ) = x - x1( i, p ) - x2( i, p ) - double_sum; % <--- no indices for double_sum
end
There is also a possibility that double_sum() is a recursive function, but because we cannot use the function name as the result variable (e.g. this page), it may be OK to exclude that possibility (so the Fortran code has two scopes, as suggested by redundant labels 10).
There is an error in your loops. The fortran code runs one loop over p=1:m, whose end is marked by the continue statement. Then, two nested loops over j and k follow.
Assuming, you know the size of all your arrays beforehand and have initialized them to the correct size (which may not be the case given your error statement) this is more along the lines of the fortran example you posted.
d = zeros(size(d));
for p=1:m
d(p)=x - x1(i,p) - x2(i,p)-double_sum(i,p,n,m,str,mot);
end
% add a statement here to set all entries of double sum to zero
double_sum = zeros(size(double_sum))
for j=1:m
for k=1:n
if k==i
else
double_sum = double_sum + mot(k,j,i,p)*str(k,j);
end
end
end
It is a little hard to give advice without knowledge of more parts of the code. are mot and str and double_sum functions? Arrays? The ambiguous choice of brackets in those two languages are hardly OPs fault, but make it necessary to provide further input.
I have a code for finding the bisection (and it finally works!), but I need to include 3 more things:
output- Root History a vector containing the sequence of midpoints obtained by the algorithm
output- the absolute value of the function
f(x) at r, i.e., fRoot = f(r) input- max iterations
function [R, E] = myBisection(f, a, b, tol)
m = (a + b)/2;
R = m;
E = abs(f(m));
while E(end) > tol
if sign(f(a)) == sign(f(m))
a = m;
else
b = m;
end
m = (a + b)/2;
R = [R, m];
E = [E, abs(f(m))];
end
how do I do this? thanks!!
I have corrected indents an you can see that you've left out end from the end of the function. (it is optional but best not to leave those things out so you know you did not mean to write couple lines to the end but you forgot it.)
R and E should be returned now, if you call myBisection apropriately, that is
[R, E] = myBisection(f, a, b, tol);
If you just call
myBisection(f, a, b, tol)
it will only return R.
To add a limit on the number of iterations, you change while's condition like so:
iter=0;
while (E(end) > tol) && (iter<max_iter)
iter = iter+1;
% ...
end
or it is better to do it in a for loop, with an if plus break:
for iter=1:max_iter
if(E(end) <= tol), break, end;
% ...
end