Журнал LinuxFormat - перейти на главную

LXF122:SciLab

Материал из Linuxformat
Перейти к: навигация, поиск
Scilab Создадим для него пакет расширений и обогатим новыми возможностями

Содержание

Scilab: Создаем Toolbox

Если возможностей, встроенных в Scilab, недостаточно для ваших целей, Александр Бикмеев покажет, как обучить его новым трюкам (ко всеобщей пользе, разумеется).

Сегодня многие уже понимают, что свободное ПО часто может заменить проприетарное без особого ущерба для функциональности. Например, свободные математические пакеты прочно обосновались на жестких дисках не только зарубежных, но и российских пользователей. Но... оказывается, что для решения некоторых задач их возможностей не хватает. Что же делать? Наверное, следует действовать в лучших традициях мира Open Source – если чего-то недостает, то это следует создать самому! Тем более, что в программе Google Summer Code все чаще появляются задачи по созданию расширений для свободных математических пакетов.

На данном уроке мы познакомимся со стандартной процедурой создания пакета расширений (Toolbox) для СКА Scilab (LXF106–109) при помощи макросов на встроенном языке программирования. Англоязычное руководство по написанию пакетов расширений можно найти на официальной вики: http://wiki.scilab.org/howto/Create_a_toolbox.

Каталоги

Если мы создаем какой-то пакет, содержащий функции, то все его файлы должны находиться в одном каталоге. Имя корневого каталога должно совпадать с названием самого пакета. Внутри корневого каталога может находиться 8 подкаталогов:

  • macros Здесь расположены макросы Scilab, то есть файлы-функции с расширением .sci, написанные на встроенном языке, а также скрипт сборки макросов buildmacros.sce.
  • src Если функции пакета представляют собой подпрограммы, написанные на C/C++ или Fortran, то в этом каталоге должны находиться файлы с их исходным кодом (с расширениями .c и .f) и сценарий сборки buildsrc.sce.
  • sci_gateway Здесь располагаются программы-интерфейсы для функций, написанных на сторонних языках программирования (C/C++, Fortran).
  • help В этом каталоге находится текст справки, представляющий собой совокупность XML-файлов, на английском и французском языках, в подкаталогах с соответствующими именами eng и fr, и традиционный скрипт сборки справочного материала: builder_help.sce.
  • etc Если для пакета нужны еще какие-либо файлы (.html, .pdf, .txt, .jpeg, …), то они размещаются здесь. Кроме того, тут расположены скрипты подготовки загрузки и выгрузки пакета из системы.
  • unit tests В этом каталоге расположены файлы с расширением .tst, представляющие собой скрипты для тестирования пакета расширений.
  • demos В этот каталог помещаются различные примеры, иллюстрирующие работу пакета.
  • includes Здесь располагаются заголовочные файлы (с расширением .h) для исходных текстов C/C++.

Кроме описанных подкаталогов, в корневом каталоге обычно располагаются 4 файла:

  • readme.txt Описание самого пакета расширений, а также процесса его установки.
  • builder.sce Основной скрипт сборки пакета...
  • loader.sce...и основной скрипт его загрузки в Scilab
  • license.txt Лицензия.

Следует отметить, что данная структура не всегда реализуется полностью. Например, если в пакете нет функций, реализованных на C/C++, можно обойтись без src; в отсутствие примеров не нужен каталог demos. В репозитории пакетов расширений на сайте Scilab встречаются экземпляры, состоящие из одного файла с функциями, без каких-либо скриптов сборки и установки. Но нам кажется, что соблюдение правил, определенных разработчиками – это верный путь к безошибочной работе конечного продукта.

В каталоге самого Scilab имеется шаблон нового пакета, который вы можете взять в качестве основы. Если вы используете двоичную версию Scilab, загруженную вручную, то пакет-шаблон располагается в каталоге scilab/contrib/toolbox_skeleton; если же Scilab установлен при помощи менеджера пакетов, то ищите в каталогах /opt или /usr. Я пользуюсь Mandriva 2009.1, и у меня он находится в /usr/share/scilab/contrib/toolbox_skeleton.

Добавим функции

Давайте создадим пакет (назовем его Ballistic), в котором будут три функции, вычисляющие параметры движения тела, брошенного под углом к горизонту, в зависимости от времени:

  • blst_height – высота тела,
  • blst_length – дальность полета,
  • blst_speed – вертикальная и горизонтальной скорости тела,

а также справка по работе с ними. Все функции будут реализованы на встроенном языке Scilab.

Напомним (LXF107), что код внешних функций в Scilab вводится в редакторе, а описание функции имеет вид:

function [<список выходных параметров>] =
<Имя Функции>(<список входных параметров>)
  <тело функции>
endfunction

Создадим в домашнем каталоге новый, с именем Scilab_Toolbox: здесь будут размещаться все пакеты расширений, загруженные из сети или созданные лично нами. Организуем в нем подкаталог для нашего пакета (ballistic). В соответствии с выбранным содержимым создадим подкаталоги macros и help.


Запускаем Scilab, открываем редактор либо командой scipad, либо при помощи меню Инструменты > Редактор и вводим код, показанный на рис. 1. В самом тексте приведено достаточно комментариев, чтобы не вдаваться в его детальное объяснение. Поясним только один момент, который не совсем очевиден, а именно – для чего в тексте функции используется цикл.

Поскольку мы бросаем тело с поверхности Земли, которую полагаем плоской, то отрицательная высота не имеет смысла. В связи с этим в код добавлена проверка рассчитанного значения, и если оно оказывается отрицательным, мы принудительно устанавливаем его в ноль. Однако проблема в том, что в качестве входных параметров функций Scilab может использоваться не одно значение, а массив. Если оставить только один оператор сравнения, то оно будет выполнено только для первого элемента массива. В результате мы получим или массив нулевых значений (если первый элемент будет отрицательным), или массив, в котором имеются и отрицательные, и положительные элементы.

Эта ошибка весьма типична для начинающих программировать в Scilab, поскольку они часто забывают, что любая переменная в этой системе рассматривается прежде всего как матрица. Таким образом, сравнение необходимо выполнить для всех элементов массива-результата, а для этого необходим цикл.

Сохраним данный код в каталоге macros под именем blst_height.sci. Затем создадим файлы blst_length.sci и blst_speed.sci, которые будут вычислять дальность полета тела и компоненты скорости соответственно. В качестве входных параметров всех трех функций выступают g – ускорение свободного падения, v0 – абсолютная величина начальной скорости, alpha – угол наклона к горизонту, t – время, прошедшее с момента начала движения. Эти функции длиннее, так что мы не будем приводить их текст в журнале: воспользуйтесь файлами с LXFDVD.


Конечно же, тексты этих макросов можно набрать в простом текстовом редакторе типа Kate, но использование Scipad позволяет проверить работу функции сразу после ввода. Для этого следует выбрать последовательно пункты меню Execute > Load into Scilab. После этого в основном окне Scilab можно будет выполнить тестовые вычисления с функциями будущего пакета.

Загрузите функцию blst_height в Scilab, как указано выше, и попробуйте следующие команды:


-->t=0:0.1:3;
-->h1=blst_height(9.81,10,45,t);
-->h2=blst_height(1.62,10,45,t);
-->plot2d(t,[h1 h2],[color(0,255,0) color(255,128,0)]);
-->hl=legend([‘Земля’;’Луна’],2);

В результате получится график, показанный на рис. 2. На нем отображаются траектории первых трех секунд полета тела с одинаковыми исходными параметрами, но на разных небесных телах: на Земле и на Луне (может, проверим, были ли там американцы?). Видно, что на Луне тело летит выше, чем на Земле. Следовательно, функция работает. Мы рекомендуем вам разработать тестовые примеры для каждой функции, чтобы впоследствии после любых изменений можно было убедиться, что новая версия функции дает тот же результат, что и старая. Собственно, для этого и нужны сценарии в подкаталоге unit tests нашего пакета.


После того, как все макросы созданы, необходимо написать скрипт их сборки и загрузки. Это обычно делается вручную. В Scilab5 появились специальные команды, упрощающие выполнение данной операции. Откройте каталог с макросами и создайте в нем простой текстовый документ с именем buildmacros.sce. Внутри него разместите следующий текст:

pathMB = get_absolute_file_path('buildmacros.sce');
tbx_build_macros('Ballistic', pathMB);
clear pathMB;

и сохраните файл. Первая строка скрипта заносит во временную переменную pathMB каталог, где расположены макросы. Вторая строка содержит команду, выполняющую сборку всех макросов, расположенных в данном каталоге. В качестве параметров указываются название пакета и путь к каталогу с макросами. Третья строка удаляет из памяти временную переменную.

В результате действия данной команды создается и скрипт загрузки макросов. Ранее его приходилось писать вручную, да и сборочный скрипт имел чуть более сложный вид.

Создаем описание

Функции написаны, но если мы не сопроводим их поясняющим текстом, то вряд ли кто-то станет разбираться, как с ними работать. Одним из вариантов является использование комментариев; однако, чтобы просмотреть их, пользователю придется лезть в исходный код. Конечно же, есть люди, которые полезут в него в любом случае, но если пользователю необходимы пояснения, он обычно открывает справочное руководство. Справочная система Scilab обладает замечательным свойством – она динамическая. То есть при загрузке в рабочую среду нового пакета расширений, его справочное руководство – если оно имеется – появляется в основном дереве руководства по всему пакету.


Для создания справочных материалов необходимо, чтобы в системе был установлен XML-анализатор sabcmd, являющийся частью пакета Sablotron, который можно найти в менеджере пакетов вашего дистрибутива. Если же там его не оказалось, то скачайте Sablotron здесь: http://www.gingerall.org/downloads.html.

Впрочем, XML-структура файла справки достаточно проста, и его можно создать в любом текстовом редакторе. Начинается все со строки, в которой указывается версия XML и используемая кодировка:

<?xml version=”1.0” encoding=”UTF-8”?>

Затем идет «шапка» для Scilab. Здесь указывается версия Scilab, название функции, язык справочного материала, а также определяются некоторые пространства имен.

<refentry version=”5.0-subset Scilab” xml:id=”blst_height” xml:lang=”en”
   xmlns=”http://docbook.org/ns/docbook”
   xmlns:xlink=”http://www.w3.org/1999/xlink”
   xmlns:svg=”http://www.w3.org/2000/svg”
   xmlns:ns3=”http://www.w3.org/1999/xhtml”
   xmlns:mml=”http://www.w3.org/1998/Math/MathML”
   xmlns:db=”http://docbook.org/ns/docbook”>

Далее идет краткое описание самой функции:

<refnamediv>
 <refname>blst_height</refname>
 <refpurpose> calculate height of body's trajectory, that was thrown from earth </refpurpose>
</refnamediv>

Затем указывается стандарт вызова:

<refsynopsisdiv>
  <title>Calling Sequence</title>
  <synopsis>a = blst_height(g, v0, alpha, t)</synopsis>
</refsynopsisdiv>

Следующая секция описывает параметры, передаваемые нашей функции:

<refsection>
  <title>Parameters</title>
   <variablelist>
     <varlistentry>
       <term>g</term>
       <listitem>
          <para>gravitational acceleration</para>
       </listitem>
     </varlistentry>
     ...
   </variablelist>
</refsection>

Далее идет раздел описания: в нем сообщается, что это за функция, для чего она нужна и так далее. Каждый параграф заключается в тэг para.

<refsection>
  <title>Description</title>
  <para>calculate height of body’s trajectory, that was thrown from earth from given gravitational acceleration, 
        initial speed and angle between the speed and horizon, and time since trow.</para>
</refsection>

Следующий раздел предлагает примеры использования данной функции.

<refsection>
 <title>Examples</title>
    <programlisting role=”example”>blst_height(9.81, 15,30, 3)</programlisting>
</refsection>

В конце могут быть указаны необязательные разделы, такие как «Автор» и «Смотри также».

<refsection>
  <title>Authors</title>
    <simplelist type=”vert”>
     <member>Alexander</member>
    </simplelist>
</refsection>

После этого файл закрывается:

</refentry>

Создайте в каталоге help подкаталог en_US (к сожалению, Scilab поддерживает справку только на двух языках: английском и французском). Затем создайте в help/en_US три файла с описанием функций с расширением .xml.

Осталось создать там же сценарий сборки англоязычного справочного материала (build_help.sce) со следующим содержанием:

pathHB = get_absolute_file_path('build_help.sce');
tbx_build_help('Ballistic', pathHB);
clear pathHB;

Так же, как и в предыдущем случае, в первой строке определяется путь к текущему каталогу с файлами справки, затем вызывается команда сборки, а в третьей строке удаляется временная переменная.

Далее, перейдите на один уровень выше в каталог help. Здесь следует создать скрипт сборки всех справочных материалов builder_help.sce:

pathH = get_absolute_file_path('builder_help.sce');
tbx_builder_help_lang(“en_US”, pathH);
clear pathH;


Управляющие скрипты

Основное содержимое готово. Теперь необходимо создать три основных скрипта, без которых ничего работать не будет:

  • builder.sce Это главный сценарий сборки пакета. Он располагается в его корневом каталоге и содержит следующие строки:
mode(-1)
pathB = get_absolute_file_path('builder.sce');
tbx_builder_macros(pathB);
tbx_builder_help(pathB);
tbx_build_loader('Ballistic', pathB);
clear pathB;

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

  • etc/Ballistic.start Это основный скрипт загрузки пакета, вызываемый из загрузчика. В нем прописывается все, что необходимо сделать во время загрузки пакета расширений. Ниже приведено содержание такого скрипта для нашего пакета:
//Запоминаем режим вывода предупреждений
warning_mode = warning('query');
//Отключаем режим вывода предупреждений
warning('off');
//Получаем путь к корневому каталогу пакета
etc_tlbx = get_absolute_file_path('Ballistic.start');
etc_tlbx = getshortpathname(etc_tlbx);
root_tlbx = strncpy( etc_tlbx, length(etc_tlbx)-length('\etc\') );
//Получаем путь к каталогу с макросами
pathmacros = pathconvert( root_tlbx ) + 'macros'+ filesep(); 
//Загружаем функции пакета
Ballisticlib = lib(pathmacros);
//Восстанавливаем режим вывода предупреждений
warning(warning_mode);
//Добавляем новую главу в справочное руководство Scilab
path_addchapter = root_tlbx + “/jar/”;
if ( fileinfo(path_addchapter) <> [] ) then
add_help_chapter('Ballistic', path_addchapter, %F);
clear add_help_chapter;
end
//Удаляем все временные переменные
clear warning_mode;
clear path_addchapter;
clear root_tlbx;
clear etc_tlbx;
clear pathmacros;
clear pathconvert;


  • etc/Ballistic.quit Сценарий, определяющий, что следует выполнить при выгрузке пакета. Обычно он остается пустым.

Итак, все готово! Запускаем Scilab и вводим команду на сборку нашего пакета, то есть вызываем основной сборочный сценарий:

exec('~/Scilab_Toolbox/ballistic/builder.sce’);

Если он отработает без ошибок, в корневом каталоге пакета появится скрипт его загрузки в систему. Выполним команду загрузки пакета расширений:

exec('~/Scilab_Toolbox/ballistic/loader.sce');

Все, теперь можно использовать функции пакета в расчетах. Более того, можно открыть справку и в самом низу (иногда вверху) увидеть название нашего пакета – 'Ballistic' . Щелкнув на этом пункте, можно посмотреть, правильно ли мы оформили справку (рис. 3). Если все сделано верно, то осталось только создать файлы с описанием установки и текстом лицензии.

Все скрипты, макросы и файлы справки можно создать, не запуская Scilab: система понадобится только на последнем этапе для сборки пакета и проверки работоспособности. Более того, шаблоны скриптов можно взять из пакета toolbox_skeleton и убрать из них все лишнее или добавить свое.

Дерзайте! А если эта статья вас заинтересовала, то напишите нам (letters@linuxformat.ru), что бы вы еще хотели узнать о создании пакетов расширений или программировании в Sсilab. Разработка графического интерфейса, создание пакетов из имеющихся специализированных библиотек или собственного блока для Scicos – что вам интересно? LXF

Персональные инструменты
купить
подписаться
Яндекс.Метрика