Научная статья на тему 'Проверка выполнения функциональных требований к алгоритму на основе структурной генерации модульных тестов'

Проверка выполнения функциональных требований к алгоритму на основе структурной генерации модульных тестов Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
50
10
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
АВТОМАТИЗИРОВАННАЯ ВЕРИФИКАЦИЯ / ДЕДУКТИВНЫЙ МЕТОД / СТРУКТУРНАЯ ГЕНЕРАЦИЯ ТЕСТОВ / НАБЛЮДАЕМОЕ ПОВЕДЕНИЕ АЛГОРИТМОВ

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Рудаков Игорь Владимирович, Ребриков Александр Викторович

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

i Надоели баннеры? Вы всегда можете отключить рекламу.

Похожие темы научных работ по компьютерным и информационным наукам , автор научной работы — Рудаков Игорь Владимирович, Ребриков Александр Викторович

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Проверка выполнения функциональных требований к алгоритму на основе структурной генерации модульных тестов»

УДК 519.876.5

И. В. Рудаков, А. В. Ребриков

ПРОВЕРКА ВЫПОЛНЕНИЯ ФУНКЦИОНАЛЬНЫХ ТРЕБОВАНИЙ К АЛГОРИТМУ НА ОСНОВЕ СТРУКТУРНОЙ ГЕНЕРАЦИИ МОДУЛЬНЫХ ТЕСТОВ

Разработан метод верификации алгоритмов, на базе дедуктивного подхода к проверке выполнения заданных требований. Основой метода является математическая модель описания наблюдаемого поведения алгоритма — элемента рефлексивно-транзитивного замыкания путей в графе выполнения алгоритма. При создании метода предусмотрена возможность управления устранением ци-кломатической сложности за счет снижения точности метода и использования жадных алгоритмов поиска.

E-mail: irudakov@yandex.ru, rebrikov_a@mail.ru

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

Применение дедуктивных методов [1] для верификации алгоритмов сопряжено с ограниченностью спектра разрешимых задач c помощью теории [2], заложенной в используемый SMT-решатель [2]. В то же время, путем расширения теории при дедуктивном подходе верифицируемый алгоритм можно задавать на языке его реализации, благодаря чему не требуется создание специализированных моделей, как в системах, основанных на верификации состояний системы [3]. При анализе функционирования сложных алгоритмов для полной, или формальной, верификации [3, 4] требуются большие временные затраты, поэтому с целью их сокращения необходимо иметь возможность проведения неполной верификации [5], посредством которой также можно проводить проверку систем с нецелочисленной логикой, что невозможно сделать при полной верификации.

Управляющим графом алгоритма называется кортеж [6]:

G = (N,E,no),

где N — множество вершин, каждая из которых соответствует оператору алгоритма; E — множество дуг, соотвествующих переходу управления; n0 — стартовая вершина.

Множество N состоит из двух непересекающихся множеств Ns, Np, где Ns — операторы, и у каждого ns £ Ns имеется не более одной вершины-потомка, т.е. 3!nj £ N:(ns,nj) £ E; Np — условные операторы, и у каждого из них существует конечное число потомков. У стартовой вершины n0 нет предков, и любая вершина графа достижима из нее.

Обозначим все множество переменных алгоритма как V, и множество функций, изменяющих значения переменных как F:2 D ^ D, где D — домены переменных V.

На определенном графе удобно ввести следующие функции разметки:

func : N х V ^ {FU0}: каждой паре вершин управляющего графа и изменяемых в них переменных соотвествует набор функций, изменяющих значение переменных. Если паре (n, v) соответствует пустое множество, то значение переменной v в вершине n не меняется. Без ограничения общности можно полагать, что отображение биективно, положив, что значение любой переменной может изменяться только один раз;

use : N ^ 2 V: каждой вершине управляющего графа соотвествует набор переменных, используемых в операторе;

def С func : N ^ 2 V: каждой вершине управляющего графа соответствует набор переменных, определенном в данном операторе. Без ограничения общности можно положить, что func : def ^ {F U 0}, т.е. определение переменной совпадает с ее первым и единственным изменением.

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

Уровнем абстракции наблюдаемого поведения алгоритма [7] будет называться отношение:

а : N ^ 2V U {ф}.

Если a(n) = ф, то это означает, что оператор n является ненаблюдаемым. На множестве уровней абстракции можно ввести отношение частичного порядка и говорить, что а1 < а2, если для всех операторов алгоритма n верно, что a2(n) = ф ^ a1(n) = ф V a1(n) С a2(n).

Для описания измения состояния алгоритма используется структура

s = (n, val),

где n £ N, val : V ^ D — значение переменной v, т.е. состояние описывается текущим выполняемым оператором и значениями переменных.

Деревом поведения алгоритма называется ациклический ориентированный граф

behaviour = (S, R, s0),

где S — множество состояний алгоритма; R — отношение достижимости на множестве S; s0 — выделенная корневая вершина (начальное состояние алгоритма).

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

Состояние s = (n, val(V)) будет наблюдаемым на заданном уровне абстракции а, если:

а) а(п) = ф;

б) 3v G V : v G а(п) Л func(n,v) = 0.

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

Назовем два алгоритма эквивалентными на уровне абстракции а, если их наблюдаемое поведение совпадает при одинаковых начальных состояниях.

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

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

Оператор n G N зависит по управлению от предиката с, который содержится в операторе условного ветвления nc G N, если в структуре потока управления алгоритма от выбора пути выполнения, на который потенциально влияет c, зависит, будет ли выполнен оператор n.

Оператор n G N зависит по данным от оператора n', если данные, определяемые в n' G N, используются в n и потенциально могут достичь n через последовательность присваиваний переменных.

Для достаточного уровня абстракции а' дадим следующее конструктивное определение. Если оператор n, входит в наблюдаемое поведение алгоритма, т.е. а(n) = ф, то множество операторов S С N, от которых n транзитивно зависит по управлению или данным, войдет в достаточный уровень абстракции вместе с оператором n и теми же наблюдаемыми переменными:

а(n) = ф ^ sigma'(n) = ф; а(n) = ф ^Vn' G S : а'(^) = а(n).

Докажем, что а < а'.

Согласно определению частичного порядка на множестве уровней абстракции, надо доказать, что (1) Vn G Nа(n) С а'(n) и (2) а'(n) = ф ^ а(и) = ф.

(1) В силу определения достаточного уровня абстракции, если оператор n включается в уровень абстракции а, то он включается с теми же наблюдаемыми переменными в а', т.е. а(н) С а'(н).

(2) Предположим обратное: Зп € N : а'(п) = ф Л а (те) = ф. Но это противоречит определению а', ведь если а(п) = ф, то в а' по крайней мере попадет п.

Из справедливости (1) и (2) согласно определнию частичного порядка следует, что а < а', ч.т.д.

Отметим, что если два алгоритма С и С2 эквивалентны на уровне абстракции а', то они эквивалентны на любом уровне абстракции а < а'. Действительно, уменьшение уровня абстракции (при прямом исключении рассматриваемых операторов либо косвенным путем за счет уменьшения числа рассматриваемых переменных) приводит к дальнейшему транзитивному расширению в дереве поведения. А раз на текущем уровне они совпадают, то и любые транзитивные операции на одинаковых множествах приведут к одинаковому результату.

Обозначим алгоритм, полученный из алгоритма С на уровне абстракции а, как С0, построение которого аналогично построению наблюдаемого поведения: необходимо лишь провести операцию транзитивного расширения достижимости операторов до множества всех наблюдаемых операторов:

Са = (К ,поа);

Уп € N : п € N ^ а(п) = ф; У(пь^) € Е : (П1,П2) € Еа ^

^ П1 € Na Л П2 € Na Л (-Зпз : П1 ^ *пэ Л пз ^ *П2);

п0а : —Зп € N0- : п ^ *п0а.

Алгоритмы С и С'0 эквивалетны на уровне абстракции а.

Необходимо отметить, что достаточный уровень абстракции является единственным и максимальным: УаЗ!а' : С С0 Л —За1 : а' < < а1 Л а' = а1.

Понятие уровня абстракции можно расширить следующим образом:

а : N ^ 2Ру °,

где Ру& — множество предикатов над переменными алгоритма и их доменами, задающих условия корректности алгоритма.

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

Основная идея метода заключается в когерентности работы алгоритма [8-11] его поведение изменяется лишь в операторах ветвления, поэтому логично проверять корректность работы алгоритма на таких наборах данных, при которых его поведение изменяется, а также в

точках, близких к этим наборам. Метод базируется на существующем методе граничных значений за тем исключением, что граничные значения берутся не из артефактов анализа предметной области, а из кода. Кроме того, к граничным значениям необходимо добавить значения переменных из условий корректности (которые, строго говоря, являются артефактами предыдущих этапов разработки).

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

Входные данные: граф выполнения программы G, условия корректности а.

Выходные данные: I — наборы входных параметров исходной программы.

Переменные: Sv — множество операторов, зависящих от операторов, изменяющих значение переменной v; S — множество решаемых систем уравнений; I — множество входных значений алгоритма. Тогда

1) I = D,S =[];

2) Получить все пути P из начальной точки алгоритма G в конечную;

3) Vp £ P получить систему: s = INPUTGEN(p), Vn £ pVpv £ £ a(n)Vv £ pv : n £ Sv добавить в s отрицание предиката pv, если его еще нет в s, S ^ s;

4) Vs £ S получить, если возможно, решение: i = SOLVE(s),I ^ i. Вернуть I.

Процедура INPUTGEN( p )

5) s =[];

6) Vv £ p определить ее тип;

7) если v — выражение, то добавить его в систему уравнений s;

8) если v — условие, и исходящее ребро из него помечено, как истинная, то добавить его предикат в систему уравнений s;

9) если v — условие, и исходящее ребро из него помечено, как ложное, то получить отрицание предиката и добавить его в систему уравнений s;

10) вернуть s.

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

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

вершины. В таком случае вероятность исключения из рассмотрения большого числа кодов заметно уменьшается.

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

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

Формализацией глубины абстракции является цикломатическая сложность алгоритма G, определяемая следующим образом:

M = |E| - |N| + 2Р,

где M — цикломатическая сложность кода; Р — число компонент связности в графе G; |E|, |N| — мощности множеств E, N.

Согласно общепринятому критерию [12], считается, что алгоритм тестируем, если M < Mmax = 50. Тогда для обеспечения возможности тестирования необходимо ограничить число анализируемых путей в графе, используя механизм абстракций. Для построения эквивалентного алгоритма (который необходим для исключения ложных срабатываний, а также для минимизации P: после редукции алгоритма до а'Р = 1) требуется по-прежнему строить алгоритм Ga>, однако при анализе путей для генерации границ классов эквивалентности пожно ограничиться меньшим уровнем абстракции:

а < ас < а',

где ас — уровень абстракции, обеспечивающий непревышение цикло-матического числа Mmax.

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

ас = ас», i = min jVj : M) = maxM(G^), k £ 1..K,

где M(G) — цикломатическая сложность алгоритма G; K — число уровней абстракций, при которых цикломатическая сложность наблюдаемого алгоритма меньше Mmax.

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

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

Входные данные: граф выполнения программы G, условия корректности а.

Выходные данные: наборы входных параметров исходной программы I.

Обозначение переменных: Sv — множество операторов, зависящих от операторов, которые изменяют значение переменной v; S — множество решаемых систем уравнений; I — множество входных значений алгоритма.

1) I = [], s = [],P = [].

2) построить алгоритм G{a'};

3) получить алгоритм G0 = Gac из алгоритма Ga/ и все части алгоритма Ga/ Gk, не попавшине в алгоритм G0 из-за нарушения ци-кломатической сложности;

4) Vi = 0..K : pathes = PATHGEN(G), P ^ pathes;

5) Vp £ P получить систему: s = INPUTGEN(p), Vn £ pVpv £ £ a(n)Vv £ pv : n £ Sv добавить в s отрицание предиката pv, если его еще нет в s, S ^ s;

6) Vs £ S получить, если возможно, решение: i = SOLVE(s),I ^ i. Вернуть I.

