0
0
Lập trình
TT

Xây dựng Trình Kiểm Tra Dạng Echelon Hàng trong Python và Go

Đăng vào 3 tuần trước

• 11 phút đọc

Giới thiệu

Dạng echelon hàng (Row Echelon Form - REF) là một khái niệm quan trọng trong đại số tuyến tính, giúp đơn giản hóa ma trận trong các phép toán như loại trừ Gaussian. Bài viết này sẽ hướng dẫn bạn xây dựng một hàm kiểm tra để xác minh xem một ma trận có ở dạng echelon hàng hay không, theo các quy tắc cụ thể. Chúng ta sẽ triển khai hàm này bằng Python và Go, thêm các trường hợp kiểm tra, và khám phá chi tiết với các ví dụ thực tế.

Hiểu Rõ Về Dạng Echelon Hàng

Dạng echelon hàng (REF) cấu trúc một ma trận sao cho mỗi hàng bắt đầu bằng các số không, tiếp theo là một phần tử khác không (nếu có), và các phần tử khác không này được sắp xếp theo cách chéo. Dạng này giúp trong việc giải các hệ phương trình bằng cách làm cho việc thay thế ngược trở nên dễ dàng hơn.

Một ma trận trong REF trông như thế này:

Copy
[ 1, 2, 3 ]
[ 0, 1, 4 ]
[ 0, 0, 1 ]

Trong đó, các phần tử khác không nằm ở cột 1, 2 và 3. Không phải tất cả các ma trận REF đều có phần tử khác không bắt đầu từ 1; chúng có thể là bất kỳ giá trị khác không nào, nhưng thường được chuẩn hóa thành 1 trong dạng REF thu gọn (mà chúng ta không áp dụng ở đây).

Để biết thêm về định nghĩa chính thức, bạn có thể tham khảo trang Wikipedia về Dạng Echelon Hàng.

Các Quy Tắc Chính Cho Trình Kiểm Tra REF

Trình kiểm tra của chúng ta áp dụng các quy tắc sau:

  • Các hàng tất cả là số không ở phía dưới: Bất kỳ hàng nào có tất cả các phần tử bằng 0 phải xuất hiện sau tất cả các hàng không phải là số không.
  • Tiến trình phần tử khác không sang bên phải: Phần tử khác không đầu tiên (phần tử chốt) trong mỗi hàng phải nằm bên phải phần tử chốt trong hàng phía trên.

Chúng ta không quan tâm đến việc các phần tử chốt có bằng 1 hay không, hoặc nếu các phần tử trên các phần tử chốt là số không - đó là cho REF thu gọn. Mục tiêu của chúng ta là REF nghiêm ngặt.

Hãy xem xét ví dụ không hợp lệ này do hàng tất cả là số không bị đặt sai:

Hàng Phần tử
1 [0, 0, 0]
2 [0, 1, 2]
3 [0, 0, 3]

Ví dụ này vi phạm quy tắc đầu tiên. Một phiên bản hợp lệ sẽ di chuyển hàng tất cả là số không xuống dưới và sau đó hoán đổi hàng 1 và hàng 2.

Triển Khai Trình Kiểm Tra Trong Python

Trong Python, chúng ta sẽ đại diện cho các ma trận dưới dạng danh sách của danh sách. Hàm sẽ lặp qua các hàng, theo dõi cột phần tử chốt cuối cùng, và kiểm tra xem có hàng tất cả là số không nào không đúng vị trí.

Dưới đây là hàm hoàn chỉnh:

python Copy
def is_row_echelon_form(matrix):
    if not matrix or not matrix[0]:
        return True  # Ma trận rỗng thì tự động ở REF

    rows = len(matrix)
    cols = len(matrix[0])

    # Đảm bảo tất cả các hàng có cùng số cột
    for row in matrix:
        if len(row) != cols:
            return False

    last_pivot_col = -1
    seen_zero_row = False

    for i in range(rows):
        # Tìm vị trí phần tử chốt trong hàng này
        pivot_col = -1
        for j in range(cols):
            if matrix[i][j] != 0:
                pivot_col = j
                break

        if pivot_col == -1:  # Hàng tất cả là số không
            seen_zero_row = True
            continue  # Hàng tất cả là số không được chấp nhận ở dưới, kiểm tra sau

        if seen_zero_row:
            return False  # Hàng không phải là số không sau hàng số không

        if pivot_col <= last_pivot_col:
            return False  # Phần tử chốt không nằm bên phải

        last_pivot_col = pivot_col

    return True

