MỞ ĐẦU Qua hai kỳ học tại trường, với các nền tảng cơ bản đã được học qua các môn như Đại số tuyến tính, Kỹ thuật lập trình hay Cấu trúc dữ liệu, chúng em đã có thể học và xử lý một số b
Trang 1KHOA CÔNG NGHỆ THÔNG TIN
-
-ĐỒ ÁN LẬP TRÌNH
ĐỀ TÀI TÍNH ĐỊNH THỨC CỦA MA TRẬN VUÔNG CẤP N
GVHD: TS Nguyễn Văn Hiệu
Sinh viên thực hiện:
Võ Trần Sơn Phong - Lớp 18T2 - Nhóm 23.16A
Nguyễn Thị Ánh Ngọc - Lớp 23T_DT4 - Nhóm 23.16A
Trang 2MỞ ĐẦU 5
TỔNG QUAN ĐỀ TÀI 6
I CƠ SỞ LÝ THUYẾT 7
1 Ý tưởng 7
2 Cơ sở lý thuyết 7
2.1 Định thức của ma trận vuông 7
2.2 Mảng 7
2.3 Phương pháp khử Gauss 8
2.4 Công thức khai triển Laplace 8
II TỔ CHỨC CẤU TRÚC DỮ LIỆU VÀ THUẬT TOÁN 9
1 Phát biểu bài toán 9
2 Cấu trúc dữ liệu 9
3 Thuật toán 9
3.1 Dùng kỹ thuật biến đổi ma trận về dạng tam giác 9
3.2 Dùng kỹ thuật đệ quy 10
III CHƯƠNG TRÌNH VÀ KẾT QUẢ 11
1 Tổ chức chương trình 11
2 Ngôn ngữ cài đặt 11
3 Kết quả 12
3.1 Giao diện chính của chương trình 12
3.2 Kết quả thực thi của chương trình 12
4 Nhận xét đánh giá 14
Trang 31.2 Chưa đạt được 14
2 Hướng phát triển 15
2.1 Tối ưu hóa thuật toán 15
2.2 Mở rộng chức năng 15
TÀI LIỆU THAM KHẢO 16
PHỤ LỤC 17
Trang 4DANH MỤC HÌNH ẢNH
Hình 1 ………
Hình 2 Phương pháp khử Gauss 7
Hình 3 Công thức khai triển Laplace 12
Hình 4 Giao diện màn hình chính 13
Hình 5 Output 1 13
Hình 6 Output 2 14
Trang 5MỞ ĐẦU
Qua hai kỳ học tại trường, với các nền tảng cơ bản đã được học qua các môn như Đại số tuyến tính, Kỹ thuật lập trình hay Cấu trúc dữ liệu, chúng em đã có thể học và
xử lý một số bài toán cơ bản cũng như biết cách đưa các tư duy giải toán vào lập trình,
từ đó có thể xử lí các bài toán với tốc độ nhanh hơn qua máy tính thay vì tự thực hiện thủ công.
Trong lĩnh vực toán học ứng dụng và khoa học máy tính, định thức của ma trậnvuông cấp n là một khái niệm cơ bản nhưng có ý nghĩa quan trọng và rộng lớn Địnhthức không chỉ là một phép toán cơ bản trong đại số tuyến tính mà còn là một công cụmạnh mẽ được sử dụng trong nhiều lĩnh vực khác nhau như giải hệ phương trình tuyếntính, tính toán giá trị riêng, và xác định tính khả nghịch của ma trận Việc triển khai cácphương pháp tính định thức hiệu quả cho các ma trận kích thước lớn rất cần thiết trongcác ứng dụng thực tiễn như xử lý tín hiệu, mật mã học và mô phỏng khoa học Vì vậy,nhóm chúng em đã chọn đề tài Tính định thức ma trận vuông cấp n nhằm củng cố kiếnthức toán học, nâng cao kỹ năng lập trình, và ứng dụng các thuật toán vào giải quyếtbài toán thực tiễn
Đồ án này sẽ không thể hoàn thành được nếu thiếu sự hỗ trợ của các thầy côhướng dẫn cũng như những người đã tư vấn cho chúng em trong quá trình chúng emlàm đồ án Nhóm chúng em mong rằng đây sẽ là minh chứng cho thành quả dạy dỗ củathầy cô cũng như nỗ lực học tập của chúng em trong suốt thời gian vừa qua
Nhóm chúng em xin chân thành cảm ơn!
Trang 6TỔNG QUAN ĐỀ TÀI
Bài toán tính định thức ma trận vuông cấp n yêu cầu chương trình có khả năng đọc dữ liệu từ file chứa ma trận có sẵn hoặc nhập ma trận từ bàn phím Sau khi nhận dữ liệu, chương trình C sẽ thực hiện các tính toán cần thiết và xuất kết quả ra file hoặc hiển thị trên màn hình Để giải quyết bài toán này, nhóm chúng em đã chọn ra hai phương phápchính:
Phương pháp khử Gauss ( biến đổi về ma trận tam giác )
Công thức khai triển Laplace ( sử dụng kỹ thuật đệ quy )
Dự án này nhằm nghiên cứu và so sánh hai phương pháp tính định thức của ma trận vuông cấp n: phương pháp khử Gauss và công thức khai triển Laplace Chúng em sẽ xây dựng các thuật toán và triển khai chúng trong một ngôn ngữ lập trình để thực hiện các phép tính định thức Bên cạnh đó, dự án cũng sẽ đánh giá hiệu suất và độ phức tạp của hai phương pháp này khi áp dụng cho các ma trận có kích thước khác nhau
Trang 7I CƠ SỞ LÝ THUYẾT
1 Ý tưởng
Phát triển thuật toán khử Gauss:
Viết thuật toán để biến đổi ma trận về dạng tam giác trên
Tính định thức bằng cách nhân các phần tử trên đường chéo chính
Phát triển thuật toán khai triển Laplace:
Viết thuật toán để tính định thức bằng cách khai triển theo hàng hoặc cột
Nếu tất cả phần tử của một dòng (cột) của định thức bằng 0 thì định thức
Trang 8 Phương pháp này là một kỹ thuật biến đổi ma trận về dạng tam giác trên bằng cách
sử dụng các phép biến đổi hàng sơ cấp
Quá trình này bao gồm chọn phần tử trục và thực hiện các phép biến đổi hàng để tạo
ra các số 0 bên dưới phần tử trục đó
Khi ma trận được biến đổi thành dạng tam giác trên, định thức của ma được tính bằng tích của các phần tử trên đường chéo chính
Hình 2 Ma trận tam giác trên
2.4 Công thức khai triển Laplace
Công thức này tính định thức của một ma trận bằng cách khai triển theo một hàng hoặc một cột của ma trận
Định thức của ma trận được tính bằng tổng của các định thức con của ma trận cấp (n−1) nhân với các phần tử tương ứng và hệ số dấu phụ
Trang 9 Công thức này thường được sử dụng cho các ma trận có kích thước nhỏ hoặc khi cần phân tích chi tiết từng phần tử.
Hình 3 Công thức khai triển Laplace
Trang 10II TỔ CHỨC CẤU TRÚC DỮ LIỆU VÀ THUẬT TOÁN
1 Phát biểu bài toán
INPUT
Dòng đầu tiên là số nguyên dương n biểu diễn số bậc của ma trận
Dòng thứ hai gồm n*n số thực là phần tử trong ma trận
Ví dụ: n=55
16.95 61.73 57.77 35.70 82.21 16.42 98.78 28.11 66.72 53.64 86.92 48.04 2.50 13.73 42.07 63.27 53.98 49.91 14.93 40.51 14.72 50.74 82.27 72.14 89.40 OUTPUT
Ghi kết quả số d là định thức của ma trận ra file *.OUT hoặc màn hình
2 Cấu trúc dữ liệu
Để lưu giá trị của các phần tử thuộc ma trận, chúng ta nên sử dụng cấu trúc dữ liệumảng 2 chiều được tổ chức bằng cách sử dụng một mảng con trỏ để lưu trữ mỗi hàngcủa ma trận, và mỗi hàng là một mảng một chiều chứa các phần tử của hàng đó Sửdụng mảng con trỏ kết hợp với cấp phát động cho phép ta linh hoạt trong việc quản lý
bộ nhớ và truy cập vào các phần tử của ma trận, điều này giúp tối ưu hóa hiệu suất vàlinh hoạt trong lập trình trong ngôn ngữ C
Trang 113 Thuật toán
3.1 Dùng kỹ thuật biến đổi ma trận về dạng tam giác
Bước 1:
Duyệt qua từng hàng của ma trận (1)
Kiểm tra phần tử trên đường chéo chính “matrix[i][i]” (được gọi là phần tửtrục) Nếu phần tử trục là 0, đổi chỗ hàng đó với một hàng khác dưới nó
có phần tử trục khác 0 (nếu có) thông qua hàm swap ( đổi chỗ 2 hàng ) (2).Đồng thời, đảo dấu của định thức (theo tính chất của định thức đã đề cập ởmục 2.1) Nếu không tìm thấy hàng khác có phần tử khác 0, định thức của
ma trận sẽ bằng 0 (3)
for (int i = 0; i < n; i++) { (1)
if (matrix[i][i] == 0) { int j;
for (j = i + 1; j < n; j++) {
if (matrix[j][i] != 0) { swap(matrix, i, j, n); (2) det *= -1.0;
break;
} }
if (j == n) return 0; (3)Bước 2:
Duyệt qua các hàng dưới hàng hiện tại (4)
Tính tỷ số giữa phần tử của hàng dưới hàng hiện tại (matrix[j][i]) và phần tử của hàng hiện tại trên đường chéo chính (matrix[i][i]) (5)
Trang 12 Biến k được khởi tạo bằng i để bắt đầu từ cột i, nơi phần tử trên đường chéo chínhcủa hàng hiện tại được đặt Trong mỗi lần lặp, giá trị của k tăng lên một đơn vị, cho phép chúng di chuyển từ cột này sang cột khác trong hàng dưới hàng hiện tại của ma trận Chúng ta sẽ biến các phần tử dưới đường chéo chính bằng 0 bằng cách lấy
Trang 13int m = 0, l = 0;
for (int i = 1; i < n; i++) { for (int k = 0; k < n; k++) {
if (k != j) { (7) sub_matrix[m][l] = matrix[i][k];
Det += ((j % 2 == 0) ? 1 : -1) * matrix[0][j] * Dequy(sub_matrix, n - 1);
III CHƯƠNG TRÌNH VÀ KẾT QUẢ
1 Tổ chức chương trình
Các thư viện có sẵn trong Dev-C++
Định nghĩa các kiểu dữ liệu
Tạo 1 file chứa các giá trị ngẫu nhiên
Chương trình chính
2 Ngôn ngữ cài đặt
Chương trình được viết bằng ngôn ngữ C
Trang 143 Kết quả
3.1 Giao diện chính của chương trình
Hình 4 Giao diện chính của chương trình
3.2 Kết quả thực thi của chương trình
3.2.1 Kết quả xuất ra màn hình
Hình 5 Output 1
3.2.2 Kết quả xuất ra file
Trang 15Hình 6 Output 2
3.3 Nhận xét đánh giá
Đã giải quyết được bài toán và đưa ra kết quả chính xác
So sánh được những ưu và nhược điểm của 2 thuật toán nêu trên
Hiệu suất kém, không phùhợp cho ma trận lớn
IV KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN
1 Kết luận
1.1 Đạt được
Hiểu rõ cách thức hoạt động của 2 thuật toán trên
Biết cách sử dụng các hàm có sẵn, điển hình là clock ( ) để so sánh tốc độ xử lícủa 2 thuật toán
Sử dụng giao diện đồ họa GUI phục vụ cho việc minh họa trở nên dễ hình dung
Giúp cải thiện tư duy và logic của cá nhân
Trang 161.2 Chưa đạt được
Chưa thể giải quyết được bài toán nếu kích cỡ đầu vào n lớn
Bài toán chỉ giải quyết được các bài toán có cấu trúc đơn giản
Giao diện còn cần nhiều cải thiện hơn
2 Hướng phát triển
2.1 Tối ưu hóa thuật toán
Nghiên cứu các kỹ thuật tối ưu hóa thuật toán tính định thức để cải thiện hiệu suất
và tốc độ tính toán, đặc biệt là cho các ma trận có kích thước lớn
Áp dụng các kỹ thuật mới như phân tán tính toán (distributed computing) hoặc sử dụng GPU để tăng cường hiệu suất tính toán
2.2 Ứng dụng thực tế
Ứng dụng trong phân tích dữ liệu: Sử dụng việc tính định thức để xác định tính
khả nghịch của ma trận trong các bài toán liên quan đến hồi quy tuyến tính, phân tích chính thành phần (PCA),
Ứng dụng trong vật lý và kỹ thuật: Tính định thức có thể được áp dụng trong các
bài toán cơ học lượng tử, điều khiển tự động, và các lĩnh vực kỹ thuật khác
Trang 17TÀI LIỆU THAM KHẢO
[1] Mảng (array) trong C,https://viettuts.vn/lap-trinh-c/mang-trong-c
[2] Tài liệu môn Đại số tuyến tính – cô Phan Quan Như Anh (Đại học sư phạm – Đại học Đà Nẵng)
Trang 18double **CopyMatrix(double **matrix, int n);
double Dequy(double **matrix, int n);
double tamgiac(double **matrix, int n);
void NhapMatrixFromString(double **&matrix, int n, const char *matrixString);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTRlpCmdLine, int nCmdShow)
{
const char CLASS_NAME[] = "MatrixDeterminantClass";
WNDCLASS wc = {};
Trang 20CreateWindow("STATIC", "Nhap gia tri ma tran:", WS_VISIBLE | WS_CHILD,
10, 240, 200, 20, hwnd, NULL, NULL, NULL);
hEditMatrix = CreateWindow("EDIT", "", WS_VISIBLE | WS_CHILD |WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL, 10, 270, 460, 200, hwnd,NULL, NULL, NULL);
Trang 21hButtonCalculate = CreateWindow("BUTTON", "Tinh ma tran", WS_VISIBLE |WS_CHILD, 10, 480, 100, 30, hwnd, (HMENU)1, NULL, NULL);
hStaticResult = CreateWindow("STATIC", "Ket qua:", WS_VISIBLE |WS_CHILD, 10, 520, 460, 90, hwnd, NULL, NULL, NULL);
Trang 22clock_t start_tamgiac = clock();
double det1 = tamgiac(matrix, n);
clock_t end_tamgiac = clock();
double time_tamgiac = (double)(end_tamgiac - start_tamgiac) /CLOCKS_PER_SEC;
clock_t start_dequy = clock();
double det2 = Dequy(tmp_matrix, n);
clock_t end_dequy = clock();
double time_dequy = (double)(end_dequy - start_dequy) /CLOCKS_PER_SEC;
Trang 23double **matrix = (double **)malloc(n * sizeof(double *));
for (int i = 0; i < n; i++)
// Function to copy a matrix
double **CopyMatrix(double **matrix, int n)
{
double **temp_matrix = (double **)malloc(n * sizeof(double *));
for (int i = 0; i < n; i++)
{
temp_matrix[i] = (double *)malloc(n * sizeof(double));
Trang 24// Function to calculate the determinant using recursion
double Dequy(double **matrix, int n)
double **sub_matrix = (double **)malloc((n - 1) * sizeof(double *));
for (int i = 0; i < n - 1; i++)
Trang 25{
for (int k = 0; k < n; k++) {
if (k != j) {
sub_matrix[m][l] = matrix[i][k]; l++; if (l == n - 1) {
l = 0; m++; }
}
}
}
Det += ((j % 2 == 0) ? 1 : -1) * matrix[0][j] * Dequy(sub_matrix, n - 1); }
for (int i = 0; i < n - 1; i++) {
free(sub_matrix[i]); }
free(sub_matrix); }
return Det;
}
Trang 26// Function to calculate the determinant using Gaussian elimination
double tamgiac(double **matrix, int n)
Trang 27// Function to fill matrix from a string
void NhapMatrixFromString(double **&matrix, int n, const char *matrixString)
sscanf(matrixString + index, "%lf", &matrix[i][j]);
while (matrixString[index] != ' ' && matrixString[index] != '\0')
{
index++;
}