본문 바로가기
개발/php, javascript

삼각행렬로 연립방정식 단번에 구하기

by 매몰 2019. 8. 19.

학창 시절.. 행렬이 수학책의 첫 단원이라 본의 아니게 공부했던 기억이 있다.

아마 나만 그랬던 건 아닐 것이다ㅎㅎ

어잿든 십수 년 코딩을 해오면서도 이제야 왜 행렬이 첫 번째인지 그 깊은 뜻이 헤아려진다.

 

머리가 나빠서 이론은 건너뛰고 실전코딩부터 했던터라 지금까지 해 오던 것이

선형대수학의 내용인지조차 몰랐었다.

왜 필요한지도 모른채 행렬부터 공부하다 보니 연결이 어려웠던 걸까..

주입식 교육의 폐해다ㅎㅎ

 

뒤늦게 다시 선형대수학을 공부하며 하나하나 정리해 가고 있는데..

삼각행렬로 연립방정식을 구하는 손쉬운 방법을 소스로 만들어 보았다.

php로 짰지만 다른 언어로도 쉽게 변경 가능하다.

 

//삼각행렬
function triangularMatrix(&$matrix) {
    $j_count = count($matrix);
    $i_count = $j_count - 1;
    
    //위에서 아래행으로 차례로 항 소거
    for ($i = 0; $i < $i_count; $i++) {
        for ($j = $i + 1; $j < $j_count; $j++) {
            if (!eraseComponent($matrix[$i], $matrix[$j], $i)) {
                //기준행과 소거행이 모두 0이면 아래행들과 교환
                $move = $i + 2;
                if ($move < $j_count) {
                    changeValue($matrix[$i], $matrix[$move]);
                    
                    $move = $j + 2;
                    if ($move < $j_count) {    
                        changeValue($matrix[$j], $matrix[$move]);
                    }
                }
                else {
                    //유일한 해가 없음
                    return false;
                }
            }
        }
    }
    
    return true;
}

//항 소거
private function eraseComponent(&$src_row, &$dst_row, $index) {
    if ($src_row[$index] == 0) {
        if ($dst_row[$index] == 0) {
            return false;
        }
        else {
            //항이 0이면 행 교환
            changeValue($src_row, $dst_row);
        }
    }
    else {
        //항을 곱하여 같은수로 맞춘후 소거
        $coef = -($dst_row[$index] / $src_row[$index]);
        foreach ($src_row as $i=>$comp) {
            $dst_row[$i] += ($comp * $coef);
        }
    }
    
    return true;
}

//행 교환
private function changeValue(&$value1, &$value2) {
    $temp = $value1;
    $value1 = $value2;
    $value2 = $temp;
}

//첨가행렬
function augmentedMatrix($matrix, $vector) {
    $a_matrix = Array();
    
    foreach ($matrix as $i=>$row) {
        $a_matrix[$i] = $row;
        
        //마지막 열에 벡터요소 추가
        $a_matrix[$i][count($row)] = $vector[$i];
    }
    
    return $a_matrix;
}

//삼각행렬을 이용해 좌표벡터 추출
function coordinateVectorFromTAM($matrix) {
    $count = count($matrix);
    $vector = array_fill(0, $count, null);
    
    //아래에서 위행으로 차례로 해를 구함
    for ($i = $count - 1; $i >= 0; $i--) {
        if (($vector[$i] = solveEquation($matrix[$i], $vector, $i)) == null) {
            //유일한 해가 없음
            return null;
        }
    }
    
    return $vector;
}

//방정식의 해
private function solveEquation($coefs, $solus, $index) {
    if ($coefs[$index] == 0) {
        return null;
    }
    
    //해가 있는 항의 총합
    $sum = sumArrayWithTimes($solus, $coefs);
    
    //구할 변수의 식으로 정리하여 해를 구함
    return ($coefs[count($coefs) - 1] - $sum) / $coefs[$index];
}

//같은 인덱스의 배열값을 곱한후 모두 더함
private function sumArrayWithTimes($array1, $array2) {
    $sum = 0;
    
    foreach ($array1 as $i=>$value1) {
        $value2 = $array2[$i];
        
        if ($value1 != null && $value2 != null) {
            $sum += ($value1 * $value2);
        }
    }
    
    return $sum;
}

 

 

* 실행하여 확인해 보자

 

//행렬을 무작위로 만든다
function createMatrix($row, $column) {
    for ($i = 0; $i < $row; $i++) {
        for ($j = 0; $j < $column; $j++) {
            $matrix[$i][$j] = rand(-9, 9);
        }
    }
    
    return $matrix;
}

//벡터를 무작위로 만든다
function createVector($length) {
    for ($i = 0; $i < $length; $i++) {
        $vector[$i] = rand(-9, 9);
    }
    
    return $vector;
}

//행렬 출력
function output($matrix, $title = "") {
    echo nl2br("\n$title\n");
    echo "<table>";
    
    foreach ($matrix as $row) {
        echo "<tr>";
        foreach ($row as $column) {
            echo "<td>[$column]</td>";
        }
        echo "</tr>";
    }
    
    echo "</table>";
}

//벡터 출력
function output_v($vector, $title = "") {
    echo nl2br("\n$title\n");
    echo "<table>";
    
    foreach ($vector as $column) {
        echo "<tr><td>[$column]</td></tr>";
    }
    
    echo "</table>";
}

//확인
$matrix = createMatrix(3, 3);
output($matrix, "행렬");

$vector = createVector(3);
output_v($vector, "벡터");

$matrix = augmentedMatrix($matrix, $vector);
output($matrix, "첨가행렬");

triangularMatrix($matrix);
output($matrix, "삼각첨가행렬");

$vector = coordinateVectorFromTAM($matrix);
output_v($vector, "좌표벡터");

 

* 결과다.

 

행렬

[5] [2] [-2]
[-1] [2] [1]
[-2] [-4] [-2]


벡터

[5]
[5]
[7]


첨가행렬

[5] [2] [-2] [5]
[-1] [2] [1] [5]
[-2] [-4] [-2] [7]


삼각첨가행렬

[5] [2] [-2] [5]
[0] [2.4] [0.6] [6]
[0] [0] [-2] [17]


좌표벡터

[-4.25]
[4.625]
[-8.5]

 

 

 

 

도움이 되셨다면~ 정성으로 빚은 저희 앱!  많은 이용 바래요:)

 

https://meorimal.com/index.html?tab=spaceship

 

우주선 - 방치형 인공지능 투자 체험기

미리 맛보는 인공지능 투자!

(주)머리말 meorimal.com

 

https://meorimal.com/subway.html

 

지하철어디있니

더이상 고민하지 마세요. 뛸지 말지 딱 보면 알죠.

(주)머리말 meorimal.com

 

사업자 정보 표시
주식회사 머리말 | 고영진 | 서울특별시 송파구 중대로 135 서관 10층 (가락동, 아이티벤처타워) | 사업자 등록번호 : 524-88-00727 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2017-서울강남-03941호 | 사이버몰의 이용약관 바로가기