# Ví dụ sử dụng:
# matrix = [[1, 2, 3], [0, 1, 4], [0, 0, 1]]
# print(is_row_echelon_form(matrix))  # Đầu ra: True

Mã này xử lý các ma trận rỗng và đảm bảo chiều dài hàng đồng nhất. Nó theo dõi last_pivot_col để thực thi quy tắc phần tử chốt và seen_zero_row để kiểm tra vị trí số không.

Kiểm Tra Triển Khai Python

Các trường hợp kiểm tra bao gồm REF hợp lệ, vị trí phần tử chốt không hợp lệ, các hàng số không bị đặt sai, và các trường hợp biên như ma trận đơn hàng hoặc ma trận rỗng.

Sử dụng unittest của Python cho các bài kiểm tra có cấu trúc. Đây là một kịch bản kiểm tra hoàn chỉnh:

python Copy
import unittest

class TestRowEchelonForm(unittest.TestCase):
    def test_valid_ref(self):
        matrix = [[1, 2, 3], [0, 1, 4], [0, 0, 1]]
        self.assertTrue(is_row_echelon_form(matrix))

    def test_invalid_pivot_position(self):
        matrix = [[1, 2, 3], [1, 1, 4], [0, 0, 1]]  # Vị trí phần tử chốt hàng thứ hai không đúng
        self.assertFalse(is_row_echelon_form(matrix))

    def test_misplaced_zero_row(self):
        matrix = [[0, 0, 0], [0, 1, 2], [0, 0, 3]]
        self.assertFalse(is_row_echelon_form(matrix))

    def test_all_zero_rows(self):
        matrix = [[0, 0], [0, 0]]
        self.assertTrue(is_row_echelon_form(matrix))

    def test_empty_matrix(self):
        matrix = []
        self.assertTrue(is_row_echelon_form(matrix))

    def test_single_row(self):
        matrix = [[1, 2, 3]]
        self.assertTrue(is_row_echelon_form(matrix))

    def test_uneven_rows(self):
        matrix = [[1, 2], [0, 1, 3]]  # Chiều dài không đồng nhất
        self.assertFalse(is_row_echelon_form(matrix))

if __name__ == '__main__':
    unittest.main()

# Khi chạy, tất cả các kiểm tra sẽ phải vượt qua ngoại trừ các kiểm tra không hợp lệ, mà sẽ thất bại đúng cách.

Những bài kiểm tra này đảm bảo rằng hàm hoạt động như mong đợi. Chạy kịch bản này để xác minh - bạn sẽ thấy 7 bài kiểm tra, không có thất bại nếu thực hiện đúng.

Để biết thêm thông tin về tài liệu kiểm tra Python, hãy xem phần unittest trong tài liệu Python.

Chuyển Đổi Trình Kiểm Tra Sang Go

Go sử dụng các lát (slices) của các lát cho ma trận. Logic tương tự như Python nhưng với hệ thống kiểu của Go và xử lý lỗi cho các hàng không đồng nhất.

Dưới đây là hàm đầy đủ trong gói chính:

go Copy
package main

import "fmt"

func isRowEchelonForm(matrix [][]int) bool {
    if len(matrix) == 0 || len(matrix[0]) == 0 {
        return true // Ma trận rỗng thì ở REF
    }

    rows := len(matrix)
    cols := len(matrix[0])

    // Kiểm tra tất cả các hàng có cùng số cột
    for _, row := range matrix {
        if len(row) != cols {
            return false
        }
    }

    lastPivotCol := -1
    seenZeroRow := false

    for i := 0; i < rows; i++ {
        // Tìm cột phần tử chốt
        pivotCol := -1
        for j := 0; j < cols; j++ {
            if matrix[i][j] != 0 {
                pivotCol = j
                break
            }
        }

        if pivotCol == -1 { // Hàng tất cả là số không
            seenZeroRow = true
            continue
        }

        if seenZeroRow {
            return false // Hàng không phải là số không sau hàng số không
        }

        if pivotCol <= lastPivotCol {
            return false // Không nằm bên phải
        }

        lastPivotCol = pivotCol
    }

    return true
}

