НАЦИОНАЛЬНЫЙ ИССЛЕДОВАТЕЛЬСКИЙ ЯДЕРНЫЙ УНИВЕРСИТЕТ «МИФИ» Кафедра информатики и процессов управления (№17) Дисциплина «Прикладное ПО» для студентов факультета КиБ, 3-й курс, 5-й семестр. Методические указания Занятие 3 Решение СЛАУ в среде Octave. Основы программирования. Содержание Решение СЛАУ в среде Octave. Основы программирования. . 1 Решение СЛАУ с помощью обращения матрицы ...................................... 2 Решение СЛАУ методом Гаусса ................................................................... 3 Хранимые программы (процедуры) ............................................................ 4 *.m – файлы ............................................................................................................. 4 Проверка входных данных ................................................................................... 5 Циклы в программах.............................................................................................. 6 Итоговое задание (8 баллов) ........................................................................ 6 Приложение. Экстремальное тестирование задания ............................... 7 1 Решение СЛАУ с помощью обращения матрицы Будем решать систему линейных алгебраических уравнений (СЛАУ), которая в векторно-матричном виде записывается как A*x=b , где A – матрица n x n , b – вектор-столбец свободных членов длиной n, а x – вектор-столбец неизвестных. Введем матрицу А, размером 3 х 3 : > A=[2 -1 5 ; 3 2 -5;1 1 -2] Введем вектор-столбец свободных членов: > b=[ 0 ; 1 ; 4 ] Есть несколько способов записи решения с помощью обратной матрицы. Наиболее компактная форма записи использует операцию обратного деления (x=A\b). Эта же форма является наиболее правильной, поскольку не использует в явном виде промежуточное вычисление обратной матрицы. Поэтому такая форма записи будет работать даже для вырожденных матриц и для неквадратных матриц (для недоопределенных и переопределенных СЛАУ). > x=A\b Альтернативный вариант – наиболее интуитивно понятная форма записи. Здесь используется обратная матрица, такую форму можно использовать только для квадратных невырожденных матриц: > x=A^(-1)*b Octave выдаст тот же ответ x = -2.8333 15.1667 4.1667 Тот же алгоритм и тот же ответ получится еще при двух альтернативных формах записи: > x=A^-1*b > x=inv(A)*b 2 Выполним проверку, перемножим A*x, сравним с введенным значением b: > A*x Полученный ответ визуально совпадает с введенным значением b: ans = -0.0000 1.0000 4.0000 Хотелось бы определить погрешность расчетов, для этого рассчитаем невязку ( A*x – b ): > A*x-b Мы видим, что существует незначительная погрешность, сравнимая с точностью представления чисел: ans = 1.0e-014 * Ответ начинается с общего масштабного множителя, показывающего, что речь идет о невязках в четырнадцатом знаке после запятой. Решение СЛАУ методом Гаусса Обращение матриц большого размера требует значительных вычислительных ресурсов. Для СЛАУ с большим количеством уравнений предпочтительнее использовать метод Гаусса, причем это справедливо не только для Octave, но для любых других средств. В методе Гаусса вводится понятие «Расширенная матрица» n x n+1, которая образуется, если к матрице A справа присоединить вектор свободных членов b. В Octave это записывается как [ A b ]. Метод Гаусса состоит из двух этапов. Первый этап – это прямой ход, в результате которого расширенная матрица системы путём элементарных преобразований (перестановка уравнений системы, умножение уравнений на число отличное от нуля и сложение уравнений) приводится к виду, когда в первых n столбцах - верхнетреугольная матрица. На втором этапе (обратный ход) получившуюся матрицу преобразовывают так, чтобы в первых n столбцах получилась единичная матрица. Последний, n+1 столбец этой матрицы содержит решение первоначальной СЛАУ. Octave содержит встроенный механизм, который полностью автоматизируют вышеописанный алгоритм. Оба этапа реализуются одной функцией rref( ) : > C=rref([A b]) > x= C( : , end ) 3 В описанном выше примере мы выбираем последний столбец (на это указывает служебное слово end в качестве второго индекса) и берем в нем все элементы (символ двоеточие в качестве первого индекса). Рассчитаем невязку ( A*x – b ) для получившегося решения: > A*x-b Ошибка по-прежнему в 14-ом разряде: ans = 1.0e-014 * Теоретически, для СЛАУ с большим количеством уравнений (более чем 200), метода Гаусса должен работать быстрее. Однако в некоторых версиях Octave это не так, вследствие того, что обратное деление в этих версиях реализовано на языке низкого уровня, а rref( ) - на языке высокого уровня. Хранимые программы (процедуры) Если одну и ту же последовательность команд предполагается использовать многократно, то ее можно запомнить в файле и вызывать при появлении необходимости. *.m – файлы Можно создавать текстовые файлы, содержащие код Octave. Если такой файл сохранить в рабочей директории с расширением .m , то его можно будет вызвать, набрав в командной строке имя файла без расширения. В качестве Примера создайте в рабочей директории при помощи редактора файл hello.m следующего содержания: % эта строка -просто комментарий disp('Моя первая программа') date_time = fix(clock) year = input('Введите (полностью) Ваш год рождения: ') ; age = date_time(1) - year ; fprintf('Ваш возраст примерно %u лет.\n', age) ; Сохраните этот файл и запустите на выполнение, набрав в командном окне: > hello 4 Проверка входных данных В программах можно осуществлять проверки условий при помощи операторов if, elseif, else, switch, case, otherwise, end. Также полезно использовать операторы return и error для прерывания программы. Заметим, что не существует оператора goto. Исследуйте особенности работы этих операторов, вставив фрагмент (6 дополнительных строк) между вводом года и вычислением возраста (age): % эта строка -просто комментарий disp('Моя первая программа') date_time = fix(clock) year = input('Введите (полностью) Ваш год рождения: '); if (year < 0) | (year > date_time(1) ) error('неверный год') elseif year < 14 year = year +2000 elseif year < 100 year = year +1900 elseif year < 1900 disp('неверный год'), return else disp('Спасибо, что ввели без ошибок ') end age = date_time(1) - year; fprintf('Ваш возраст примерно %u лет.\n', age); Немного пояснений по поводу добавленных строк. Здесь представлен наиболее полный вариант if, в других случаях отдельные куски конструкции могут быть пропущены, например можно убрать блок else, или блок elseif, или оба. Вертикальная черточка, которая соединяет два условия в первой проверке, означает логическую связку ИЛИ. Вторая и третья проверка позволяет исправить ошибку ввода, если пользователь ввел только последние две цифры года рождения. Сохраните этот файл и запустите несколько раз на выполнение. Исследуйте все ветки if, то есть попробуйте разные варианты ввода, например: -5 11 96 1896 1996 2116 Сделайте заключение о действии использованных конструкций elseif, else, end, disp, return, error. 5 Циклы в программах Octave имеет встроенные средства для обработки матриц и векторов, не прибегая к циклам для перебора индексов. Тем не менее, возможность организовывать циклы также имеется. Циклы, повтор группы команд, обеспечиваются при помощи операторов for, while, break, end . Циклы могут быть вложенными. В качестве Примера будем искать и обнулять в магическом квадрате простые числа. Создайте в рабочей директории при помощи редактора файл prime.m следующего содержания, структурировав циклы и условия отступами, чтобы было видно, что закрывает каждый end : A=magic(4) for m=1:4 for n=1:4 if isprime(A(m,n)) A(m,n) = 0 ; end end end A Немного пояснений. Встроенная функция isprime() проверяет, является ли число простым. Точка с запятой в конце оператора обнуления предотвращает вывод результатов внутри цикла. Итоговый результат выводится вне цикла, для этого в конце программы набрано имя получившейся матрицы A. Запустите созданный файл на выполнение, набрав: prime Как уже говорилось, в Octave можно много сделать, не прибегая к циклам. Например, тот же результат можно получить, используя механизм логической индексации: > A=magic(4) ; > A(isprime(A))=0 Итоговое задание (8 баллов) Используя полученные навыки и знания, напишите программу для решения произвольной СЛАУ. Программа должна запросить и ввести исходные данные, проверить их корректность, например, квадратность и соответствие размерностей. Перед решением СЛАУ необходимо ее проверить. В частности, если матрица вырожденная, то надо выдать соответствующее сообщение и завершить программу. Детерминант вычисляется встроенной функцией det() . Также предварительно надо проверить существование решения. Согласно теории, для этого надо, чтобы ранг матрицы равнялся рангу расширенной матрицы и равнялся размерности матрицы. Ранг вычисляется встроенной функцией rank() . 6 Приложение. Экстремальное тестирование задания Здесь приведены некоторые тестовые СЛАУ для проверки экстремальных случаев. Самый высокий балл получает программа, которая правильно реагирует на все проверки. Баллы A +1 б 1 1 2 1 +1 б 2 1 2 1 +1 б 2 1 2 1 +1 б +1 б +1 б +1 б +1 б +1б 2 2 1 0 1 1 0 1 1 1 1 0 1 1 0 1 1 0 1 2 2 0 1 1 0 1 1 0 1 1 1 1 b 1 2 2 2 2 2 2 2 Должно получиться: текст (если нужен), и ответ: х 1 0 Бесчисленное множество решений. Например, 1 одно из них: 0 Задача некорректна. Вектор b слишком длинный Задача некорректна. Вектор b слишком короткий 2 Бесчисленное множество решений. Например, 0 2 одно из них: 0 2 2 2 2 2 4 2 Решений нет. Минимальной невязка равна 2.333 2 (0.333, 0.333, -0.333) при следующем х: 2.333 5 2 Задача некорректна. Вектор b слишком короткий 2 2 Решений нет. Минимальной невязка равна 3 (0.5, -0.5) при следующем х: 7 1 0.5