Устранение цикломатической сложности возможно не только за счет недобавления операторов в уровень абстракции aC по причине нарушения цикломатической сложности, но и на основе иных условий. Эти методы можно классифицировать следующим образом [6, 12, 13].

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

Метод итеративного исключения. На каждой итерации отбора в уровень абстракции не включается та переменная, исключение кото-

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

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

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

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

Структурная генерация с масштабированием показала существенное улучшение покрытия кода при одновременном уменьшении общего числа тестов (рис. 1) и лучших временных характеристиках, чем у полной верификации.

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

Рис. 1. Сравнение способов генерации тестов по покрытию кода

Рис. 2. Влияние глубины абстракции на время генерации и число найденных ошибок

при глубине абстракции 3, после которого не происходит повышения качества тестирования. Данный вывод подверждает устоявшийся ци-кломатический критерий сложности.

Эксперименты проводились на модулях с открытым исходным кодом репозитория CPAN [14]. Программный комплекс, реализующий данную схему для алгоритмов, которые записаны на языке Perl, зарегистрирован в Объединенном фонде алгоритмов и программ [16].

Ручное составление тестов является наименее эффективным (см. рис. 1) с точки зрения покрытия кода. При этом автоматическая генерация тестов обеспечивает почти полное покрытие (исключение составляют функции, содержащие циклы). В то же время (рис. 3), для ручного составления тестов требуется несравнимо больше времени, чем п составлении автоматическими методами.

Важной характеристикой метода генерации тестов является число тестов, после которого перестает возрастать степень покрытия кода:

П =

П

n

где п3 — число тестов, после которого перестает возрастать (или незначительно возрастает) покрытие кода; п — общее число тестов. Тесты с номерами до п3 называются полезными тестами. Для случайных тестов этот показатель обычно низкий (в наших тестовых

Случайные тесты Граничные значения Структурная генерация ■ Число тестов, шт ■ Время генерации тестов, с

Рис. 3. Сравнение методов генерации тестов по времени затрат

примерах всего 0,051), для граничных значений он составляет 0,734, для тестов, генерируемых автоматически - 1 (что следует из структуры алгоритмов генерации на каждую непокрытую ветвь возвращается только один тестовый случай).

Качество теста можно охарактеризовать следующими величинами:

c

c0 =--> max;

n

П ^ max; t

t0 =--> mm;

n

e ^ max;

ПСо nc

ql =-=--> max;

to t '

ne nen

q2 = — =--> max,

q2 to t ,

где c — покрытие кода тестами данного метода генерации; n — число тестов, обеспечивших данное покрытие; n — относительный уровень насыщения; t — время, необходимое для генерации заданного числа тестов; e — число обнаруживаемых мутантов; ql — мультипликативный критерий качества, направленный на максимизацию, без учета обнаружения ошибок; q2 — мультипликативный критерий качества, направленный на максимизацию, без учета покрытия. Введены два разных критерия ql и q2, поскольку существует корреляция между параметрами e и c0.

Таким образом, автоматическая генерация тестов, выигрывая практически по всем частным критериям, существенно отстает по временным характеристикам, в результате чего оказывается наихудшим из рассмотренных способов генерации тестов по критерию д2 (табл. 1).

Таблица 1

Результаты сравнения методов генерации тестов

Вид генерации с, % t, с П e qi q2

Случайная 60 11,3 0,051 21 0,271 293,814

Граничные значения 85 3,1 0,734 36 20,126 1798,537

Структурная генерация 94 217,97 1 47 0,43 8,409

Общее значение 94 232,37 0,123 47 0,513 85,422

Помимо мультипликативного критерия качества для сравнения способов генерации тестов применяется мутационный критерий. Изначально все тестовые модели приводятся к состоянию, в котором используемые методы генерации входных параметров не обнаруживают ошибок в работе моделей. Затем в программы вносятся ошибки — мутации, для каждой одной мутации строится отдельная программа — мутант. Показателем качества является число обнаруживаемых мутантов (табл. 2).

Таблица 2

Сравнение методов генерации тестов (обнаружение ошибок)

Вид генерации Ошибок выполнения Нарушений условий корректности Всего

Случайная 14 7 21

Граничные значения 25 11 36

Автоматическая генерация 33 14 47

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

