Программирование в Scilab Микаэль Боден Micha
Скачать 1.35 Mb.
|
Программирование в Scilab Микаэль Боден (Micha¨ el Baudin) Сентябрь 2011 года Аннотация В этом документе мы представляем программирование в Scilab 1 . В первой части мы представляем управление памятью в Scilab. Во второй части мы представляем различ- ные типы данных и анализируем методы программирования, связанные с теми структу- рами данных. В третьей части мы представляем характеристики для разработки гибких и устойчивых функций. В последней части мы представляем методы, которые позво- ляют получить наилучшие характеристики, основанные на вызовах высокооптимизи- рованных числовых библиотек. Предоставляется много примеров, которые позволят увидеть эффективность методов, которые мы представляем. 1 Прим. перев. — произносится «сайлаб» 1 Содержание 1 Введение 6 2 Управление переменными и памятью 6 2.1 Стек 6 2.2 Подробнее об управлении памятью 9 2.2.1 Ограничения памяти со стороны Scilab 9 2.2.2 Ограничения памяти в 32 х - и 64 х -битных системах 11 2.2.3 Алгоритм в stacksize 12 2.3 Список переменных и функция who 12 2.4 Переносимость переменных и функций 13 2.5 Уничтожение переменных : clear 16 2.6 Функции type и typeof 17 2.7 Заметки и ссылки 18 2.8 Упражнения 18 3 Специальные типы данных 19 3.1 Строки 19 3.2 Многочлены 22 3.3 Гиперматрицы 26 3.4 Типы и размерности выделенной гиперматрицы 28 3.5 Тип данных list (список) 31 3.6 Тип данных tlist 33 3.7 Имитация объектно-ориентированного программирования с помощью типизи- рованных списков 37 3.7.1 Ограничения позиционных аргументов 37 3.7.2 Класс «person» в Scilab 38 3.7.3 Расширение класса 41 3.8 Перегрузка типизированных списков 42 3.9 Тип данных mlist 44 3.10 Тип данных struct 45 3.11 Массив структур struct 46 3.12 Тип данных cell 48 3.13 Сравнение типов данных 50 3.14 Заметки и ссылки 51 3.15 Упражнения 52 4 Управление функциями 53 4.1 Продвинутое управление функциями 54 4.1.1 Как сделать запрос о функции 54 4.1.2 Функции не зарезервированы 56 4.1.3 Функции — это переменные 57 4.1.4 Функции обратного вызова 58 4.2 Разработка гибких функций 59 4.2.1 Обзор функции argn 60 4.2.2 Практические вопросы 61 4.2.3 Использование переменных аргументов на практике 64 2 4.2.4 Значения по умолчанию для необязательных аргументов 67 4.2.5 Функции с переменным типом входных аргументов 69 4.3 Устойчивые функции 71 4.3.1 Функции warning и error 71 4.3.2 Общая схема для проверок входных аргументов 73 4.3.3 Пример устойчивой функции 74 4.4 Использование parameters 75 4.4.1 Обзор модуля 75 4.4.2 Практический случай 78 4.4.3 Проблемы с модулем parameters 81 4.5 Область видимости переменных в стеке вызовов 83 4.5.1 Обзор области видимости переменных 83 4.5.2 Плохая функция: неоднозначный случай 85 4.5.3 Плохая функция: случай тихого обрушения 86 4.6 Проблемы с функциями обратного вызова 89 4.6.1 Бесконечная рекурсия 89 4.6.2 Неправильный индекс 91 4.6.3 Решения 92 4.6.4 Функции обратного вызова с дополнительными аргументами 93 4.7 Мета-программирование: execstr и deff 95 4.7.1 Основное использование execstr 95 4.7.2 Основное использование deff 97 4.7.3 Практический пример оптимизации 98 4.8 Заметки и ссылки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 5 Производительность 102 5.1 Измерение производительности . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 5.1.1 Основные применения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 5.1.2 Пользовательское время и время ЦП . . . . . . . . . . . . . . . . . . . . 104 5.1.3 Профилирование функции . . . . . . . . . . . . . . . . . . . . . . . . . . 105 5.1.4 Функция benchfun . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 5.2 Основы векторизации . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 5.2.1 Интерпретатор . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 5.2.2 Циклы в сравнении с векторизацией . . . . . . . . . . . . . . . . . . . . 115 5.2.3 Пример анализа производительности . . . . . . . . . . . . . . . . . . . . 116 5.3 Уловки оптимизации . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 5.3.1 Опасность динамических матриц . . . . . . . . . . . . . . . . . . . . . . 118 5.3.2 Линейная индексация матрицы . . . . . . . . . . . . . . . . . . . . . . . 120 5.3.3 Обращение через матрицу логических значений . . . . . . . . . . . . . . 122 5.3.4 Повтор строк или столбцов вектора . . . . . . . . . . . . . . . . . . . . . 123 5.3.5 Комбинирование векторизованных функций . . . . . . . . . . . . . . . . 123 5.3.6 Постолбцовое обращение быстрее . . . . . . . . . . . . . . . . . . . . . . 125 5.4 Оптимизированные библиотеки линейной алгебры . . . . . . . . . . . . . . . . 127 5.4.1 BLAS, LAPACK, ATLAS и MKL . . . . . . . . . . . . . . . . . . . . . . . 128 5.4.2 Методы низкоуровневой оптимизации . . . . . . . . . . . . . . . . . . . . 129 5.4.3 Установка оптимизированных библиотек линейной алгебры для Scilab под Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 3 5.4.4 Установка оптимизированных библиотек линейной алгебры для Scilab под Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 5.4.5 Пример улучшения производительности . . . . . . . . . . . . . . . . . . 134 5.5 Измерение числа операций с плавающей запятой за секунду (флопс) . . . . . 135 5.5.1 Произведение матрицы на матрицу . . . . . . . . . . . . . . . . . . . . . 135 5.5.2 Обратный слэш . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 5.5.3 Многоядерные вычисления . . . . . . . . . . . . . . . . . . . . . . . . . . 140 5.6 Замечания и ссылки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 5.7 Упражнения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 6 Благодарности 143 7 Ответы к упражнениям 144 7.1 Ответы к разделу 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 7.2 Ответы к разделу 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 7.3 Ответы к разделу 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 Предметный указатель 150 Список литературы 150 4 Copyright c 2008-2010 - Michael Baudin Copyright c 2010-2011 - DIGITEO - Michael Baudin Copyright c 2011 - Stanislav Kroter (translation into Russian) Этот файл должен использоваться на условиях Creative Commons Attribution-ShareAlike 3.0 Unported License: http://creativecommons.org/licenses/by-sa/3.0 5 1 Введение Этот документ является проектом с открытым исходным кодом. Исходный код на L A TEXдоступен на Scilab Forge: http://forge.scilab.org/index.php/p/docprogscilab Исходные коды на L A TEXпредоставляются на условиях лицензии Creative Commons Attribution- ShareAlike 3.0 Unported License: http://creativecommons.org/licenses/by-sa/3.0 Файлы-сценарии Scilab предоставляются на Forge, внутри проекта в подкаталоге scripts. Файлы-сценарии распространяются на условиях лицензии CeCiLL: http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt 2 Управление переменными и памятью В этом разделе мы опишем несколько характеристик Scilab, которые позволяют управ- лять переменными и памятью. На самом деле, мы иногда обращаемся к большим вычисле- ниям, так что, для того, чтобы взять от Scilab всё, мы должны увеличить память, доступную для переменных. Мы начнём с представления стека, который Scilab использует для управления своей памятью. Мы представим как использовать функцию stacksize для того, чтобы настро- ить размер стека. Затем мы проанализируем максимально доступную память для Scilab, в зависимости от ограничений операционной системы. Мы кратко представим функцию who в качестве инструмента осведомления о переменных, определённых в данный момент. За- тем мы выделим переносимость переменных и функций, так что мы сможем разрабатывать сценарии, которые будут работать одинаково хорошо в различных операционных системах. Мы представим функцию clear, которая позволяет уничтожать переменные когда конча- ется память. Наконец, мы представим две функции часто используемые когда мы хотим динамически менять поведение алгоритма в зависимости от типа переменной, то есть мы представим функции type и typeof. Информация, представленная в этом разделе будет интересна тем пользователям, ко- торые хотят более глубоко понять внутреннее устройство Scilab. Между прочим, точное управление памятью является ключевой характеристикой, которая позволит выполнить вы- числения наиболее требовательные к памяти. Команды, которые позволяют управлять пе- ременными и памятью представлены на рисунке 1 2.1 Стек В Scilab версии 5 (и прежних версиях), память управляется с помощью стека. При запуске Scilab распределяет фиксированное количество памяти для хранения переменных данной сессии. Некоторые переменные уже предопределены при запуске, что потребляет небольшое количество памяти, но б´ ольшая часть памяти свободна и предоставлена поль- зователю. Когда бы пользователь ни определил переменную, внутри стека используется соответствующая память и в соответствующее количество памяти удаляется из оставшейся 6 clear уничтожить переменные clearglobal уничтожить глобальные переменные global определить глобальные переменные isglobal проверить является ли переменная глобальной stacksize установить размер стека Scilab gstacksize установить/получить размер стека Scilab who листинг переменных who_user листинг пользовательских переменных whos листинг переменных в формате long Рис. 1: Функции для управления переменными. свободной части стека. Эта ситуация представлена на рисунке 2 . Когда не остаётся сво- бодной памяти в стеке, пользователь больше не может создать новую переменную. В этом случае пользователь должен либо разрушить существующую переменную, либо увеличить размер стека. Внутренние переменные (например, 10%) Пользовательские переменные (например, 40%) Свободно (например, 50%) Стек (100%) Рис. 2: Стек Scilab. Всегда есть некоторое сомнение о бите и байтах, их обозначениях и их единицах изме- рения. Бит (двоичная цифра) — это переменная, которая может быть равна только 0 или 1. Байт (обозначается латинской B или Б) состоит из восьми битов. Есть два разных типа обозначений единиц измерения для множества байтов. В десятичной системе единиц изме- рения один килобайт состоит из 1000 байт, так что используется обозначение (латинское KB или КБ) (10 3 байт), MB (10 6 байт), GB (10 9 байт) и более (такие как TB для терабайт и PB для петабайт). В двоичной системе единиц измерения один килобайт состоит из 1024 байт, так что обозначения включают в себя строчную букву «i» в своих единицах измерения: KiB, MiB, и так далее. . . . В данном документе мы используем только десятичную систему единиц измерения. Функция stacksize позволяет узнать текущее состояние стека. В сессии, выполняемой после запуска Scilab’а, мы вызываем stacksize для того, чтобы получить текущие свойства стека. - - > s t a c k s i z e () ans = 5 0 0 0 0 0 0 . 3 3 3 6 0 . 7 Первое число, 5 000 000, это общее число 64 х -битных слов, которые могут быть сохранены в стеке. Второе число, 33 360, это число 64 х -битных слов, которые уже используются. Это значит, что только 5 000 000 – 33 360 = 4 966 640 64 х -битных слов доступны для пользовате- ля. Число 5 000 000 равно числу 64 х -битных чисел с плавающей запятой двойной точности (т. е. «double»), которые могут быть сохранены, если стек содержит только этот тип дан- ных. Общий размер стека 5 000 000 соответствует 40 МБ, поскольку 5 000 000×8 = 40 000 000. Эта память может быть полностью заполнена плотной квадратной матрицей размерами 2236 на 2236 с числами двойной точности (double), поскольку √ 5000000 ≈ 2236. Действительно, стек используется для хранения как действительных значений, цело- численных, строковых, так и более сложных структур данных. Когда хранится 8 и -битное целочисленное значение, это соответствует 1/8 памяти, требуемой для хранения 64 х -битного слова (поскольку 8 × 8 = 64). В данном случае требуется только 1/8 часть памяти, требу- емой для хранения 64 х -битного слова, чтобы сохранить целочисленное значение. В общем, второе целочисленное значение сохраняется во 2/8 части того же слова, так что память не теряется. Установка по умолчанию возможно достаточна для большинства случаев, но может быть ограничение для некоторых приложений В сессии Scilab’а мы видим, что создание случайной плотной матрицы 2300 × 2300 генерирует ошибку в то время, как создание матрицы 2200 × 2200 возможно. \ b e g i n { s c r i p t s i z e } \ b e g i n { v e r b a t i m } - - > A = r a n d ( 2 3 0 0 , 2 3 0 0 ) ! - - e r r o r 17 r a n d : Превышен допустимый размер стека (используйте функцию stacksize для его увеличения). - - > c l e a r A - - > A = r a n d ( 2 2 0 0 , 2 2 0 0 ) ; В том случае, где нам нужно сохранить большие наборы данных, нам нужно увеличить размер стека. Команда stacksize("max") позволяет настроить размер стека таким, что- бы распределить максимально возможное количество памяти системы. Следующий файл- сценарий предоставляет пример этой функции, выполненной на ноутбуке с операционной системой GNU/Linux с объёмом памяти 1 ГБ. Функция format используется для того, что- бы отображались все знаки. - - > f o r m a t ( 2 5 ) - - > s t a c k s i z e ( " max " ) - - > s t a c k s i z e () ans = 2 8 1 7 6 3 8 4 . 3 5 0 7 7 . Мы можем видеть на этот раз, что общая доступная память в стеке соответствует 28 176 384 единицам 64 х -битных слов, что соответствует 225 МБ (поскольку 28 176 384 × 8 = 225 411 072). Максимальная плотная матрица, которая может быть сохранена, сейчас размером 5308 на 5308, поскольку √ 28176384 ≈ 5308. Теперь увеличим размер стека до максимума и создадим плотную квадратную матрицу чисел типа double размером 3000 на 3000. - - > s t a c k s i z e ( " max " ) - - > A = r a n d ( 3 0 0 0 , 3 0 0 0 ) ; 8 Предположим, что у нас 32 х -битная машина с Windows XP и 4 ГБ памяти. На этой машине у нас установлен Scilab 5.2.2. Определим плотную квадратную матрицу чисел типа double размером 12 000 на 12 000. Это соответствует приблизительно 1,2 ГБ памяти. - - > s t a c k s i z e ( " max " ) - - > f o r m a t ( 2 5 ) - - > s t a c k s i z e () ans = 1 5 2 6 1 1 5 3 6 . 3 6 8 2 0 . - - > s q r t ( 1 5 2 6 1 1 5 3 6 ) ans = 1 2 3 5 3 . 6 0 4 1 7 0 4 4 3 5 3 9 2 6 0 3 0 5 - - > A = z e r o s ( 1 2 0 0 0 , 1 2 0 0 0 ) ; Мы задали размер плотной матрицы типа double для того, чтобы получить грубое представление о том, чему эти числа соответствуют на практике. Конечно, пользователь может по-прежнему управлять гораздо б´ ольшими матрицами, например, если они являются разреженными матрицами. Но в любом случае общая используемая память может превысить размер стека. Scilab версии 5 (и ранние) может адресовать 2 31 ≈ 2,1 × 10 9 байт, т. е. 2,1 ГБ памяти. Это соответствует 2 31 /8 = 268 435 456 чисел типа double, которыми может быть заполнена плотная квадратная матрица типа double размером 16 384 на 16 384. Это ограничение вызва- на внутренним устройством Scilab в любой операционной системе. Более того, ограничения, налагаемые операционной системой могут больше ограничить эту память. Эти темы деталь- но рассматриваются в следующем разделе, который представляет внутренние ограничения Scilab и ограничения, вызванные различными операционными системами, на которых может быть запущен Scilab. 2.2 Подробнее об управлении памятью В этом разделе мы расскажем более детально о доступной памяти в Scilab с точки зрения пользователя. Мы отделим ограничения памяти, вызванные устройством Scilab от ограничений, вызванных устройством операционной системы. В первом разделе мы анализируем внутреннее устройство Scilab и способ управления памятью с помощью 32 х -битных целых чисел со знаком. Затем мы покажем ограничение распределения памяти на различных 32 х - и 64 х -битных операционных системах. В последнем разделе мы представляем алгоритм, используемый функцией stacksize. Эти разделы скорее технические и могут быть пропущены большинством пользовате- лей. Но пользователи, более опытные в теме памяти, или те, кто хочет узнать как точное устройство Scilab версии 5, могут узнать о точных причинах этих ограничений. 2.2.1 Ограничения памяти со стороны Scilab Scilab версии 5 (и ранние) обращается к своей внутренней памяти (т. е. стеку) 32 х - битными целыми числами со знаком в любой операционной системе на которой он запущен. Это объясняет то, что максимальное количество памяти, которое Scilab может использовать, равно 2,1 ГБ. В этом разделе мы расскажем как это реализовано в большинстве частей Scilab’а, которые управляют памятью. В Scilab, шлюз — это функция C или Fortran, которая даёт пользователю особую функ- цию. А конкретнее, она соединяет интерпретатор с отдельным набором библиотечных функ- 9 ций чтением входных аргументов, заданных пользователем, и записью выходных аргумен- тов, затребованных пользователем. Рассмотрим следующий пример Scilab. x = 3 y = sin ( x ) Здесь переменные x и y являются матрицами типа double. В шлюзе функции sin мы прове- ряем число входных аргументов и их тип. Как только переменная x проходит проверку, мы создаём выходную переменную y в стеке. Наконец, мы вызываем функцию sin, предостав- ленную математической библиотекой и кладём результат в y. |