func main() {
    matrix := [][]int{{1, 2, 3}, {0, 1, 4}, {0, 0, 1}}
    fmt.Println(isRowEchelonForm(matrix)) // Đầu ra: true
}

Phiên bản này sử dụng số nguyên để đơn giản; điều chỉnh thành số thực nếu cần cho các ma trận thực. Biên dịch và chạy với go run main.go.

Kiểm Tra Triển Khai Go

Gói testing trong Go xử lý các bài kiểm tra. Chúng ta sẽ làm tương tự như các trường hợp trong Python.

Tạo một tệp main_test.go:

go Copy
package main

import "testing"

func TestIsRowEchelonForm(t *testing.T) {
    tests := []struct {
        name    string
        matrix  [][]int
        want    bool
    }{
        {"valid_ref", [][]int{{1, 2, 3}, {0, 1, 4}, {0, 0, 1}}, true},
        {"invalid_pivot", [][]int{{1, 2, 3}, {1, 1, 4}, {0, 0, 1}}, false},
        {"misplaced_zero", [][]int{{0, 0, 0}, {0, 1, 2}, {0, 0, 3}}, false},
        {"all_zeros", [][]int{{0, 0}, {0, 0}}, true},
        {"empty", [][]int{}, true},
        {"single_row", [][]int{{1, 2, 3}}, true},
        {"uneven_rows", [][]int{{1, 2}, {0, 1, 3}}, false},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := isRowEchelonForm(tt.matrix); got != tt.want {
                t.Errorf("isRowEchelonForm() = %v, want %v", got, tt.want)
            }
        })
    }
}

// Chạy với 'go test' - mong đợi tất cả các bài kiểm tra sẽ vượt qua.

Phương pháp kiểm tra theo bảng này giúp việc thêm các trường hợp trở nên dễ dàng. Sử dụng go test để thực hiện - hãy tìm đầu ra "ok".

Xem gói kiểm tra của Go trong tài liệu chính thức.

So Sánh Cách Tiếp Cận Giữa Python và Go

Việc sử dụng kiểu động trong Python giúp đơn giản hóa việc xử lý ma trận, trong khi Go yêu cầu kiểm tra rõ ràng cho chiều dài lát. Cả hai đều sử dụng vòng lặp tương tự, nhưng hiệu suất của Go nổi bật cho các ma trận lớn nhờ vào việc biên dịch.

Khía cạnh Python Go
Đại diện Ma trận Danh sách của danh sách Lát của lát
Xử lý Kiểu Linh hoạt (int/float) Cố định (int ở đây; sử dụng float64)
Kiểm tra Lỗi Kiểm tra độ dài tại thời điểm chạy Kiểm tra độ dài tại thời điểm chạy
Kiểm Tra Dựa trên lớp unittest Dựa trên bảng với t.Run

Python cảm thấy nhanh hơn cho việc lập trình thử nghiệm, trong khi Go phù hợp hơn cho sản xuất với các kiểu chặt chẽ.

Xử Lý Các Trường Hợp Biên Trong Cả Hai Ngôn Ngữ

Các trường hợp biên bao gồm các ma trận không vuông, như [1,0],[0,0],[0,0] hoặc [0,1],[1,0].

Trong mã, các triển khai của chúng ta xử lý những điều này: ma trận không vuông hoạt động miễn là các hàng đồng nhất. Đối với số thực, thay đổi các phép so sánh (ví dụ: sử dụng epsilon cho số không).

Thêm kiểm tra: Một ma trận với các số không ở đầu hàng nhưng có các phần tử chốt đúng, như [[0,1,2],[0,0,3]] - hợp lệ, cột chốt 1 và 2.

Cả hai ngôn ngữ đều vượt qua kiểm tra này mà không cần thay đổi. Đối với các ma trận lớn, hãy xem xét hiệu quả; độ phức tạp O(rows * cols) là ổn cho hầu hết các mục đích.

Việc xây dựng trình kiểm tra này củng cố các kiến thức cơ bản về đại số tuyến tính và kỹ năng đa ngôn ngữ. Bạn có thể điều chỉnh nó cho dạng REF thu gọn bằng cách thêm kiểm tra cho pivot=1 và các số không ở trên các phần tử chốt. Hãy kiểm tra kỹ lưỡng trong các dự án của bạn để phát hiện sớm các vấn đề về ma trận.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào