Тверской государственный университет
Опубликован: 13.09.2006 | Доступ: свободный | Студентов: 5136 / 389 | Оценка: 4.23 / 3.83 | Длительность: 28:12:00
Специальности: Программист, Менеджер
Лекция 2:

Excel для математиков

Задача 12 Решение системы линейных уравнений и обращение матриц

Постановка задачи: Найти решение системы линейных уравнений AX = B

Чтобы одним выстрелом "убить двух зайцев", рассмотрим эту задачу в более общей постановке. Будем полагать, что B - это не вектор правых частей, а матрица из m столбцов, каждый из которых задает правую часть уравнения. Тем самым мы будем решать m систем линейных уравнений с одной и той же левой частью и разными правыми частями. Переход от решения одной системы уравнений к решению m систем сам по себе является важным достоинством рассматриваемого алгоритма. Но более важно то, что здесь же становится возможным находить обратную матрицу для A. Достаточно задать в качестве матрицы правых частей B единичную матрицу E, и тогда матрица X будет обратной к A.

Заголовок функции, решающей эту задачу, имеет такой же вид, как и при умножении матриц и отличается только именем функции:

Function SLEQ(A As Variant, B As Variant) As Variant

Эта функция имеет два входных параметра, - матрицу коэффициентов системы уравнений и матрицу правых частей, и возвращает как результат матрицу X. Конечно, реализация этой функции требует больших усилий, чем умножение матриц. Мне пришлось написать пять процедур, вызываемых в процессе вычислений функции SLEQ. Но сама идея алгоритма достаточно прозрачна. Вначале строится расширенная матрица AB путем присоединения справа матрицы B к матрице A. Затем линейными преобразованиями над ее строками матрица A переводится в единичную матрицу E. Эти же преобразования переводят матрицу B в решение X. Если в качестве B задать единичную матрицу, X будет представлять обратную матрицу. Если B - вектор из одного столбца, то речь идет об обычной системе линейных уравнений. В промежуточном случае B представляет прямоугольную матрицу, и тогда одновременно получа R± ется решение для m систем линейных уравнений. Теперь приведу текст функции SLEQ и прокомментирую его, а затем уже приведу процедуры, вызываемые по ходу работы. Вот текст основной функции, вызываемой в формуле над массивами рабочего листа Excel:

Public Function SLEQ(A As Variant, B As Variant) As Variant
	'Решение системы линейных уравнений: AX = B
	'A - матрица коэффициентов, B - матрица правых частей.
	'X - матрица решений.
	'Для каждого столбца B1 матрицы B соответствующий столбец X1
	'является решением системы AX1 = B1.
	'Если B - единичная матрица E, то X - матрица, обратная к A.
	Dim i As Integer, j As Integer
	Dim N As Integer, M As Integer
	Dim msg1 As String, msg2 As String
	msg1 = " При вызове SLEQ система уравнений линейно зависима!"
	msg2 = " При вызове SLEQ некорректно задана размерность системы уравнений!"
	'Проверка корректности задания размерности СЛУР.
	N = A.Rows.Count
	If (A.Columns.Count = N) And (B.Rows.Count = N) Then
		'Размерность задана корректно.
		M = B.Columns.Count
		ReDim AB(1 To N, 1 To N + M)
		'Построение расширенной матрицы.
		For i = 1 To N
			For j = 1 To N
				AB(i, j) = A.Cells(i, j)
			Next j
		Next i
		For i = 1 To N
			For j = 1 To M
				AB(i, N + j) = B.Cells(i, j)
			Next j
		Next i
		'Цикл линейных преобразований над матрицей AB.
		Dim k As Integer
		Dim Independence As Boolean
		k = 1: Independence = True
		Do
			Independence = FindMax(AB, k, i)
			If Not Independence Then Exit Do
			Call Change(AB, k, i)
			Call Normalization(AB, k)
			Call Linear(AB, k)
			k = k + 1
		Loop While k <= N
		If Not Independence Then MsgBox (msg1)
		
		'Возвращение результата.
		For i = 1 To N
			For j = 1 To M
				AB(i, j) = AB(i, j + N)
			Next j
		Next i
		ReDim Preserve AB(1 To N, 1 To M)
		SLEQ = AB
	Else
		'Некорректно задана размерность.
		MsgBox (msg2)
	End If
	
End Function

Дам теперь необходимые пояснения:

  • В реализации функции можно выделить три основные части: построение расширенной матрицы, цикл линейных преобразований и формирование результирующей матрицы. Для построения расширенной матрицы вводится динамический массив AB. Его заполнение достаточно очевидно. Окончательный результат представляет лишь часть расширенной матрицы и формируется на месте исходной матрицы B. Чтобы выделить эту часть, я использую возможности динамического массива: переопределяю его размерность и затем, используя спецификатор Preserve, сохраняю нужные результаты. Таким образом, новый массив не вводится, а сжимается существующий до нужного размера. Правда, это сжатие возможно лишь для последнего измерения. Поэтому предварительно нужные результаты переписываются в начало массива AB.
  • С содержательной точки зрения основу алгоритма составляет цикл, в котором над матрицей выполняются линейные преобразования. Алгоритм реализует схему Гаусса с выбором главного элемента в столбце. На каждом шаге цикла линейными преобразованиями над строками матрицы ее очередной k -й столбец приводится к единичному столбцу с единицей на диагонали матрицы и остальными нулевыми элементами. Вначале вызывается функция FindMax, которая в k -ом столбце находит максимальный по модулю элемент, расположенный ниже диагонали. Процедура Change меняет строки местами, так чтобы найденный максимальный элемент стал диагональным. Процедура Normalization нормирует k -ю строку делением всех ее элементов на элемент, расположенный на диагонали. Сам этот элемент тем самым становится равным 1. Процедура Linear выполняет линейные преобразования над строками, вычитая из каждой строки k -ю строку, умноженную на подходящий коэффициент, так чтобы сделать нулевыми все элементы k -го столбца, расположенные выше и ниже диагонали.
  • Вначале проверяется корректность задания размерности матриц A и B. Подобная проверка проводилась при умножении матриц. Вторая проверка позволяет обнаружить линейную зависимость строк или столбцов матрицы A. В случае линейной зависимости система уравнений не имеет единственного решения, а обратную матрицу вычислить невозможно.
  • Данная функция является чисто пользовательской, и я ориентируюсь лишь на один способ передачи параметров, - в виде Range -объектов.

Приведу теперь тексты процедур, вызываемых в теле функции SLEQ, и начну с функции FindMax:

Public Function FindMax(A() As Variant, ByVal Num As Integer, _
						Ind As Integer) As Boolean
	'В столбце с номером Num матрицы A, начиная с диагонального элемента,
	'ищется максимальный по абсолютной величине элемент,
	'и вычисляется его индекс Ind.
	'Функция возвращает true, если элемент отличен от нуля.
	Dim i As Integer, Elem As Variant
	Elem = Abs(A(Num, Num)): Ind = Num
	For i = Num + 1 To UBound(A, 1)
		If Abs(A(i, Num)) > Elem Then
			Elem = Abs(A(i, Num)): Ind = i
		End If
	Next i
	FindMax = Not (Elem = 0)

End Function

Прежде всего, заметьте, что в теле пользовательской функции SLEQ вызываются обычные процедуры и функции. Помимо своей основной задачи - нахождения максимального по модулю элемента столбца и определения его индекса Ind, -булева функция FindMax позволяет определить, является ли система уравнений линейно зависимой. Если найденный элемент равен 0, то и все остальные элементы равны 0, а это и есть признак линейной зависимости. Эта проверка предохраняет нас от возможного деления на 0. Конечно, разумнее выполнять не строгую, а слабую проверку на 0, полагая, что система "почти линейно зависима" (плохо обусловлена), если вычисляемый нами элемент близок к 0. Но это уже вычислительные, а не программистские аспекты, которые здесь обсуждать не место. Следующие две процедуры Change и Normalization совсем простые:

