Mô tả
• Chúng ta có thể định nghĩa hàm bằng cách sử dụng kí hiệu mũi tên (->) nh− vẫn th−ờng làm trong toán học. Công thức định nghĩa hàm f xác định bằng biểu thức bt(x) là f:=x->bt(x); Tên hàm bắt buộc phải nằm bên trái của phép gán (:=), còn định nghĩa hàm ( trong đó sử dụng ->) thì phải nằm ở vế phải phép gán.
• Chú ý rằng bt(x) chỉ có thể là một biểu thức trong Maple (mặc dù có thể gồm nhiều hàm lồng vào nhau) nh−ng không thể là nhiều biểu thức (cách nhau bởi dấu phân cách nh− `;` hoặc `:`). Chẳng hạn ta không thể gán f:=x- >{a:=sin(x);10*a;}. Lệnh này sẽ bị báo lỗi. Muốn khai báo hàm có chứa nhiều biểu thức, ta phải dùng chu trình proc()..end sẽ đ−ợc trình bày ở ch−ơng sau.
• Ngoài toán tử mũi tên, chúng ta cũng có thể sử dụng lệnh unapply để định nghĩa một hàm từ các biểu thức và các tên biến (biến toán học). Khai báo của hàm unapply nh− sau:
unapply(expr,x,y,z,..)
trong đó expr là biểu thức chứa các biến x,y,z,... còn các đối số x,y,z.. là các tên biến.
Kết quả của hàm unapply là một toán tử hàm với các ẩn số là x,y,z,...
• Tuy nhiên vẫn có sự khác biệt giữa khai báo hàm bằng unapply và toán tử mũi tên. Hàm unapply định giá luôn biểu thức dùng để định nghĩa hàm, trong khi khai báo bằng toán tử mũi tên chỉ tạo ra một toán tử hàm trỏ đến
biểu thức đó mà không định giá biểu thức. Ví dụ d−ới sẽ thể hiện rõ điều này.
Minh họa
Định nghĩa hàm qua phép lấy giới hạn, trong đó việc sử dụng toán tử mũi tên chỉ cho kết quả trong đó y là một biểu thức theo x:
[>y:=x->limit((1+x/n)^n,n=infinity); := y x → lim → n ∞ 1 + nx n
Tính giá trị của hàm khi x=-1 bằng lệnh [>x:=-1:
[>y(x);
Nếu sử dụng hàm unapply thì biểu thức đ−ợc định giá thành hàm exp() tr−ớc khi đ−ợc gán cho p: [>p:=unapply(limit((1+z/n)^n,n=infinity),z); := p exp [>z:=-1: [>p(z); e(-1) 3.3.3. Định nghĩa hàm bằng toán tử hợp thành @ Lệnh Toán tử hợp thành: f@g Toán tử hợp thành lặp: f@@n đối số: f,g: là các hàm trong Maple n: một số nguyên Mô tả
• Toán tử hợp thành @ đ−ợc sử dụng giống nh− toán tử hợp thành trong toán học fοg. Ta có thể sử dụng nhiều toán tử hàm liên tiếp để tạo ra một hàm mới.
• Toán tử hợp thành lặp f@@n đ−ợc sử dụng để tạo ra hàm hợp của n hàm f liên tiếp lồng nhau f(f(f(...f(x)))). Ưu điểm của việc sử dụng toán tử này là ta có thể thiết lập một hàm từ số l−ợng lớn các hàm lồng nhau chỉ bằng một lệnh khai báo đơn giản. Tuy nhiên các hàm lồng nhau phải cùng một kiểu hàm, và giá trị của hàm f bắt buộc phải cùng kiểu với đối số.
Minh họa
Định nghĩa hai hàm lồng nhau: [>A:=sin@cos; := A sin cos@ [>A(Pi/3); sin 12
Định nghĩa nhiều hàm lồng nhau: [>B:=sin@exp@max;
:=
[>B(1/2,1/3,1/5);
( ) sin e(1 2/)
Dùng toán tử @@ để định nghĩa nhiều hàm lồng nhau: [>g:=sin@@20; := g sin(20) [>g(Pi/8); (sin(19)) 12 2 − 2
3.3.4. Dùng chu trình proc()...end để tạo hàm
Mô tả
• Cấu trúc proc()...end đ−ợc dùng để định nghĩa hàm bao gồm các lệnh đ−ợc xử lý theo bó (batch processing), tức là thực hiện một dãy các lệnh liên tiếp nhau mà không có sự can thiệp trực tiếp của ng−ời dùng.
• Cấu trúc này đ−ợc sử dụng tiện lợi khi mà ta cần thực hiện những tính toán trong đó không thể thực hiện đ−ợc bằng cách gọi các hàm lồng nhau hoặc bằng cách dùng toán tử định nghĩa hàm -> nh− ở trên, nhất là khi phép tính cần kết hợp kết quả của nhiều hàm để thực hiện một công việc. Khi thực hiện một chu trình của Maple, ta chỉ cần lấy (có thể chỉ là một phần) kết quả của hàm tr−ớc truyền cho hàm tiếp theo, và do đó ta không thể dùng hàm gọi các hàm lồng nhau hay định nghĩa bằng toán tử định nghĩa hàm đơn giản ->
đ−ợc.
• Cấu trúc này là thành phần cơ bản cho lập trình trên Maple. Chi tiết về nội dung và cách sử dụng của cấu trúc proc()..end sẽ đ−ợc trình bày trong ch−ơng sau. Trong phần này, ta chỉ đề cập đến những chu trình đơn giản nhất.
Ví dụ minh hoạ
Để định nghĩa một chu trình bằng cách sử dụng proc()..end ta cần gọi dãy các hàm giữa hai từ khoá proc() và end, tham số của chu trình đ−ợc khai trong dấu ngoặc, tên chu trình đ−ợc gán nh− gán tên các hàm thông th−ờng. Ví dụ sau là một số các chu trình định nghĩa số phức, tính tổng và tính tích hai số phức, lấy phần thực và phần ảo của một số phức. Trong các chu trình này ta chỉ kết hợp việc sử dụng các kết quả của các hàm trong Maple để tính toán:
[>#tao mot so phuc tu phan thuc va ao comp:=proc(r,i)
RETURN([r,i]); end:
#tim phan thuc cua so phuc crel:=proc(c)
RETURN(op(1,c)); end:
#tim phan ao cua so phuc cimg:=proc(c)
RETURN(op(2,c)); end:
#tong cua hai so phuc c_cong:=proc(c1,c2) local r1,i1,r2,i2,c; r1:=crel(c1);i1:=cimg(c1); r2:=crel(c2);i2:=cimg(c2); c:=comp(r1+r2,i1+i2); RETURN(c); end:
#tich cua hai so phuc c_nhan:=proc(c1,c2) local r1,i1,r2,i2,c; r1:=crel(c1);i1:=cimg(c1); r2:=crel(c2);i2:=cimg(c2); c:=comp(r1*r2-i1*i2,r1*i2+r2*i1); RETURN(c); end: [>A:=comp(1,2); := A [1 2, ] [>B:=comp(3.5,-1); := B [3.5 -1, ] [>c_cong(A,B); [4.5 1, ] [>c_nhan(A,B); [5.5 6.0, ]
Các chu trình sẽ mạnh hơn nếu chúng ta kết hợp việc sử dụng các hàm, các toán tử khai báo trong chu trình với lệnh điều kiện và các lệnh lặp nh− trong các ngôn ngữ lập trình truyền thống.
Ví dụ sau đây là một chu trình về việc xây dựng một hàm tính giá trị lớn nhất của ba số thông qua việc sử dụng lệnh điều kiện if..then..else..fi:
[>max3:=proc(a,b,c)
print(`Gia tri lon nhat trong ba so la:`); if a<b then
if b<c then c else b fi; elif a<c then c else a fi; end:
Sau khi khai báo chu trình, ta có thể sử dụng chúng bằng cách gọi chu trình nh−
sau:
[>max3(10,100,-2.34);
Gia tri lon nhat trong ba so la:
100
Sau đây là một ví dụ khác về sử dụng cấu trúc proc()..end để định nghĩa hàm thực hiện tính số hạng thứ n của dãy Fibonaci, là dãy đ−ợc định nghĩa nh− sau: u[0]=1;u[1]:=1;u[n]:=u[n-1]+u[n-2];n>=2; Trong chu trình này ta sử dụng vòng lặp
for..do..od : [>u:=proc(n)
local a,b,c,i; a:=1;b:=1; if n<0 then
print(`Khong co gia tri`); elif n<=1 then
print(`Gia tri thu`,n,`bang:`,a); else for i from 2 to n do c:=a+b;a:=b;b:=c; od; print(c); fi; end:
Gọi chu trình tính giá trị của phần tử thứ n trong dãy: [>u(1000); 70330367711422815821835254877183549770181269836358732742604905 08715453711819693357974224949456261173348775044924176599108818 63632654502236471060120533741212738673391111981393731255987676 90091902245245323403501
3.4. Các cấu trúc dữ liệu cơ bản
3.4.1. Cấu trúc dữ liệu dãy
Lệnh tạo dãy
seq(f(i),i=low..high);
Khai báo này sẽ tạo ra một dãy bằng cách thay thế giá trị i trong f(i) bởi các số nguyên liên tiếp nằm trong giới hạn từ low đến high.
seq(f(x),x=expression);
Khai báo này sẽ tạo ra một dãy mà mỗi thành phần của nó đ−ợc sinh bằng cách cho hàm f tác dụng lên một thành phần (operand) của biểu thức expression. Giá trị của expression th−ờng là một tập hợp hay danh sách nào đó, và cũng có thể là bất cứ cấu trúc dữ liệu nào khác mà lệnh op có thể áp dụng đ−ợc, chẳng hạn nh−
tổng hay tích.
Mô tả
• Dãy(sequence) là một nhóm những đối t−ợng của Maple đ−ợc sắp xếp có thứ tự và ngăn cách nhau bởi dấu phẩy, chẳng hạn nh−a,b,c là một biểu thức dãy. Dãy có thể đ−ợc gán làm giá trị cho các biến, ví dụ ta có thể gán dãy
a,b,c cho biến x bằng lệnh x:=a,b,c.
• Dãy đ−ợc dùng vào nhiều mục đích khác nhau trong trong Maple: dãy đ−ợc dùng để xây dựng tập hợp và danh sách, dãy cũng đ−ợc dùng trong việc truyền đối số cho các hàm có nhiều tham biến. Một số hàm trong Maple cho kết quả d−ới dạng dãy. Chẳng hạn hàm solve() đôi khi cho một dãy các đáp số khi bài toán có nhiều hơn một nghiệm. Khi hàm op() nhận đối số là một biểu thức, nó cũng cho một dãy bao gồm tất cả các thành phần trong biểu thức nhập vào. Kí hiệu đặc biệt NULL thay thế cho dãy trống (dãy không chứa gì cả). Sự định giá hoàn toàn (full evaluation) đ−ợc Maple tự động áp dụng trong quá trình tạo ra dãy, do vậy dãy các dãy đ−ợc đơn giản thành một dãy. Chẳng hạn, nếu biến s1 đ−ợc gán bởi dãy a,b,c trong đó a,b,c là các biến ch−a đ−ợc gán giá trị thì lệnh s2:=s1,d sẽ gán cho biến s2 dãy a,b,c,d
và s3:=s1,NULL,s1; sẽ gán cho biến s3 dãy a,b,c,a,b,c.
• Các hàm op() và nops() không đ−ợc phép sử dụng cho dãy. Nguyên nhân là do Maple dùng các dãy làm đối số truyền cho các hàm. Do đó, lời gọi hàm:
op(s1) đ−ợc định giá thành: op(a,b,c), nh−ng do hàm op chỉ nhận nhiều nhất là hai đối số: đối số đầu là một số nguyên hay một phạm vi số (tức là một
mảng số nguyên liên tiếp, thí dụ nh− 2..4 là mảng các số nguyên trong phạm vi từ 2 đến 4), còn đối số thứ hai là một biểu thức, do đó lệnh trên sẽ bị Maple báo lỗi.
• Chu trình seq() rất thuận tiện cho việc tạo ra một dãy các phần tử phụ thuộc tham số. Nh− trình bày ở phần khai báo, seq() sẽ tạo ra một dãy các phần tử theo một công thức hay một phép gán nào đó. Thông qua sự biến đổi các chỉ số trong phạm vi các số nguyên cho một biểu thức, ta thu đ−ợc một dãy (hay nói cách khác, trong tr−ờng hợp này có thể xem dãy nh− là tập giá trị của một hàm trên một dải số nguyên nào đó). Xem ví dụ d−ới đây để biết thêm chi tiết.
Minh họa
Lệnh seq() thực hiện khá giống lệnh sum() trong việc áp dụng mỗi giá trị của chỉ mục trong phạm vi cho tr−ớc vào hàm để thu đ−ợc các phần tử của dãy:
[>seq(2*i,i=1..10); , , , , , , , , , 2 4 6 8 10 12 14 16 18 20 [>tong:=sum(i^2,i=1..n); := tong 13(n + 1)3 − 1 + + 2(n + 1)2 1 6n 1 6 [>seq(op(j,tong),j=1..4); , , , 1 3(n + 1)3 −12(n + 1)2 1 6n 1 6
seq() tạo ra một dãy bằng cách tác dụng hàm f lên mỗi thành phần của danh sách
cho tr−ớc x: [>x:=[seq(Pi/i,i=1..9)]; := x π,1 , , , , , , , 2π 1 3π 1 4π 1 5π 1 6π 1 7π 1 8π 1 9π [>y:=seq(sin(i)+a,i=x); := , 1+ y a a,1 . 3 , . 2 2 + 1 + 2 a a, 1 2. 5− 5+ 4 a, , sin 7 π + + 1 2 a a, 1 2− 2+ 2 a, sin 9 π + a
3.4.2. Cấu trúc tập hợp và danh sách
Tập hợp
• Cấu trúc dữ liệu tập hợp(set) trong Maple đ−ợc dùng để gom các đối t−ợng phân biệt vào trong cùng một nhóm gọi là tập hợp. Tập hợp đ−ợc tạo thành bằng cách bao quanh một dãy trong cặp dấu ngoặc móc ('{ }'). Giống nh− hầu hết các đối t−ợng khác trong Maple, ta có thể gán Tập hợp cho các biến, và có thể sử dụng tập hợp nh− là đối số hoặc là kết quả của một số hàm. Tập hợp khác danh sách ở chỗ, các phần tử trong một tập hợp phải phân biệt nhau.
• Các phép toán đ−ợc sử dụng cho kiểu tập hợp: union (hợp của hai tập hợp),
intersect (giao của hai tập hợp), minus (hiệu của hai tập hợp). Tập hợp rỗng đ−ợc kí hiệu là {}.
• Trật tự của các phần tử trong tập hợp đ−ợc quyết định bởi hệ thống. Giống nh− các số hạng trong một tổng, trật tự của một tập hợp thì không thay đổi trong mỗi lần tính toán, nh−ng lại thay đổi giữa các phiên (session) tính toán, và
giữa các máy khác nhau. Vì vậy, một tập hợp có thể đ−ợc in là
{x,y,z}trong lần tính toán này, trong khi ở lần khác nó có thể xuất hiện d−ới dạng {z,y,x}. Nếu bạn muốn có một trật tự rõ ràng cho các phần tử, hãy dùng một danh sách để l−u dữ liệu.
Danh sách
• Danh sách (list) là một cấu trúc dữ liệu trong Maple dùng để gom các đối t−ợng (có thể giống nhau hoặc khác nhau) thành một danh sách.
• Giống nh− cấu trúcdãy, danh sách l−u giữ dữ liệu theo trật tự nh− khi đ−ợc tạo ra. Hai giá trị giống nhau có thể đ−ợc l−u trữ trong cùng một danh sách, trong khi đó chúng sẽ bị loại bỏ bớt đi một nếu chúng đ−ợc l−u trữ trong cùng một
tập hợp. Các toán tử dùng trong cấu trúc tập hợp: union, intersect, minus
không đ−ợc định nghĩa cho danh sách.
• Một danh sách có thể đ−ợc tạo ra bằng cách bao quanh một dãy bằng cặp dấu ngoặc vuông ([ ]), và khi ấy nó không còn là một dãy. Ng−ời ta th−ờng sử dụng danh sách để nhóm các đối t−ợng với nhau khi mỗi nhóm đ−ợc xem nh− là một đối số đơn của một hàm nào đó.
• Để minh hoạ cho sự khác nhau giữa dãy và danh sách trong Maple, ta xét lệnh
x:=[a,b],[b,c], khi đó a sẽ đ−ợc gán là dãy của hai danh sách x:=[a,b],[b,c] , trong khi đó x:=(a,b),(b,c) thì kết quả gán cho x sẽ tự động nối lại thành dãy đơn x:=a,b,b,c.
• Hàm op() đ−ợc dùng để rút ra một thành phần trong một biểu thức, và do đó ta có thể sử dụng nó để lấy ra một thành phần trong một danh sách: phần tử thứ i do hàm op() cho chính là đối t−ợng thứ i trong danh sách hay tập hợp, theo trật tự phụ thuộc việc bạn thấy tập hợp và danh sách đ−ợc in ra nh− thế nào. Chẳng hạn khi bạn gán x:=[a,b,d,c] thì lệnh này in ra màn hình là x:=[a,b,d,c], khi đó lệnh y:=op(3,x) sẽ cho lại kết quả y:=d.
• Việc ghép 2 dãy nhỏ thành một dãy to là khá đơn giản (xem phần trên). Nh−ng để gộp (involving) hai hay nhiều danh sách (hoặc là tập hợp) với nhau để tạo ra một danh sách (hay tập hợp) mới thì không đơn giản nh− vậy. Muốn làm điều này ta tiến hành qua 3 b−ớc: tr−ớc hết ta biến đổi chúng thành các dãy
(bằng lệnh seq()), rồi dùng lệnh ghép các dãy nhỏ thành dãy to, sau đó biến đổi dãy thành một danh sách (hoặc tập hợp) bằng cách đ−a chúng vào trong cặp dấu ngoặc thích hợp. Để hiểu rõ thêm, xin xem trong phần ví dụ.
• Toán tử [] dùng để tham chiếu đến một phần tử của một danh sách, tập hợp. Ví dụ, ta có ds=[a,b,d,c] là một danh sách, lời gọi y:=ds[2] sẽ cho ta kết quả là y=b. Ta cũng có thể dùng toán tử trên để thay đổi giá trị của một phần tử trong danh sách nh−ng không thể dùng lệnh này để thay đổi bất cứ phần tử nào trong tập hợp. Chẳng hạn đối với danh sách ds=[a,b,d,c] trên, lệnh
ds[2]:=e sẽ thay giá trị b của phần tử thứ 2 trong danh sách ds thành e, vì vậy danh sách trở thành x=[a,e,d,c], trong khi đó đối với tập hợp y:={a,b,d,c} thì lệnh y[2]:=e sẽ báo lỗi.
• Hàm subsop() đ−ợc dùng để tạo ra một danh sách hay tập hợp mới bằng cách thay thế một hay nhiều phần tử của một danh sách hay một tập hợp đã cho nào đó. Xem cụ thể hơn ở phần sau.
Lệnh tạo danh sách và tập hợp
• Ta đã biết cách tạo một dãy bằng lệnh seq() hoặc bằng cách liệt kê các phần tử. Một cách thông th−ờng để tạo ra một danh sách (hay là một tập hợp) là tạo từ một dãy bằng cách đ−a nó vào trong một cặp dấu ngoặc t−ơng ứng.
• Một cách khác để tạo một danh sách(tập hợp) là tìm cách biến đổi một hay một số phần tử của một danh sách(tập hợp) đã có sẵn. Lệnh supsop đ−ợc mô tả sau đây cho phép thay thế một số thành phần của danh sách đã cho bằng một số thành phần khác: subsop(index = replacement, expression).Trong lệnh này, tham biến expression có thể nhận giá trị là một biểu thức, thành phần tại vị trí index trong biểu thức expression
đ−ợc thay bởi giá trị mới là replacement. Nh− vậy, hàm supsop() tạo ra một biểu thức hoàn toàn mới giống biểu thức mẫu, trừ phần tử bị thay thế. Lệnh supsop(i=NULL,ds) dùng để xoá thành phần thứ i trong ds.
• Hàm subsop(index1=repl1,...indexn=repln,expr) cho phép tạo ra biểu thức mới bằng cách thay thế n giá trị tại n vị trí trong biểu thức
expr. Minh họa [>restart; Khai báo tập hợp: [>taphop1:={a,b,c}; := taphop1 {a b c, , } [>taphop2:={a,d,e};
:=
taphop2 {e a d, , }
[>taphop3:={e,f};
:=
taphop3 {e f, }
Thực hiện các phép toán trên tập hợp: [>taphop4:=taphop1 union taphop2;
:=
taphop4 {e a b c d, , , , }
[>taphop5:=taphop2 intersect taphop3;
:=
taphop5 { }e
[>taphop6:=taphop1 minus taphop2;
:=
taphop6 {b c, }
[>taphop6[2];
c
Khai báo các danh sách: [>list01:=[x,y,z]; := list01 [x y z, , ] [>list02:=[z,t,u,v]; := list02 [z t u v, , , ]