Проведенные исследования позволили:

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

2) установить значение числа ложных срабатываний — из 47 найденных ошибок 44 были подтверждены составленными вручную тестами;

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

Эксперименты проводились на модулях с открытым исходным кодом репозитория CPAN [14]. Программный комплекс, реализующий данную схему для алгоритмов, коорые записаны на языке Perl, зарегистрирован в Объединенном фонде алгоритмов и программ [15, 16].

СПИСОК ЛИТЕРАТУРЫ

1. Кулямин В. В. Методы верификации программного обеспечения / Всероссийский конкурсный отбор обзорно-аналитических статей по приоритетному направлению "Информационно-телекоммуникационные системы", 2008. -117 с.

2. Ч е н ь Ч., Ли Р. Метод резолюций // Математическая логика и автоматическое доказательство теорем = Chin-Liang Chang; Richard Char-Tung Lee (1973). Symbolic Logic and Mechanical Theorem Proving. Academic Press. - М.: Наука, 1983. - 358 c.

3. Leue S., We i W. Counterexample-based refinement for a boundedness test for CFSM languages, International Workshop on Model Checking Software (SPIN): Lecture Notes in Computer Science (LNCS) / Godefroid P. (ed.). - Vol. 3639. San Francisco, CA, USA. August 2005. - Springer-Verlag. - P. 58-74.

4. Symbolic model checking: 1020 states and beyond / J Burch, E. Clarke, K. McMillan, D Dill, and L. Hwang // Information and Computation. - 1992. -Vol. 98, No. 2. - P. 142-170.

5. Рудаков И. В., Р е б р и ко в А. В. Неполная верификация сложных дискретных систем // Информационные технологии. - 2011. - № 3. - С. 31-34.

6. P o d g u r s k i A. and C l a r k e L. A. A Formal Model of Program Dependences and its Implications for Software Testing, Debugging, and Maintenance // IEEE Trans. Softw. Eng. - 16, 9 (Sep. 1990). - P. 965-979.

7. Савенков К. О. Масштабирование дискретно-событийных имитационных моделей: дис. ... канд. физ.-мат. наук: 05.13.133. МГУ, 2007.

8. Gupta N., MathurA. P. and S o f f a M. L. Generating Test Data for Branch Coverage // Proc. of the 15th IEEE Int. Conf. on Automated Software. - 2000. -P. 219-227.

9. Р у д а к о в И.В., Р е б р и к о в А. В. Масштабирование алгоритмов для автоматической генерации модульных тестов // Вестник МГТУ им. Н.Э. Баумана. Сер. Приборостроение. -2011. -№ 4. - С. 119-126.

10. Р е б р и к о в А. В. Редукция операторов алгоритма для оптимизации времени структурной генерации модульных тестов / Материалы четырнадцатого научно-практич. семинара "Новые информационные технологии в автоматизированных системах". - М.: Моск. гос. ин-т электроники и математики, 2011. - С. 28-34.

11. Рудаков И. В., РебриковА. В. Неполная верификация систем, представленных в виде вероятностных автоматов с нечеткой функцией переходов // Информатика и системы управления в XXI веке: Сб. тр. молодых ученых, аспирантов и студентов МГТУ им. Н.Э. Баумана. - 2010. - С. 76-78.

12. Harrison. Applying Mccabe's complexity measure to multiple-exit programs: Software: Practice and Experience. October 1984. Vol. 14, Issue 10. - P. 1004-1007.

13. Брусенцов Л. Автоматическая оптимизация при компиляции [Электрон. ресурс]. [Режим доступа свободный] http://www.osp.ru/os/2011/02/13007711/

14. Comprehensive Perl Archive Network [Электрон. ресурс] http://cpan.org/ [Режим доступа свободный].

15. Comprehensive Perl Archive Network, pgriffin's author page [Электрон. ресурс] http://search.cpan.org/~pgrifQn/ [Режим доступа свободный].

16. Р е б р и к о в А. В. Автоматический генератор тестов. 2010. 02076881.0042501.

Статья поступила в редакцию 10.05.2012

i Надоели баннеры? Вы всегда можете отключить рекламу.