Public Sub Change(A() As Variant, _
			ByVal Ind1 As Integer, ByVal Ind2 As Integer)
	'Перестановка строк с индексами Ind1 и Ind2 матрицы A
	Dim i As Integer, Elem As Variant
	If Not (Ind1 = Ind2) Then
		For i = LBound(A, 2) To UBound(A, 2)
			Elem = A(Ind1, i)
			A(Ind1, i) = A(Ind2, i)
			A(Ind2, i) = Elem
		Next i
	End If
End Sub

Public Sub Normalization(A() As Variant, Ind As Integer)
	'Нормировка строки с индексом Ind матрицы A
	'делением на диагональный элемент.
	Dim i As Integer, Elem As Variant
	Elem = A(Ind, Ind): A(Ind, Ind) = 1
	For i = Ind + 1 To UBound(A, 2)
		A(Ind, i) = A(Ind, i) / Elem
	Next i

End Sub

Процедура Linear выполняет линейное преобразование над строками матрицы. Под линейным преобразованием понимается добавление к одной строке матрицы другой строки, умноженной на произвольный коэффициент. Вот текст этой процедуры:

Public Sub Linear(A() As Variant, Ind As Integer)
	'Линейные преобразования над строками матрицы A.
	'В результате столбец Ind становится единичным.
	Dim i As Integer
	For i = 1 To Ind - 1
		Call AddLine(A, Ind, i)
	Next i
	For i = Ind + 1 To UBound(A, 1)
		Call AddLine(A, Ind, i)
	Next i
End Sub

В процедуре Linear поочередно изменяются все строки за исключением строки с номером Ind. Целью линейных преобразований является получение нулей выше и ниже диагонали в столбце с заданным индексом Ind. Для этого в теле Linear организованы два цикла, в которых вызывается процедура AddLine, выполняющая линейное преобразование для заданной строки.

Public Sub AddLine(A() As Variant, _
		ByVal Ind1 As Integer, ByVal Ind2 As Integer)
	'Cтрока с индексом Ind1 с соответствующим коэффициентом
	'вычитается из строки Ind2 матрицы A
	Dim i As Integer, Elem As Variant
	Elem = A(Ind2, Ind1)
	For i = Ind1 To UBound(A, 2)
		A(Ind2, i) = A(Ind2, i) - A(Ind1, i) * Elem
	Next i
End Sub

Нам остается привести результаты тестирования функции SLEQ. Вот как они выглядят на рабочем листе Excel:

Решение m систем линейных уравнений и обращение матриц.

увеличить изображение
Рис. 2.8. Решение m систем линейных уравнений и обращение матриц.

В ячейки рабочего листа я ввел матрицу A, матрицу правых частей B и единичную матрицу E, дав всем этим массивам соответствующие имена. Матрица B состоит из двух столбцов, так что, вызвав функцию SLEQ в формуле над массивами - {=SLEQ(A;B)}, я "одним махом" решил две системы линейных уравнений, получив решение в матрице X, каждый столбец которой является решением соответствующей системы уравнений. Затем, используя в формуле над массивами единичную матрицу E - {=SLEQ(A; E)}, я вычислил матрицу, обратную к A. Для проверки качества решения я, используя вызов MultMatr, умножил матрицу A на полученную обратную матрицу AMinus1, а также A умножил на X. В первом случае получена "почти" единичная матрица (один из элементов не равен точно 0 ), во втором случае результат умножения, как и дол жно, практически совпадает с матрицей B.

Ольга Гафарова
Ольга Гафарова

Добрый день. Подскажите формулы при решении задачи на рис. 2.2 в лекции №2. Закон Ома, какие должны использоваться формулы для I и R

Курс: Основы офисного программирования и документы Excel

Серегй Лушников
Серегй Лушников