diff --git a/02-digital-image-processing.tex b/02-digital-image-processing.tex new file mode 100644 index 0000000..ebf993e --- /dev/null +++ b/02-digital-image-processing.tex @@ -0,0 +1,508 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\author{Алфимцев Александр Николаевич} +\title{Цифровая обработка изображений в информационных системах} +\date{2022-02-09} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\numerationTop +\usepackage{subfiles} + +\begin{document} +\thispagestyle{titlepage} +\maketitle +\newpage +\pagestyle{fancy} +\section{Введение} +Изображения всё больше оцифровываются. Мультимодальность в изображениях заключается в том, что человек много дополняет зрительную информацию (80\%) образами из головы. + +ЦОИ много применяется для медицины (последние годы особенно), полиграфии, оптического приборостроения. Мы будем использовать для распознавания образов. Главная математическая модель для ЦОИ - глубокие нейронные сети, глубокие свёрточные нейронные сети (джефри хилтон). ЦОИ это не только про распознавание, но и про фильтрации для получения дополнительной информации. Цои используется для кавтоматизации контроля производства (конвейерные линии) + +\begin{itemize} +\item 1980год Неокогнитрон +\item 1990-1995-свёрточные нейросети +\item 2012 DL революция в распознавании CNN +\end{itemize} + +Джеффри хинтон + +\begin{itemize} +\item ЦОИ = изображение - обработка - изображение +\item Компьютерное зрение = изображение - обработка - число (вектор, свёртка). данные и алгоритмы. +\item Машинное зрение - данные, алгоритмя, аппаратное обеспечение +\end{itemize} + +Актуальность ЦОИ: +\begin{enumerate} +\item изображение - главный источник информации +\item средства получения изображений дёшевы и распространены +\item последовательность изображений (видеопоток) - это биг дата +\item ЦОИ математическими методами и моделями - это простая и понятная иллюстрация их работы +\item автоматическая обработка цифровых изображений - самый выразительный пример развития искусственного интеллекта +\item Курс ЦОИ – фундаментальная структура современного технологического мировоззрения. +\end{enumerate} + +Будем использовать Python, в начале стараемся не использовать OpenCV, хотя им можно закрыть весь курс. + +Литература: +\begin{enumerate} +\item Gonzalez R., Woods R. Digital Image Processing (4th Edition). London: Pearson. 2018. 1019 p. ( Гонсалес Н., Вудс Р. Цифровая обработка изображений. Уч. пос. М.: Изд. “Техносфера”, 2012. 1104 с.) +\item Шапиро Л., Стокман Д. Компьютерное зрение; Пер. с англ.-М.: БИНОМ. Лаборатория знаний, 2006. 752 с. +\item Красильников Н. Н. Цифровая обработка 2D- и 3D-изображений : учеб. пособие для вузов / Красильников Н. Н. СПб. : БХВ-Петербург, 2011. 595 с. +\item Duda, Hart. Pattern Classification, 2nd edition. Wiley Interscience. 2001. +\item Пролетарский А.В., Алфимцев А.Н., Лычков И.И. Практикум по цифровой обработке изображений в компьютерных сетях. М.: МГТУ им. Н.Э. Баумана. 2016. 71 с. +\item Laganière R. OpenCV 3 Computer Vision Application Programming Cookbook. 2017. +\item Тарантино К. Цифровая фотография. Компьютерная обработка изображений. М.: Омега, 2005.- 142 с. +\end{enumerate} + +\textbf{Вопросы, решаемые курсом} +\begin{enumerate} +\item понятие цои +\item история цои +\item области применения цои +\item основные этапы цои +\item введение в теорию вероятности +\end{enumerate} + +\subsection{Понятие} +изображение - это двумерная функция f(x,y) где x и y это координаты в пространстве (на плоскости). Если величины x, y, f принимают дискретные значения, то изображение является цифровым (I[x,y]). + +\textbf{Цифровой обработкой изображений} называется обработка цифровых изображений с помощью цифровых вычислительных машин. Первое цифровое изображение содержало боксёра, цифровое изображение, полученное с использованием перфоленты это портреь Фрейда. Первые цифровые обработки связаны с фотографиями луны в 1958 и 1964 годах, соответственно. + +Области применения цои - слишком много, поэтому берём базовую идею. в бытовом смысле цои - это работа с видимым спектром. В промышленности (прикладная область цои) использует гораздо больший спектр электромагнитного излучения. +\begin{itemize} +\item гамма излучение - это медицинская радиология и космическая цои (остатки сверхновой, опухоли, боеголовка ядерной ракеты, рентгены, в том числе печатных плат). +\item Ультрафиолет (снимки зёрен, звёзд). +\item Инфракрасный диапазон (дистанционное зондирование, астрономия, световая микроскопия, промышленность, правоохранительная деятельность). +\item Терагерцевое излучение - между инфракрасным и СВЧ диапазоном. Используется в безопасности, например, просвечивает одежду +\item Микроволны. Радиолокация объектов +\item Радиоволны (медицина, астрономия), отслеживание спектров излучений. +\item Цифровые изображения могут быть получены сейсмически, ультразвуком, электронным микроскопом, фрактальные. +\end{itemize} + +База знаний курса, этапы ЦОИ +\begin{enumerate} +\item регистрация изображений; +\item улучшение изображения (improvement) - обработка с целью повысить качество для человека. +\item восстановление изображений (enhancement) - мат. Процедура которая основывается на модели шума. +\item обработка цветных изображений; +\item морфологическая обработка; +\item сегментация изображения; +\item описание изображения; +\item распознавание образов +\end{enumerate} + +\subsection{Введение в теорию вероятности} +Случайная величина (random variable) — это переменная, значения которой представляют собой исходы какого-нибудь случайного события (численное выражение результата случайного события). Вероятность (probability) — степень (относительная мера, количественная оценка) возможности наступления некоторого события. +\section{Аудио у Вики} + +\section{Пространственные методы улучшения изображений} +пространственные методы - слева-направо-сверху-вниз +частотные методы - через преобразование фурье превращается в набор коэффициентов. происходит переход и туда и обратно. + +основные градационные преобразования - работа над чб. $g(x,y) = T[f(x,y)]$. логарифмические формы и обратные лог формы функции это преобразование яркости, либо затемнение (обратный) либо осветление (прямой). Фильтрация происходит в рамках границ. +\begin{itemize} +\item Преобразование в негатив $s = L - 1 - r$. +\item логарифмическое преобразование $s = c\log(1+r)$ +\item степенные преобразования $s = cr^\gamma$. гамма-преобразование. положительная гамма затемняет, дробная осветляет. +\item кусочно-линейные функции преобразования - вырезание диапазона яркостей, усиление контраста. широкие возможности, но есть проблема производительности. вырезание битовых плоскостей +\end{itemize} +видоизменение гистограммы - отличная визуализация для человека. Гистограмма - это дискретная функция $h(r_k)$. по оси абсцисс если яркость 0-255 где 0 чёрное, то по ординатам будет кол-во пикселей, имеющих такую яркость. гистограммы используют только те пиксели, которые есть в изображении, ничего не домысливая. приёмы: +\begin{enumerate} +\item Эквализация Г - похожа на нормализацию. формулы пытаются проверить, является ли функция яркости однозначной и монотонной. +\item приведени гистограммы. не просто автоматически, а экспертно подбираем функцию. нужно чтобы специально обработать изображение. +\item локальное улучшение - любое из предыдущих улучшений, применённое локально. обычно это квадрат или прямоугольник. используется когда глобальная обработка сильно зашумит итоговое изображени +\item улучшение основанное на локальных статистиках. происходит сравнение локлаьного значения яркости с глобальным значением яркости, то есть если относительно ярче - делаем более ярким (улучшаем) по сигмаидальной функции отклонения +\end{enumerate} +арифметико-логические операции улучшения изображений - редкое применение в ЦОИ. поэлементно применяем к изображению. называется функционально-полный базис. операции используются для маскИрования изображения. с точки зрения задач улучшения делается для изолирования области. часто используются в морфологических операциях. +\begin{itemize} +\item Вычитание изображений - простейший алгоритм для обнаружения движения. +\item Усреднение изображения - сложение. используется для улучшения путём избавления от шума (выдержка). +\end{itemize} +пространственная фильтрация - математическая работа с фильтрами. обычно маски выбираются нечётных размерностей. маски называются свёртками. накрываем область маской. в результате получаем число. что делают с краями? заполняют нулями или дублируют крайние пиксели. Операция свёртки отличается от операции корелляции. + +Известные пространственные фильтры +\begin{itemize} +\item простейший линейный сглаживающий усредняющий фильтр (нч-фильтр) получает взвешенное среднее по окрестности. полезны для расфокусировки. можно выполнить обратное преобразование +\item медианный фильтр - нелинейное преобразование. +\item адаптивный медианный фильтр +\item пространственный фильтр повышения резкости. используется для увеличения резкости мелких деталей. основывается на пространственном диференцировании. дифференцирование позволяет усилить разрывы в изображения (не затрагивает области медленного изменения яркости). +\item улучшение изображений с использованием лапласиан - фильтр повышения резкости второй производной. +\item нерезкое маскирование и фильтрация с подъёмом частот. +\item градиент (первая производная). обобщение по модулю. на основании градиента получается оператор Собеля. +\end{itemize} +методы часто комбинируют, поскольку один метод чаще всего не решает задачу. общей теории нет, поэтому комбинации и порядок каждый раз разные. + + +\newpage +\section{Частотные методы улучшения изображений} +преобразование фурье и частотная область. любая периодическая функция может быть представлена как сумма синусов и косинусов, которая называется рядом фурье. + +Одномерное преобразование фурье это парные функции. можно применять к функциям двух переменных (ф-лы 3,4). дороговато работать с экспонентой, поэтому использовали ф-лу эйлера (7), что позволило получить привычный вид преобразований. + +дискретное прямое и обратное преобразование фурье (слайд13) + +фильтры и их свойства +\begin{enumerate} +\item фильтр-пробка 04-17. оптически вырезает начало координат. происходит падение общей яркости. +\item фильтр нч и вч. по названию понимаем, какие частоты пропускаются. это центрально-симметричные фильтры. чтобы не терять яркость добавляют дополнительные коэффициенты в фильтры вч. +\item гауссов фильтр. прямое и обратное ПФ это гауссовы функции. +\item сглаживающие частотные фильтры. ослабляем высокочастотные значения и получаем размытие. Идеальный ФНЧ по сути как фильтр-пробка, очень жёсткий. +\item ФНЧ Баттерворта (нечто среднее между идеальным и гауссовым) +\item гауссовы ФНЧ - гарантируют, что никакие артефакты после фильтрации не появятся +\item фильтры повышения резкости ослабляем низкочастотные колебания. идеальные ФВЧ с очень резким порогом +\item Баттерворт +\item Гаусс +\end{enumerate} + +Лапласиан в частотной области +получаем некоторое серое изображение, при наложении на исходное значительно повышаем резкость. + +\section{Обработка цветных цифровых изображений} +\subsection{Цветовые модели} +Исследование показало, что в цветовом пространстве HSI цвета кожи лежат в одном пространстве, что позволяет осуществлять обработку изображений с камер для управления жестами. В целом существует 6,2 млрд устройств, способных формировать изображения. Цветные изображения в видимом электромагнитном излучении это капля в море. (05-07) + +Цвет это субъективная характеристика. Глаз видит в RGB. Цвет фактически проходит через весь мозг до затылочной зоны. При интерпретации цветов для устройств (печать, например, используется CMYK). Для более-менее объективного представления цветов и определения возможностей цветопередачи, например, устройств, используют диаграммы цветности. + +\begin{figure}[H] + \centering + \includegraphics[width=8cm]{05-col-diag.png} + \caption{Диаграмма цветностей} + \label{pic:col-diag} +\end{figure} + + +Человеческий фактор в восприятии цвета обычно выражается в сопоставлении цветов явлениям. как, например, объяснить слепому, что такое красный или зелёный. То есть мозг интерпретирует цвета и дополняет эту интерпретацию образами или ощущуениями. Цвета часто дополняют друг друга или чёрно-белые изображения (эксперименты когда смотрим на точку в негативе, меняем на ЧБ изображение и видим цвет). + +Самое простое и частое представление цвета - это RGB. это обычный куб где в обном углу чисто белый в противоположеном чисто чёрный и по оси идут отенки серого. в дополнение к цвету дополняют дальномером для вычитания фона - это rgb-d. + +Обратное цветовое пространство - это cmyk. где cmy = 1 - RGB. + +HSI сразу даёт оценку основному цвету. в РГБ яркость размазана по компонентам, а здесь интенсивность выделена в отдельный компонент. большинство проблем компьютерного зрения решается. Недостаток - это очень дорогой переход из пространства RGB. + +YUV - пространство имеющее свои корни в телевидении. UV это цветность красного и синего. Y - это полутоновые значения. есть некоторая матрица перевода в RGB. + +\subsection{Обработка изображений в псевдоцветах} +Полутона это на самом деле трёхмерный объект. Чтобы превратить такое изображение в цвет осуществляют квантование по яркости. Самое распространённое это применение например при метеосводках или а аэропортах для контроля багажа - красим изображение в некоторые цвета. всегда очень много эвристики, надо понимать какие компоненты цвета квантовать. + +Часто псевдоцвета используются в космической отрасли или ДЗЗ. Либо преобразуем всё целиком, либо какую-то одну компоненту. + +Основы преобразований: \textbf{c} есть некоторый вектор в цветовом пространстве \textbf{RGB} +\begin{equation*} + \begin{gathered} + c = \Big[\substack{c_R\\c_G\\c_B} \Big] = \Big[\substack{R\\G\\B}\Big]\\ + c(x,y) = \bigg[\substack{c_R(x,y)\\c_G(x,y)\\c_B(x,y)} \bigg] = \bigg[\substack{R(x,y)\\G(x,y)\\B(x,y)}\bigg] + \end{gathered} +\end{equation*} + +\subsection{Цветовые преобразования} +Преобразование цветных изображений задается выражением: +\[ g(x,y) = T[f(x,y)] \] +Рассмотрим преобразование вида +\begin{equation*} + \begin{gathered} + s_i = T_i(r_1,r_2,...,r_n), i=1,2,...,n\\ + g(x,y)=kf(x,y)\\ + s_3=kr_3\\ + s_i=kr_i, i=1,2,3\\ + s_i=kr_i+(1-k), i=1,2,3 + \end{gathered} +\end{equation*} +в 3 к это коэффициент яркости. все простые цифровые преобразования работают и для цветовых преобразований. + +\begin{enumerate} +\item Цветовое дополнение. в полутонах использовали для поднятия яркости. для уветного изображения используется для преобразования в негатив. +\item Использование цветовых сочетаний - комплементарное (противоположные по HSI), аналогия (соседние), троичное (треугольник по HSI), сплит-комплементарное (контрастная триада), тетраидное сочетание (прямоугольник в HSI). Используются, например, в кино, для создания эффектов мякгости, уюта, экшна, привлечения внимания, дискотеки. +\item вырезание цветового диапазона +\item яркостная и цветовая коррекция (модель увета представлена сферой). смысл в том что надо сначала исправить яркость, чтобы работать с цветом. Некоторые цвета заложены в аналогиях в мозге. Мы глазами сразу видим расхождения в цвете, это обусловлено эволюционно. +\item Обработка гистограмм (нормализация и эквализация). можем потерять детали +\end{enumerate} + +\subsection{Сглаживание и повышение резкости} +\begin{itemize} +\item фильтр усреднения (сглаживание, интеграл). +\item повышение резкости с помощью лапласиана +\end{itemize} +\subsection{Цветовая сегментация} +выбираем компоненту которая ближе к искомому объекту, бинаризируем, сглаживаем и выделяем не просто порогом, а трёхмерное пороговое преобразование, которое более точное. + +Обнаружение контуров на цветных изображениях производится также выделением шума, в HSI не очень удобно, компоненты выдяелять сложнее. + +Усиление цвета - частая задача для подводных работ, поскольку цвет на глубине визуально меняется. Короризацию осуществляют нейросетями и свёртками. + + +\section{Морфологическая обработка изображений} +Также называют математической обработкой изображений. Теория множеств позволяет получить базовый математический аппарат, выполняющий обработки. +\subsection{Основы морфологической обработки} +\begin{itemize} +\item Центральное отражение $\hat{B} = \{ w| w=-b, b\in B \}$; +\item сдвиг $(A)_z = \{ c|c=a+z,a\in A \}$; +\item логические операция (функционально-полный базис) (06-06-13) +\item дилатация $A\oplus B = \{ z|(\hat{B}_z \cap A \neq \oslash)\}$ или $A\oplus B = \{ z|[(\hat{B}_z) \cap A] \subseteq A \}$; +\item эрозия $A\ominus B = \{z| (\hat{B}_z\subseteq) A\}$ (06-15); +\item размыкание в общем случае подсвечивает разрывы, расширяет (06-18) +\item замыкание в общем случае заливает узкие места изображения. +\item hit or miss transform (06-28) +\end{itemize} + +Операции размыкания и замыкания являются двойственными (06-22). Многократное применение операций не имеет действия. Эффект будет только один раз. +\subsection{Морфологические алгоритмы} +Это некий набор устоявшихся эвристик (комбинаций основных морфологических основ). +\begin{enumerate} + \setcounter{enumi}{-1} +\item (29) Определение отверстий, углов и связных признаков: при правильном выборе свёртки и операции успех/неудача у изображения будут «подсвечены» соответствующие части, например, отверстия, углы или границы; +\item (30) Выделение границ $\beta (A) = A - (A \ominus B)$. +\item (31) Алгоритм заполнения областей $X_k = (X_{k-1} \oplus B) \cap A^c$. Рекуррентная процедура, находим границу и границы заливки, и объединяем. +\item (32) Выделение связных компонент $X_k = (X_{k-1} \oplus B) \cap A$. Также рекуррентная процедура. Связанные компоненты это если между ними есть цепочка пикселей. +\item (33) Выпуклая оболочка. полезна для построения описания объектов. Используем 4 примитива, в отличие от остальных. Сама оболочка это объединение четырёх обработок. +\item (34) Уточнение. основано на успех/неудаче. +\item (35) Утолщение. двойственная операция от утончения. также можно записать серией примитивов +\item (36) Построение остова. сильно похож на утончение, применяется для сегментации сложных объектов +\item (42) Усечение. позволяет практически «вырастить» исходное изображение из минимального набора данных. область применения - распознавания рукописных знаков. есть допущение, что длина паразитных пикселей не должна быть больше полезной. так можно подавить паразитную ветку. у этого преобразования строго набранные примитивы и применяются в строгом порядке для получения концевых точек. +\item (43-48) Морфологическая реконструкция. сходная по работе с усечением. но кроме примитива используется более сложное изображение. +\end{enumerate} +\subsection{Применение морфологии к полутоновым изображениям} +\begin{enumerate} +\item дилатация (52) +\item эрозия (53) +\item (54) размыкание и замыкание применяются для устранения шумов. +\end{enumerate} +\subsection{Полутоновые морфологические алгоритмы} +\begin{enumerate} +\item морфологическое сглаживание избавление от шумов +\item морфологический градиент ищет границы исходного изображения +\item top-hat bottom-hat находит верхний и нижний уровень, коррекция затемнения +\item гранулометрия +\item текстурная сегментация +\item полутоновая морфологическая реконструкция +\end{enumerate} +Для сложных комбинаций используются нейронные сети и глубокое обучение. +\section{Сегментация цифрового изображения} +\subsection{Обнаружение областей} +Сегментация изображения – это процесс разбиения изображения на множество покрывающих его областей. +Две основные цели сегментации: +\begin{enumerate} +\item Декомпозиция изображения на части, более удобные для дальнейшей обработки. +\item Изменение формы описания изображения. (для уменьшения объёма хранения, например). +\end{enumerate} + +Ключевой вопрос, можно ли выполнять сегментацию снизу вверх без уч§та особенностей информации. Сегментация также называется бинаризация и возможна при помощи нечёткой логики. Желательные свойства сегментированных областей: +\begin{enumerate} +\item Области должны быть целостными и однородными по какому-либо признаку. (например по текстуре) +\item Внутренние части областей должны иметь простую форму и не содержать большое количество мелких отверстий. (хотя мелкие области могут формировать текстуру) +\item Смежные области должны существенно отличаться по значению сегментирующего признака. (по которыми они должны быть неоднородными) +\item Границы области должны иметь гладкую форму. (без зазубрин и разрывов) +\end{enumerate} + +Рассмотрим следующие алгоритмы сегментации, позволяющие обнаруживать области на цифровом изображении: +\begin{enumerate} +\item Итерационная кластеризация по математическому ожиданию. + + Кластеризация – это процесс разбиения множества векторов признаков на подмножества, называемые кластерами. + (07-08) + Будем рассматривать K кластеров $C_1, C_2, ..., C_K$ с математическими ожиданиями $m_z, m_2, ..., m_K$. Квадратичная ошибка определяется выражением + \[D = \sum_{k=1}^K \sum_{x_i \in C_k} || x_i - m_k ||^2\] + измеряем точки между собой и определяем центры, каждую точку сравниваем с центром полученного кластера и определяем, какая точка принадлежит какому кластеру. Алгоритм точно завершится, но нельзя заранее понять сколько кластеров (нужно задавать руками) + Формирование K кластеров на множестве n-мерных векторов. + \begin{enumerate} + \item присвоить счётчику итераций $ic$ значение 1 + \item случайным образом выбрать K значений математических ожиданий $m_1(1), m_2(1), ..., m_K(1)$ + \item для каждого вектора $x_i$ вычислить расстояние $D(x_i, m_k(ic))$ для каждого $k = 1, ..., K$ и поместить $x_i$ в кластер $C_j$ с ближайшим вектором математического ожидания + \item увеличить $ic$ на 1 и скорректировать значения математических ожиданий для получения нового множества $m_1(ic), m_2(ic), ..., m_K(ic)$ + \item повторять шаги 3 и 4 до тех пор, пока при всех $k$ не будет выполняться равенство $C_k(ic) = C_k(ic + 1)$. + \end{enumerate} + +\item Алгоритм кластеризации ISODATA. + \[x_i = [v_1, v_2, ..., v_n] \] + \[m_k = [m_{1k}, m_{2k}, ..., m_{nk}] \] + \begin{equation*} + \sum_k = \begin{bmatrix} + \sigma_{11} & \sigma_{21} & ... & \sigma_{1n} \\[0.3em] + \sigma_{12} & \sigma_{22} & ... & \sigma_{2n} \\[0.3em] + ... & ... & ... & ... \\[0.3em] + \sigma_{1n} & \sigma_{2n} & ... & \sigma_{nn} + \end{bmatrix} + \end{equation*} + + (07-12) + развитие евклидовых способов обработки изображений. +\item Алгоритм поиска моды гистограммы. + Относится к простым гистограммным методам. итерационные идут по исходным данным много раз, а эти один раз, то есть работает значительно быстрее. предназначен для сегментации в пространстве измерений. например, для выбора моды (мода в отличие от средних значений выбирается, а не вычисляется). + процедура бинаризации - это всегда преобразование в ч/б. +\item Рекурсивный гистограммный метод Оландера. + усовершенствование гистограммного метода. сначала ищется мода на полном изображении, а затем на каждом кластере, пока возможно сегментировать. + (07-16) + связанные компоненты маркируются, и снова вызывается метод. гистограммы не всегда работают на RGB. +\item Графовое разбиение Ши. + в отличие от предыдущих, работающих на простых изображениях. цель сегментации в нахождении такого количества вершин, чтобы были непересекающиеся множества, максимально отличающихся друг от друга. + (07-17,18) +\item Алгоритм наращивая областей Харалика + ищутся области из связанных пикселей с общим выборочным средним и дисперсией. Если выбрать пиксели с определённой интенсивностью, то область является областью с некоторой степенью свободы, куда может быть добавлена новая область с новым средним и новой дисперсией. +\end{enumerate} + +\subsection{Обнаружение контуров} +Рассмотрим следующие алгоритмы сегментации, позволяющие обнаруживать контуры на цифровом изображении: +\begin{enumerate} +\item Выделение границ областей на маркированном изображении. (24) +\item Детектор краев Кэнни. наиболее часто применяемый алгоритм. сначала сглаживаем изображение с сигмой, потом считаем направление градиента для максимального подавления. +\item Группировка согласующихся контуров в кривые. (27) +\item Преобразование Хафа. (31) + ищут обычно дуги окружностей, нелинейные отрезки. параметры выбираются вручную. +\end{enumerate} + +\subsection{Обнаружение моделей сегментов} +Рассмотрим подходы, позволяющие обнаруживать модели сегментов на цифровом изображении, в частности подбор прямой. +\begin{itemize} +\item подбор прямой (37) используется критерий наименьших квадратовПроблемы аппроксимации: +1. Выбросы. +2. Определения отклонения. +3. Нелинейная оптимизация. +4. Большая размерность. +5. Ограничения аппроксимации. +лентой называется продолговатой области, форма которой приблизительно симметрична относительно главной оси. часто, но не всегда края ленты характеризуются симметричным контрастом и фоном. +\item обнаружение углов (43) поиск характерных признаков и построение вектора движения, то есть работа уже в 4х мерном прстранстве +\end{itemize} + +главная архитектура - это кодер/декодер. главная модель - U-net. изображения сегментируют в базы данных, которые классифицируют. +\subsection{Обнаружение высокоуровневых структур} +\subsection{Обнаружение согласованного движения} +\subsection{Нейронные сети} + +\section{Описание цифрового изображения} +возможно представить область через внешние или через внутренние характеристики. Внешнее обычно выбирается если интересна форма, внутренняя если текстура или цвет. +1) Коды, линии, границы, области. +2) Дескрипторы границ. +3) Дескрипторы областей. + +Цепной код. с их помощью граница показывается в виде точек и соединений в одном направлении. важен момент аппроксимации, чтобы потом возможно было восстановить изображение обратно. иногда кодируют не абсолютными значениями, а разницей прошлой точки и следующей. + +Аппроксимация ломанной линией. цель - представить объект как можно меньшим числом линий. используются методы слияния, разбиения на различные отрезки (до выполнения критерия). + +сегменты границы. при декомпозиции упрощается описание за сч§т уменьшения сложности. обычно применяется если есть несколько ярко выраженных вогнутостей. на практике границы областей неровные, поэтому их можно сегментировать и отбросить неважное методами морфологического анализа. + +один из простейших дескрипторов - длина (возможно, с порогом отклонением). также можно использовать диаметр (две экстремальные точки, определяющие диаметр). эксцентриситет - величина границы (кривизна, которая определяется как скорость изменения угла наклона). + +Фурье дескрипторы обходят границу и представляют ея в виде последовательности координат (комплексных чисел). применив дискретное преобразование - получим фигуру с заданной точностью. + +статистические характеристики это средние, дисперсии, и так далее. характеризовать можно не только яркость, но и цвет, и так далее. здесь рассматриваются амплитуды и строятся гистограммы, чтобы наложить изображение на координатную ось, которое можно нормализовать и преобразовать. с точки зрения реализации явно указывается простота. + +дескрипторы областей +\begin{itemize} +\item площадь (число пикселей внутри) +\item периметр (кол-во пикселей на периметре) +\item компактность (наличие неровностей) +\item среднее значение яркостей пикселей +\item медиана яркостей пикселей +\end{itemize} + +Топологические дескрипторы +если нет разрывов и склеек - это область изучения топологии. + +Текстурные дескрипторы +Отсутствует формальное определение, но интуитивно понятно, что есть гладкость, шероховатость, периодичность. Для определения текстуры есть статистический, структурный и спектральный подходы. + +моменты двухмерных функций. с исходным изображением совершили несколько манипуляций и получили несколько инвариантов + +\section{Распознавание образов} +Самый популярный способ - машины опорных векторов. в них возможно использовать не только одномерные но и двухмерные (линейные базисные функции). но этот подход неустойчив к шуму. У деревьев решений также есть ряд недостатков: недостаточность данных, многозначные атрибуты. + +Есть также кластерный анализ (как в сегментации). + +SIFT. +\appendix +\setcounter{secnumdepth}{0} +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Alph{subsection}} + +\subsection{Семинар 1 (2022-02-16)} +Книга: Dictionary of computer vision and image processing + +Вопросы нам: +\begin{itemize} +\item \textbf{color quantization}: The quantization (i.e., discretization) of the image sig- nal into a number of bins each rep- resenting a specific level of intensity (i.e., pixel values). Occurs at image capture, at the CCD or CMOS sensor level, within the camera. For RGB color image capture this is facilitated using the Bayer pattern on the sensor itself. +Also performed as a secondary process, re-quantization for color reduction or color re-mapping: Coarser quantization allows image compression with fewer bits. [SB11:2.3.2] +\item color re-mapping: An image transfor- mation where each original color is replaced by another color from a col- ormap. If the image has indexed col- ors, this can be a very fast opera- tion and can provide special graphical effects for very low processing over- head: [WAF+98] +\item Feret’s diameter: The distance between two parallel lines at the extremities of some shape that are tangential to the boundary of the shape. Maximum, minimum and mean values of Feret’s diameter are often used (where every possible pair of parallel tangent lines is considered): [WP:Feret\_diameter] +\end{itemize} + +Наши возможные вопросы: +\begin{multicols}{2} + \includegraphics[width=7cm]{sem-02-illum.png} + + \columnbreak + coaxial illumination: Front lighting with the illumination path running along the imaging optical axis. An advantage of this technique is that there are no visible shadows or direct specularities from the camera’s viewpoint. +\end{multicols} + + + +\subsection{Семинар 2 (2022-03-16)} +При МО мы имеем изображения как на входе так и на выходе, то есть в отличие от частотной нет промежуточного результата. + +МО использует математику множеств. +множеству можно принадлежать или не принадлежать, множества можно объединять, у множеств бывают пересечения. Множества можно вычитать. Математическое множество можно перевернуть (отражать) и осуществить параллельный перенос. + +В морфологии изображений есть два базовых понятия +\begin{itemize} +\item Дилатация - это все такие точки З, что перенос отражённого Б в эту точку принадлежит множеству А. Все переносы считаются относительно центра примитива Б.маленький квадрат Б двигаем внутри большого квадрата А и там точно есть хотя бы одна общая точка. Дилатация Б приводит к расширению А. +\item Эрозия - наоборот А как-то схлопывается. $A\ominus B = \{z | (B_z) \subseteq A\}$. Так мы можем убирать какие-то помехи и шумы. +\end{itemize} + +Из этих базовых операций складываются операции замыкания и размыкания. смыкание для сглаживания контуров. Размыкание - это сначала эрозия, потом дилатация А по Б. Замыкание - обратная операция - сначала дилатация А по Б, затем эрозию А по Б. +Если берём А треугольник, а Б круг - при размыкании получим такой же треугольник, но с закруглёнными углами. +У размыкания есть свойства. А размыкание Б всегда лежит в А. +\begin{enumerate} +\item $A\odot B \subseteq A$ +\item $C \in D, C \odot B \subseteq B \in D \odot B$ +\item $(A\odot B) \odot B = A\odot B$ +\end{enumerate} + +\subsection{Семинар 3 (2022-04-13)} +Вариант 9 + + +1. Поменять местами второй и пятый столбцы матрицы. Нумерация идет слева направо. +2. Поменять местами первую и вторую строку. Нумерация идет сверху вниз. +3. Выполнить траспонирование матрицы +4. Горизонтальный переворот матрицы. Первый столбец становится пятым и т.д. +5. Увеличение яркости. К каждому значению RGB прибавить 20. +6. Уменьшение яркости. Из каждого значения RGB вычесть 30. +7. Выполнить обработку матрицы согласно эффекту сепия. +8. Выполнить обработку матрицы согласно эффекту оттенки серого. +9. Сделать изображение черно-белым. +\subsection{Семинар 4 (2022-04-27)} +ForeSight +\subsection{Семинар 5 (2022-05-11)} +Вариант 9 + +Разделы автореферата +- степень разработанности проблемы; +написано будто задачи поставлены и решены, но явного указания (раздела) нет + +- материал и методы исследования (предмет и объект исследования, методологическая и теоретическая база исследования); +методы и инструменты описаны, но раздела с материалом нет + +?+ теоретическая и практическая значимость работы; +описана только практическая + +- выводы; +(описаны основные результаты работы, но не указаны места сообщений и не сделаны выводы) + +- практические рекомендации; +раздел практических рекомендаций также отсутствует + +Подробнее: +Актуальность: не указана научная (но значительно раскрыта практическая) +Цели+ +Задачи+ +Предмет- +Объект- +Положения на защиту+ но не указан личный вклад (изложение не структурировано, просто перечислены пункты) +Научная новизна+ но не соответствует структуре (нет новых проблем, не устанавливаются связи) +Практическая значимость формально+ но никакой аналитики нет (экономика, масштабы, итд) +Обоснование соответствия диссертации паспорту специальности указано, но не указаны в примерах + + +\end{document} \ No newline at end of file diff --git a/02-digital-signal-processing-micro-devices-lecture.tex b/02-digital-signal-processing-micro-devices-lecture.tex new file mode 100644 index 0000000..1990c65 --- /dev/null +++ b/02-digital-signal-processing-micro-devices-lecture.tex @@ -0,0 +1,3053 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\author{Выхованец Валерий Святославович} +\title{Микропроцессорные устройства обработки сигналов} +\date{2022-02-11} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\numerationTop +\usepackage{subfiles} +\newcommand\ver[1]{\rotatebox{90}{#1 }} + +%% This code creates the groups +% ----------------------------------------- +\usepackage{etoolbox} +\renewcommand\nomgroup[1]{% + \item[\bfseries + \ifstrequal{#1}{C}{Общие}{% + \ifstrequal{#1}{A}{Применение}{% + \ifstrequal{#1}{P}{Процессор}{% + \ifstrequal{#1}{M}{Память}{% + \ifstrequal{#1}{I}{Ввод-вывод}{% + \ifstrequal{#1}{O}{Прочие}{} + } } } } }% + ] +} +% ----------------------------------------- + +\begin{document} +\maketitle +\newpage +\tableofcontents +\newpage +\section{Введение} +\tiny +дз1 = док Д6. особенное внимание к оформлению лаб и дом работ. разделитель десятичной части - запятая. +\normalsize +\subsection{Понятие обработки сигналов} +имеются аналоговые входные и выходные сигналы, и есть цифровая часть. +Аналоговый сигнал усиливается, фильтруется, АЦПируется, получили $x(\tau)$ буферизируется и поступает на сигнальный процессор, преобразуется в выход, задержанный на n тактов, поэлементно ЦАП, фильтруется и усиливается или ослабляется (рис. \hrf{pic:SignalProcessing}). +\begin{figure}[h] + \centering + \includegraphics[width=15cm]{00-SP.png} + \caption{Обработка сигналов} + \label{pic:SignalProcessing} +\end{figure} + +То есть всегда накапливается n отсчётов и обработка происходит "пакетно", поскольку для одного значения не имеют смысла. Сигналы всегда задержаны на n тактов. Сигнальные процессоры бывают с фиксированной и плавающей запятой. + +Узкое место фон-Неймановой архитектуры - один канал для доступа и управления и к командам и к данным. сигнальные процессоры разделяют каналы данных и команд (слайд19), гарвардская архитектура. Сигнальные процессоры позволяют отказаться от кэш-памяти совсем. + +\subsection{Сигнальные процессоры} +СП сами по себе не используются, только в связке с другими процессорами. тактовые частоты обычно небольшие (поскольку данные поступают одновременно с командами, без задержек) из-за этого сильно развита ковейеризация. Прямой доступ к памяти доведён до максимума, нет времени заниматься вводом-выводом. + +\begin{figure}[h] + \centering + \includegraphics[width=10cm]{00-SPC.png} + \caption{Устройство обработки сигналов} + \label{pic:inner-spd} +\end{figure} + +Внутри (рис. \hrf{pic:inner-spd}) имеются средства обработки запросов пользователя, асики, два сигнальных ядра (внутри каждого есть память и у сигнальных ядер есть общая память). вся обработка осуществляется через кодеки. на примере на слайде указана ПЛИС для радиочастотного интерфейса. + +\nomenclature[C]{ASIC}{Analog Specific Integrated Circuit (схема сопряжения)} +\nomenclature[C]{DSP}{Digital Signal Processors (процессор цифровой обработки сигналов)} +\nomenclature[C]{GPP}{General Purpose Processors (процессор общего назначения)} +\nomenclature[C]{FPGA}{Field Programmable Gate Array (программируемая логическая матрица)} +\nomenclature[C]{NoC}{Network on Chip (вычислительная сеть на кристалле)} +\nomenclature[C]{RF}{Radio Frequency} +\nomenclature[C]{Shared Bus}{общая шина} +\nomenclature[C]{SoC}{signal system on chips (обработка сигналов на кристалле)} +\nomenclature[C]{VLSI}{very large scale integration (сверхбольшая степень интеграции)} +\nomenclature[C]{CISC}{Complex Instruction Set Computer (проц. слож. набор команд)} +\nomenclature[C]{RISC}{Reduced Instruction Set Computer (проц. сокр. набор команд)} +\nomenclature[C]{ARM}{Advanced RISC Machine (усовершенствованный RISC-проц.)} +\nomenclature[C]{HDMI}{High-Definition Multimedia Interface, мультимедийный интерфейс} +\nomenclature[C]{MHL}{Mobile High-definition Link(1/2 HDM, TX - Transmit)} +\nomenclature[C]{NAND}{флэш-память типа NOT-AND} +\nomenclature[C]{NOR}{флэш-память типа NOT-OR} +\nomenclature[C]{SD/SDIO}{Secure Digital Input Output, интерфейс карт памяти SD} +\nomenclature[C]{FPU}{Float Pointer Unit, процессор с плавающей запятой} +\nomenclature[C]{GPU}{Graphics Processing Unit, графический процессор} +\nomenclature[C]{PLL}{Phase Locked Loop, фазовая автоподстройка} +\nomenclature[C]{RTC}{Real Time Clock, часы реального времени} +\nomenclature[C]{DAC}{Digital to Analog Converter, цифро-аналоговый преобразователь} +\nomenclature[C]{ADC}{Analog to Digital Converter, аналого-цифровой преобразователь} +\nomenclature[C]{PWM}{Pulse Width Modulation, широтно-импульсная модуляция} +\nomenclature[C]{(LP)DDR}{Low Power Double Data Rate, синхронная динам. память} +\nomenclature[C]{eMMC}{Embedded Multi Media Card, встроенный интерфейс карт} +\nomenclature[C]{SPI}{Serial Peripheral Interface, последов. периферийны интерфейс} +\nomenclature[C]{ROM}{Read Only Memory, постоянное запоминающее устройство} +\nomenclature[C]{SIMD}{Single Instruction Multiple Data, одна команда, много данных} +\nomenclature[C]{TRNG}{True Random Number Generator} +\nomenclature[C]{eFuse}{память динамического программирования микросхем} +\nomenclature[C]{HDR}{High Dynamic Range, увеличение динамического диапазона} +\nomenclature[C]{SSE(2)}{Streaming SIMD Extensions (2), потоковое SIMD-расширение} +\nomenclature[C]{H.264}{Advanced Video Coding, стандарт сжатия видео} +\nomenclature[C]{H.265}{High Efficiency Video Coding, стандарт сжатия видео} +\nomenclature[C]{VP9}{Video Processing 9, стандарт сжатия видео от Google} +\nomenclature[C]{JPEG}{Joint Photographic Experts Group, растровый формат} +\nomenclature[C]{USB}{Universal Serial Bus, универсальная последовательная шина} +\nomenclature[C]{PCIe}{Peripheral Component Interconnect Express, компьютерная шина} +\nomenclature[C]{SATA}{Serial Advanced Technology Attachment, посл. обмен данными} +\nomenclature[C]{MAC}{Media Access Control, управление доступом к среде} +\nomenclature[C]{PHY}{Physical layer, физический уровень} +\nomenclature[C]{IR}{Infrared interface, инфракрасный интерфейс} +\nomenclature[C]{TX/RX}{Transmitter/Receiver, передатчик-приемник} +\nomenclature[C]{GMII}{Gigabit Media-Independent Interface, гигабитный интерфейс} +\nomenclature[C]{RGMII}{Reduced GMII (1/2 GMII), улучшенный гигабитный интерфейс} +\nomenclature[C]{SGMII}{Serial GMII, последовательный гигабитный интерфейс} +\nomenclature[C]{Serial TP}{Serial Twisted Pair, витая пара} +\nomenclature[C]{UART}{Universal Asynchronous Receiver-Transmitter, УСПП} +\nomenclature[C]{GPIO}{general-purpose input/output, универсальный вход-выход} +\nomenclature[C]{I2C}{Inter-Integrated Circuit, приборный интерфейс} +\nomenclature[C]{LSADC}{Low Speed ADC, низкоскоростной многоканальный АЦП} +\nomenclature[C]{I2S}{Integrated Inter-chip Sound, звуковой интерфейс} +\nomenclature[C]{CEC}{Consumer Electronics Control, управление бытовой электроникой} + +\section{Обработка сигналов} +ЦОС - это дискретная обработка сигналов. ЦОС - это обработка одномерных массивов, изображений - двумерных массивов. несмотря на то, что изображения приходят построчно + +\textbf{Сигнал} – физический процесс, протекающий во времени и отражающий состояние некоторого объекта наблюдения + +\textbf{Аналоговый сигнал} – непрерывная функция времени: +\[ \chi(t)\in[\chi_{min},\chi{max}]; t\in[t_{min},t_{max}]. \] + +\textbf{Дискретный сигнал} – последовательность отсчетов аналогового сигнала в дискретные моменты времени с дискретными значениями: \[x(\tau)\in \overline{0, L - 1} (\tau = \overline{0, N - 1}).\] + +слайд 4 +(непрерывность - это математическое обобщение) +\begin{multicols}{2} + \textbf{Квантование по времени} + \[ \chi(t) \in [\chi_{min},\chi_{max}], t \in[t_{min}, t_{max}] \] + \[ \Rightarrow \chi(\tau) \in [\chi_{min}, \chi_{max}](\tau = \overline{0, N-1}) \] +\columnbreak +\begin{tikzpicture} + \begin{axis}[ + domain=0:360, axis x line*=middle, xtick=\empty, samples=15, width=9cm, height=4.5cm, + xlabel=$t$, ylabel=$x(t)$ + ] + \addplot [ycomb, mark=triangle*, thick, mark size=1] {sin(x) + 1}; + \addplot [densely dotted, samples=51] {sin(x) + 1}; + \end{axis} +\end{tikzpicture} +\end{multicols} + +\begin{multicols}{2} + \textbf{Квантование по уровню} + \[ \chi(\tau) \in [\chi_{min}, \chi_{max}] \Rightarrow \chi(\tau) \in \overline{0, L - 1} \] + \columnbreak +\begin{tikzpicture} + \begin{axis}[ + domain=0:360, axis x line*=middle, xtick=\empty, samples=30, width=9cm, height=4.5cm, + xlabel=$t$, ylabel=$x(t)$ + ] + \addplot [const plot mark mid, very thick, gray] {sin(x) + 1}; + \addplot [densely dotted, samples=51] {sin(x) + 1}; + \end{axis} +\end{tikzpicture} +\end{multicols} + +\begin{multicols}{2} + \textbf{Дискретный сигнал} + \[ \chi(\tau) \in \overline{0, L - 1} (\tau = \overline{0, N-1}) \] + \[ t = t_{min} + \tau T, T = \frac{t_{max} - t_{min}}{N} \] + \[\chi = \chi_{min} + x D, D = \frac{\chi_{max} - \chi_{min}}{L}\] + \columnbreak +\begin{tikzpicture} + \begin{axis}[ + domain=0:360, axis x line*=middle, xtick=\empty, samples=15, width=9cm, height=4.5cm, + xlabel=$t$, ylabel=$x(t)$ + ] + \addplot [const plot mark mid, very thick, gray] {sin(x) + 1}; + \addplot [ycomb, mark=triangle*, thick, mark size=1] {sin(x) + 1}; + \addplot [densely dotted, samples=51] {sin(x) + 1}; + \end{axis} +\end{tikzpicture} +\end{multicols} + +\subsection{Что мы, в принципе, можем сделать с сигналом?} +\label{subsect:methods} +\begin{itemize} +\item \textbf{Передискретизация} – изменение частоты дискретизации (многоскоростная обработка). + \[ x(0), x(1),... , x(N - 1) \Rightarrow y(0), y(1),... , y(M - 1) \] +Представлена процессами \textbf{децимации} и \textbf{интерполяции}. При интерполяции - дополняем отсчёты промежуточными (увеличение частоты дискретизации) и пытаемся аппроксимировать. При децимации наоборот, уменьшение частоты дискретизации. +\item \textbf{Преобразование} – функциональное преобразование сигнала по одному отсчету. +\begin{itemize} +\item Нелинейное $ y(\tau) = f(x(\tau)) (\tau = \overline{0, N - 1})$; +\item Модуляция $ y(\tau) = f(x(\tau), m(\tau)) (\tau = \overline{0, N - 1})$; +\item Манипуляция $ y(\tau) = f(x(\tau), b(\tau)) (\tau = \overline{0, N - 1})$. +\end{itemize} +Выполняется независимо от других отсчётов. например нелинейное преобразование - это ограничение звукового сигнала. В отличие от простого ограничения происходит плавное изменение максимума. Иногда преобразование происходит с учётом какого-то другого сигнала - это манипуляция или модуляция. Как примеры: нелинейное - просто обрезать крайние значения синусоиды до уровня. Модуляция, манипуляция - АМ, ЧМ, ФМ. +\item \textbf{Корреляция} – проверка степени линейной зависимость сигналов. + \begin{equation*} + \begin{split} + r(\tau) = \frac{1}{N}\sum_{k=0}^{K - \tau - 1}x(\tau + k) \times y(k)\\ + (\tau = \overline{0, K-1})\\ + K = N + M - 1\\ + x(i \pm N) = x(i) (i = \overline{0, N - 1})\\ + y(j \pm M) = y(j) (j = \overline{0, M - 1}) + \end{split} + \end{equation*} + + \begin{figure}[H] + \centering + \begin{subfigure}[b]{0.6\textwidth} + \centering + \includegraphics[width=\textwidth]{01-correl1.png} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.3\textwidth} + \centering + \includegraphics[width=\textwidth]{01-correl2.png} + \end{subfigure} + \end{figure} + +Используются при обработке сигналов связи. Сравниваем входящий сигнал который имеет N отсчётов с другим сигналом с M отсчётов и определяем меру подобия. Считается мерой линейной связи сигналов. Вычисляем похожесть с учётом сдвигов сигналов относительно друг друга. Фактически получается сумма произведений сигналов. Когда смещение сигналов нулевое - корелляционная функция максимальная. +\item \textbf{Фильтрация (не)рекурсивная} – нелинейная (линейная) обработка сигнала. + \[ y(\tau) = \sum_{i=0}^{H-1} h(i) \times x(\tau - i) (\tau = \overline{0, N - 1}) \] + + Функция, которую можно представить как линейную обработку сигналов (также сумма произведений). Например, усреднение сигнала. Для работы надо знать несколько предыдущих значений (на глубину количества отсчётов импульсной характеристики). Важно не забыть про значения задержки. Коэффициенты можно посчитать в матлабе. Это фильтр с конечной импульсной характеристикой. + \begin{figure}[H] + \centering + \begin{subfigure}[b]{0.2\textwidth} + \includegraphics[width=\textwidth]{01-fic1.png} + \end{subfigure} \hfill + \begin{subfigure}[b]{0.5\textwidth} + \includegraphics[width=\textwidth]{01-fic2.png} + \end{subfigure} + + \begin{subfigure}[b]{0.2\textwidth} + \includegraphics[width=\textwidth]{01-fic3.png} + \end{subfigure} \hfill + \begin{subfigure}[b]{0.7\textwidth} + \includegraphics[width=\textwidth]{01-fic4.png} + \end{subfigure} + \end{figure} + + + \textbf{Рекурсивный фильтр} - есть обратные связи. Бесконечная импульсная характеристика. +\[y(\tau) = \sum_{i=0}^{H-1} h(i) \times x(\tau - i) - \sum_{j=1}^G g(j) \times y(\tau - j) (\tau = \overline{0, N - 1})\] +Повторяет нерекурсивный фильтр и добавляется ещё G элементов задержки. Индекс значений начинается с нуля, а выходных отсчётов с единицы. Характерны возможностью возбуждения (как микрофон возле динамика), неверно подобранные коэффициенты могут приводить к неустойчивости фильтра. На рис. фильтр устойчивый, потому что площадь над Х больше площади под Х. Все нерекурсивные фильтры устойчивы. +\begin{figure}[H] + \centering + \includegraphics[width=17cm]{01-iic1.png} +\end{figure} + +\item \textbf{Фильтрация адаптивная} – фильтрация с изменением характеристик фильтра. + \begin{tikzpicture}[ + x=0.75pt, y=0.75pt, + yscale=-1, xscale=1, + outline/.style={draw=#1, thick}, + outline/.default=black, + ] + \tkzblk{outline}{75,100}{АЦП} + \tkzblk{outline}{175,100}{АУ} + \tkzblk{outline}{175,50}{П} + \tkzblk{outline}{175,150}{ГС} + \tkzblk{outline}{275,100}{ЦАП} + \tkzblk{outline}{375,100}{СФ} + + \draw [dashed] (150,25) rectangle (200, 125); + \draw [-|>] (0, 100) -- (48,100) node[above left] {$x(t)$}; + \draw [-|>] (102, 100) -- (155,100) node[above left] {$x(n)$}; + \draw [-|>] (195, 100) -- (248,100) node[above left] {$y(n)$}; + \draw [-|>] (302, 100) -- (355,100) node[above left] {$y(t)$}; + \draw [-|>] (395, 100) -- (455,100) node[above left] {$\tilde{y}(t)$}; + \draw [-|>] (175, 135) -- (75,115); + \draw [-|>] (175, 135) -- (175,115); + \draw [-|>] (175, 135) -- (275,115); + \draw [-] (190, 50) -- (275,40) node[right]{Процессор}; + \draw [<|-] (165, 65) -- (165,85); + \draw [-|>] (185, 65) -- (185,85); + \end{tikzpicture} + + \begin{figure}[H] + \includegraphics[width=17cm]{01-adapt.png} + \end{figure} + + Цифровая фильтрация: имеется АЦП, генератор тактов, и арифметическое устройство, накапливающий сумматор, ЦАП. Адаптивная фильтрация - это фильтр при которой изменяются коэффициенты фильтра. Обычно это нерекурсивная фильтрация, но можно сделать и рекурсивный фильтр. При адаптивной фильтрации имеется дополнительный вход с шумами сопровождающими полезный сигнал. Шум попадает в блок адаптации чтобы изменять коэффициенты, это делается для того, чтобы минимизировать ошибку. + \begin{equation*} + \begin{split} + y(\tau) = \sum_{i=0}^{H-1} h(i) \times x(\tau - i)\\ + e(\tau) = d(\tau) - y(\tau)\\ + \tilde{h}(i) = h(i) + \mu \times e(\tau) \times x(\tau - i)\\ + i = \overline{0, H-1}; \tau = \overline{0, N - 1}; \mu \in (0,1] + \end{split} + \end{equation*} +\item \textbf{Спектральная обработка(13-16)} – обработка сигнала в спектральной области. + + \includegraphics[width=15cm]{01-spectral1.png} + + самое сложное - это спектральное преобразование Фурье. Сложное не только потому что раскладываем не только во времени, но и в амплитуде. Один комплект отсчётов для амплитуды, а второй для фазы. Получив коэффициенты можем менять сам сигнал. Для обработки изображений используется косинусное преобразование (для сжатия изображений). В дискретном виде спектральное преобразование выглядит следующим образом: +\begin{enumerate} +\item прямое коэффициенты умножаем на матрицу получаем вектор для преобразования. + \[c(i) = \sum_{\tau=0}^{N-1} r_i(\tau) \times x(\tau); C = R \times X\] +\item обратное коэффициенты умножаем на матрицу обратного преобразования - получаем входной сигнал. + \[x(\tau) = \sum_{i=0}^{N-1} s_\tau(i) \times c(i); X = S \times C\] +\item если взять матрицы из первых двух пунктов и умножить - получим единичную матрицу. + \[ \delta_{i\tau} = \sum_{j=0}^{N-1} r_i(j) \times s_\tau(j); R \times S = I\] +\end{enumerate} + +\includegraphics[width=15cm]{01-spectral3.png} + +сложность в том что мы ловим операции, которые можно исключить. На практике используются только быстрые преобразования фурье - это не просто умножение матриц, а некоторые умножения исключаются. Также существуют вариации спектрального преобразования + +\includegraphics[width=15cm]{01-spectral2.png} + +В этой обработке предполагается восстановление сигнала - после ЦАП ставим фильтр низких частот. + +\includegraphics[width=15cm]{01-spectral4.png} + +Частота среза фильтра считается по теореме Котельникова. + +\includegraphics[width=15cm]{01-spectral5.png} + +\end{itemize} + +\section{Представление целых чисел} +Используются числа с фиксированной запятой из-за скорости таких вычислений. +Числа бывают: +\begin{itemize} +\item Натуральные числа: N8, N16, N32, N64. Число = разрядность, N = натуральное +\item Целые числа: Z8, Z16, Z32, Z64. (\textit{Z, видимо, znakovoe, прим. Овчинников}) +\item Числа с фиксированной запятой: Q4.12, Q1.15, Q1.31. Числа = разрядности до и после запятой, соотвествтенно\footnote{Wikipedia: The Q notation, as defined by Texas Instruments, consists of the letter Q followed by a pair of numbers m.n, where m is the number of bits used for the integer part of the value, and n is the number of fraction bits.} +\item Числа с плавающей запятой: F32, F64, F80. F = floating point. +\item Рациональные числа $\frac{\text{числитель}}{\text{знаменатель}}$: R8, R16, R32, R64. +\item Логарифмические форматы (логарифм значения и знак). +\item Символьные форматы. +\end{itemize} +\subsection{Целые и натуральные числа} +Натуральные числа представлены двумя типами: знаковым и беззнаковым. Знаковое представлено в дополнительном коде. +\begin{frm} + \textit{Фрагмент (Овчинников, неопубликованное, 2019)}: Преобразование из системы счисления с бОльшим основанием в систему счисления с меньшим основанием производится последовательным делением исходного числа на основание системы счисления и записи остатков такого деления в младшие разряды. Например: + \[ + \frac{116}{2} = \frac{58 (0)}{2} = \frac{29 (0)}{2} = \frac{14 (1)}{2} = \frac{7 (0)}{2} = \frac{3 (1)}{2} = \frac{1 (1)}{2} = 1 < 2 + \] + В этом примере полученные остатки от деления записаны в скобках. Обратное преобразование - это последовательное умножение разрядов числа на величину каждого разряда с их аккумулированием к общему результату: + \begin{equation*} + \begin{gathered} + 1110100 = 0 \cdot 2^0 + 0 \cdot 2^1 + 1 \cdot 2^2 + 0 \cdot 2^3 + 1 \cdot 2^4 + 1 \cdot 2^5 + 1 \cdot 2^6 = \\ + 0 \cdot 1 + 0 \cdot 2 + 1 \cdot 4 + 0 \cdot 8 + 1 \cdot 16 + 1 \cdot 32 + 1 \cdot 64 = \\ + 4 + 16 + 32 + 64 = 116 + \end{gathered} + \end{equation*} +\end{frm} +\textbf{Формат N:} при последовательном сложении значений разрядов, умноженных на двойку в степени позиции в приведённой ниже таблице получим число 33121. + + \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|} + $x_{15}$ & $x_{14}$ & $x_{13}$ & $x_{12}$ & $x_{11}$ & $x_{10}$ & $x_{9}$ & $x_{8}$ & $x_{7}$ & $x_{6}$ & $x_{5}$ & $x_{4}$ & $x_{3}$ & $x_{2}$ & $x_{1}$ & $x_{0}$ \\ [0.5ex] + $2^{15}$ & $2^{14}$ & $2^{13}$ & $2^{12}$ & $2^{11}$ & $2^{10}$ & $2^{9}$ & $2^{8}$ & $2^{7}$ & $2^{6}$ & $2^{5}$ & $2^{4}$ & $2^{3}$ & $2^{2}$ & $2^{1}$ & $2^{0}$ \\ [0.5ex] + \hline + 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 1 \\ + \hline + \end{tabular} +\[ X = \sum_{i=0}^{15} x_i \cdot 2^i \] +\textbf{Формат Z:} Знаковым является самый старший разряд, соответственно, даёт наибольшее промежуточное значение с нужным знаком, чтобы никакие дальнейшие вычисления не смогли сменить знак. Поэтому аналогичное двоичное представление числа при вычислениях со знаком даст результат -32415. +\[ X = -s \times 2^{15} + \sum_{i=0}^{14} x_i \cdot 2_i \] + +Соответственно, при любой разрядности (L03-04, L03-05), с точностью $\varepsilon = 1$ (поскольку числа - целые), у беззнаковых чисел все биты занимаются хранимым значением, а у знаковых старший бит отводится под знак, отсюда диапазоны возможных принимаемых значений\footnote{квадратные скобки означают нестрогое неравенство, включение во множество, круглые скобки означают строгое неравенство, исключение из множества}: +\begin{itemize} +\item [N16] $[0,65535]$ +\item [Z16] $[-32768,32767]$ +\item [N32] $[0,4929967295]$ +\item [Z32] $[-2147483648,2147483647]$ +\end{itemize} +Шестнадцатиричное представление аналогично двоичному, просто двоичные разряды разделены на тетрады и обозначаются цифрами 0-F. + +\subsection{Внутренний формат} +\textbf{N40 [0, 1099511627775].} Это обычные 32-разрядные целые числа и 8 защитных разрядов (защищают от переполнения). +\begin{frm} +Для смены знака числа нужно инвертировать разряды и добавить единицу. АЛУ работает только со сложением и все остальные операции работают через него. +\end{frm} +Для беззнаковых чисел есть флаги переноса и заёма (CF,SF). + +\begin{tikzpicture} +\draw (0,0)coordinate (O)--++(30:1)coordinate (A)--++(90:2)coordinate (B)--++(150:1)coordinate (C)--cycle; +\draw [->]($(A)!0.5!(B)$)--++(0:1)node[right]{$Z(N40)$}; +\draw [->]($(O)!0.5!(A)$)--++(-90:1)--++(0:2)node[right]{$CF$}; +\draw [->]($(O)!0.25!(A)$)--++(-90:1.5)--++(0:2.25)node[right]{$SF$}; +\draw [->]($(O)!0.75!(A)$)--++(-90:0.5)--++(0:1.75)node[right]{$ZF$}; +\draw [<-]($(B)!0.5!(C)$)--++(90:0.5)--++(180:1.75)node[left]{$C_0$}; +\draw [<-]($(C)!0.33!(O)$)--++(180:0.5) node[left]{$X(N40)$}; +\draw [<-]($(C)!0.67!(O)$)--++(180:0.5) node[left]{$Y(N40)$}; +\end{tikzpicture} + +\[ X_{N40} = \sum_{i=0}^{39}x_i \times 2^i \] +\[ CF = c_{40}, SF = z_{39}, ZF = \&_{i=0} \overline{z}_i \] +\[ c_0 = 0, c_i + x_i + y_i = z_i + 2 \cdot c_{i+1} \] +\[ b_0 = 0, -b_i + x_i - y_i = z_i - 2 \cdot b_{i+1} \] +\[ X_{N40} + Y_{N40} = \sum_{i=0}^{39} x_i \cdot 2^i + \sum_{i=0}^{39} y_i \cdot 2^i = c_{40} \cdot 2^{40} + \sum_{i=0}^{39} z_i \cdot 2^i | CF=0 \] +\[ X_{N40} - Y_{N40} = \sum_{i=0}^{39} x_i \cdot 2^i + \sum_{i=0}^{39} y_i \cdot 2^i + 1 | CF = 1 \] + +\begin{multicols}{3} + $z = x + y$ + + \begin{tabular}{|ccc|cc|} + \hline + $c_i$ & $x_i$ & $y_i$ & $z_i$ & $c_{i+1}$ \\ + \hline + 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 1 & 0 \\ + 0 & 1 & 0 & 1 & 0 \\ + 0 & 1 & 1 & 0 & 1 \\ + 1 & 0 & 0 & 1 & 0 \\ + 1 & 0 & 1 & 0 & 1 \\ + 1 & 1 & 0 & 0 & 1 \\ + 1 & 1 & 1 & 1 & 1 \\ + \hline + \end{tabular} + + \columnbreak + + $z = x - y$ + + \begin{tabular}{|ccc|cc|} + \hline + $b_i$ & $x_i$ & $y_i$ & $z_i$ & $b_{i+1}$ \\ + \hline + 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 1 & 1 \\ + 0 & 1 & 0 & 1 & 0 \\ + 0 & 1 & 1 & 0 & 0 \\ + 1 & 0 & 0 & 1 & 1 \\ + 1 & 0 & 1 & 0 & 1 \\ + 1 & 1 & 0 & 0 & 0 \\ + 1 & 1 & 1 & 1 & 1 \\ + \hline + \end{tabular} + + \columnbreak + + $z = x + \overline{y} + 1; c_i = \overline{b_i}$ + + \begin{tabular}{|ccc|cc|} + \hline + $\overline{b}_i$ & $x_i$ & $\overline{y}_i$ & $z_i$ & $\overline{b}_{i+1}$ \\ + \hline + 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 1 & 0 \\ + 0 & 1 & 0 & 1 & 0 \\ + 0 & 1 & 1 & 0 & 1 \\ + 1 & 0 & 0 & 1 & 0 \\ + 1 & 0 & 1 & 0 & 1 \\ + 1 & 1 & 0 & 0 & 1 \\ + 1 & 1 & 1 & 1 & 1 \\ + \hline + \end{tabular} + +\end{multicols} + +\textbf{Z40 [-549755813888, 549755813887]} для целых чисел есть флаг знака и знак переполнения (SF, OF). + +\begin{tikzpicture} +\draw (0,0)coordinate (O)--++(30:1)coordinate (A)--++(90:2)coordinate (B)--++(150:1)coordinate (C)--cycle; +\draw [->]($(A)!0.5!(B)$)--++(0:1)node[right]{$Z(N40)$}; +\draw [->]($(O)!0.5!(A)$)--++(-90:1)--++(0:2)node[right]{$OF$}; +\draw [->]($(O)!0.25!(A)$)--++(-90:1.5)--++(0:2.25)node[right]{$SF$}; +\draw [->]($(O)!0.75!(A)$)--++(-90:0.5)--++(0:1.75)node[right]{$ZF$}; +\draw [<-]($(B)!0.5!(C)$)--++(90:0.5)--++(180:1.75)node[left]{$C_0$}; +\draw [<-]($(C)!0.33!(O)$)--++(180:0.5) node[left]{$X(N40)$}; +\draw [<-]($(C)!0.67!(O)$)--++(180:0.5) node[left]{$Y(N40)$}; +\end{tikzpicture} + +Компилятор не может выполнять операции не в модулярной арифметике. Это позволяет генерировать исключения при переполнении разрядной сетки. +\begin{equation} + X_{Z40} = -s_x \cdot 2^{39} + \sum_{i=0}^{38} x_i \cdot 2^i + \label{eq:xz-40} +\end{equation} + +\[ Y_{Z40} = -s_y \cdot 2^{39} + \sum_{i=0}^{38} y_i \cdot 2^i \] + \begin{equation*} + \begin{gathered} + X_{Z40} + Y_{Z40} =\\ + = -s_x \cdot 2^{39} + \sum_{i=0}^{38} x_i \cdot 2^i - s_y \cdot 2^{39} + \sum_{i=0}^{38} y_i \cdot 2^i =\\ + = -(s_x + s_y + c_{39}) \cdot 2^{39} + \sum_{i=0}^{38} z_i \cdot 2^i =\\ + = -s_z \cdot 2^{39} + \sum_{i=0}^{38} z_i \cdot 2^i | OF = 0 + \end{gathered} + \end{equation*} + + \begin{tabular}{|ccc|cc|c|} + \hline + $s_x$ & $s_y$ & $c_{39}$ & $c_{40}$ & $s_z$ & OF \\ + \hline + 0 & 0 & 0 & 0 & 0 & 0 \\ + \cellcolor{red!25}{0} & \cellcolor{red!25}{0} & 1 & 0 & \cellcolor{red!25}{1} & 1 \\ + 0 & 1 & 0 & 0 & 1 & 0 \\ + 0 & 1 & 1 & 1 & 0 & 0 \\ + 1 & 0 & 0 & 0 & 1 & 0 \\ + 1 & 0 & 1 & 1 & 0 & 0 \\ + \cellcolor{red!25}{1} & \cellcolor{red!25}{1} & 0 & 1 & \cellcolor{red!25}{0} & 1 \\ + 1 & 1 & 1 & 1 & 1 & 0 \\ + \hline + \end{tabular} + + $OF = c_{40} \oplus c_{39}$ + +\subsection{АЛУ} +АЛУ обирает 40 одноразрядных сумматоров. + +\begin{multicols}{2} +\begin{tikzpicture}[circuit logic IEC] +\matrix[column sep=10mm] + { + \node (ci) {$c_i$}; & & \node [or gate] (a1) {}; & \\ + & \node [or gate](i0) {}; & & \\ + \node (xi) {$x_i$}; & & \node [and gate] (a2) {}; & \\ + & \node [and gate](i1) {}; & & \node [or gate] (o) {};\\ + \node (yi) {$y_i$}; & & & \\ + }; + + \draw (ci.east) -- ++(right:2mm) |- (a1.input 1); + \draw (xi.east) -- ++(right:4mm) |- (i0.input 1); + \draw (xi.east) -- ++(right:4mm) |- (i1.input 1); + \draw (yi.east) -- ++(right:6mm) |- (i0.input 2); + \draw (yi.east) -- ++(right:6mm) |- (i1.input 2); + + \draw (ci.east) -- ++(right:2mm) |- (a2.input 1); + \draw (i0.output) -- ++(right:7mm) |- (a1.input 2); + \draw (i0.output) -- ++(right:7mm) |- (a2.input 2); + + \draw (a2.output) -- ++(right:5mm) |- (o.input 1); + \draw (i1.output) -- ++(right:5mm) |- (o.input 2); + + \draw (a1.output) -- ++(right:23mm) node [right] {$Z_i$}; + \draw (o.output) -- ++(right:3mm) node [right] {$C_{i+1}$}; +\end{tikzpicture} + + \columnbreak + + \includegraphics[width=9cm]{01-alu1.png} +\end{multicols} + +Если на мультиплексоры подавать разные значения К то будут выполняться разные операции - сложение или вычитание. +\[CF = c_{40}, SF = z_{39}, OF = c_{40} \oplus c_{39}, ZF = \&_{i=0}^{39}\overline{z}_i \] +CF=carry, SF=sign, OF=overflow, ZF=zero. + +\begin{multicols}{2} + \begin{tabular}{|ccc|cc|} + \hline + $c_i$ & $x_i$ & $y_i$ & $z_i$ & $с_{i+1}$ \\ + \hline + 0 & 0 & 0 & 0 & 0 \\ + 0 & 0 & 1 & 1 & 0 \\ + 0 & 1 & 0 & 1 & 0 \\ + 0 & 1 & 1 & 0 & 1 \\ + 1 & 0 & 0 & 1 & 0 \\ + 1 & 0 & 1 & 0 & 1 \\ + 1 & 1 & 0 & 0 & 1 \\ + 1 & 1 & 1 & 1 & 1 \\ + \hline + \end{tabular} + + \columnbreak + + \begin{tabular}{|c|c|} + \hline + $K_x$ & A \\ + \hline + 0 & X \\ + 1 & $\overline{X}$ \\ + 2 & -1 \\ + 3 & 0 \\ + \hline + \end{tabular} +\end{multicols} + +\subsection{Проблемы двоичной арифметики} +Флаги результата операции: +\begin{itemize} +\item ZF – Zero (флаг нуля) – равенство всех разрядов результата нулю; +\item CF – Carry (флаг переноса) – наличие переноса за пределы разрядной сетки; +\item OF – Overflow (флаг переполнения) – не равенство переноса из знакового разряда результата переносу в знаковый разряд; +\item SF – Sign (флаг знака) – наличие единицы в знаковом разряде результата. +\end{itemize} + +\setlength\tabcolsep{2pt} +\begin{tabular}{ccccc} + \begin{arithmetic} + 0010~2~2 &\\ + + 0010~2~2 &\\ + 0100~4~4 &\\ + \end{arithmetic} +& + \begin{arithmetic} + 0110~~~6~6 &\\ + + 0010~~~2~2 &\\ + 1000~-8~8 &\\ + \end{arithmetic} +& + \begin{arithmetic} + 1110~-2~14 &\\ + + 1010~-6~10 &\\ + 1000~~-8~8 &\\ + \end{arithmetic} +& + \begin{arithmetic} + 0110~~~6~~6 &\\ + + 1110~-2~14 &\\ + 0100~~~4~~4 &\\ + \end{arithmetic} +& + \begin{arithmetic} + 1010~-6~10 &\\ + + 1100~-4~12 &\\ + 0110~~~6~~6 &\\ + \end{arithmetic} + \\ +CF=0, OF=0& +CF=0, OF=1& +CF=1, OF=0& +CF=1, OF=0& +CF=1, OF=1\\ +\end{tabular} +\setlength\tabcolsep{6pt} + +для контроля правильности вычислений нужно дописать встроенную функцию. если включается режим контроля переполнения в компиляторе - программа работает медленнее и/или занимает больше места. +\begin{lstlisting}[language=C,style=CCodeStyle] + static inline int CF() { + int c = 1; // *SP(1) + asm( + “BCC L1, CARRY + MOV #0, *SP(1) + L1: NOP“); + return c; + } +// +unsigned int x, y, z; +int t; +x = 0xFDE3, y = 0x71A4; +t = -x; if (CF() == 0) error(); +z = x + y; if (CF() == 1) error(); +z = x - y; if (CF() == 0) error(); + +int x, y, z; +x = 0xFDE3, y = 0x71A4; +z = -x; if(OF() == 0) error(); +z = x + y; if (ОF() == 1) error(); +z = x - y; if (ОF() == 0) error(); +\end{lstlisting} + +\textbf{Мнемоники для работы с числами в МК} + +\begin{tabular}{|c|c|c|} + \hline + Код J* & Название & Условие \\ + C & Carry (перенос) & $C = 1$ \\ + NC & No carry (не перенос) & $C = 0$ \\ + S & Sign (знак) & $S = 1$ \\ + NS & No sign (не знак) & $S = 0$ \\ + E, Z & Equal (равно), zero (нуль) & $Z = 1$ \\ + NE, NZ & No equal (не равно), no zero (не нуль) & $Z = 0$ \\ + O & Overflow (переполнение) & $V = 1$ \\ + NO & No overflow (не переполнение) & $V = 0$ \\ + \rowcolor{yellow} + L, NGE & Less (меньше), no great or equal (не больше или равно) & $S \^{} V = 1$ \\ + \rowcolor{yellow} + GE, NL & Great or equal (больше или равно), no less (не меньше) & $S \^{} V = 0$ \\ + \rowcolor{yellow} + LE, NG & Less or equal (меньше или равно) & $(S \^{} V) | Z = 1$ \\ + \rowcolor{yellow} + G, NL & Great (больше), no less (не меньше) & $(S \^{} V) | Z = 0$ \\ + \rowcolor{green} + B, NAE & Below (ниже), no above or equal (не выше или равно) & $C = 1$ \\ + \rowcolor{green} + AE, NB & Above or equal (выше или равно), no below (не ниже) & $C = 0$ \\ + \rowcolor{green} + BE, NA & Below or equal (ниже или равно), no above (не выше) & $C | Z = 1$ \\ + \rowcolor{green} + A, NBE & Above (выше), no below or equal (не ниже или равно) & $C | Z = 1$ \\ + \hline +\end{tabular} + +где \lh{yellow}{знаковый формат чисел}, и \lh{green}{формат чисел без знака}. + +\subsection{Преобразование целых чисел} +Если расширяем c 32-разрядного числа - расширяем знак, если сужаем до 32-разрядного - можем потерять данные, если знак в целевом (32м) разряде или старше - не совпал со знаковым разрядом источника (40). Представление 40-разрядного числа (\hrf{eq:xz-40}). +\[ X_{Z32} = -s_x \cdot 2^{31} + \sum_{i=0}^{30} x_i \cdot 2^i \] +В данном случае сумма - это геометрическая прогрессия +\[ \sum_{i=0}^{n-1} aq^i = a\frac{q^n - 1}{q - 1} \] +Поэтому, преобразование в меньшую разрядность можно представить следующим образом: +\[ 2^{39} - \sum_{i=31}^{38} = 2^{39} - 2^{31} \frac{2^8 - 1}{2 - 1} = 2^{31} \] +А преобразование в б\'{о}льшую разрядность так: +\begin{equation*} + \begin{gathered} + X_{Z32} = -s_x \cdot 2^{31} + \sum_{i=0}^{30} x_i \cdot 2^i =\\ + = -s\big(2^{39} - \sum_{i=31}^{38}2^i\big) + \sum_{i=0}^{30}x_i \cdot 2^i =\\ + = -s\cdot 2^{39} + \sum_{i=0}^{38}x_i\cdot 2^i + \Bigg|\substack{x_{38} = s\\x_{37} = s\\...\\x_{31} = s} + \end{gathered} +\end{equation*} + +\subsection{Умножение натуральных чисел} +Для умножения сумматор не годится. Результат умножения получается в два раза длиннее (по разрядности) исходных. Мы не можем представить умножение в общем виде, но можем посчитать максимальную разрядность результата. Такое вычисление можно представить в следующем виде: +\begin{equation*} + \begin{gathered} + X_{N16} = \sum_{i=0}^{15} x_i \cdot 2^i, Y_{N16} = \sum_{i=0}^{15} y_i \cdot 2^i, Z = X_{N16} \cdot Y_{N16}.\\ + Z = \Big(\sum_{i=0}^{15}x_i \cdot 2^i \Big) \Big(\sum_{i=0}^{15}y_i \cdot 2^i \Big)\\ + Z_{max} = \sum_{i=0}^{15}2^i \cdot \sum_{i=0}^{15}2^i = (2^{16} - 1)(2^{16}-1) = 2^{32} - 2^{17} + 1\\ + Z_{min} = 0\\ + Z_{N32} = \sum_{i=0}^{31}z_i \cdot 2^i + \end{gathered} +\end{equation*} + +В представлении операции на языке С можно записать следующим образом\footnotemark{}: +\begin{lstlisting}[language=C,style=CCodeStyle] + unsigned int x, y; + unsigned long z; + x = 0xFDE3, y = 0x71A4; + z = (long)x * y; +\end{lstlisting} + + +\subsection{Умножение целых чисел} +Для умножения знаковых нужно на один разряд меньше, чем в два раза больше от исходных, надо расширять знак на 32й разряд. +\begin{equation*} + \begin{gathered} + X_{Z16} = -s_x \cdot 2^{15} + \sum_{i=0}^{14} x_i \cdot 2^i, Y_{Z16} = -s_y \cdot 2^{15} + \sum_{i=0}^{14} y_i \cdot 2^i, Z = X_{N16} \cdot Y_{N16}.\\ + Z = \Big(-s_x \cdot 2^{15} + \sum_{i=0}^{14}x_i \cdot 2^i \Big) \Big(-s_x \cdot 2^{15} + \sum_{i=0}^{14}y_i \cdot 2^i \Big)\\ + Z_{max} = (-2^{15})(-2^{15}) = 2^{30}\\ + Z_{min} = -2^{15}\sum_{i=0}^{14} 2^i = -2^{15} \cdot (2^{15} - 1) = -2^{30} + 2^{15}\\ + Z_{Z32} = -s_z \cdot 2^{31} + \sum_{i=0}^{30}z_i \cdot 2^i, s_z = z_{30} \text{(расширение знака)} + \end{gathered} +\end{equation*} + +В представлении операции на языке С можно записать следующим образом\footnotemark[\value{footnote}]: +\begin{lstlisting}[language=C,style=CCodeStyle] + int x, y; + long z; + x = 0xFDE3, y = 0x71A4; + z = (long)x * y; +\end{lstlisting} +\footnotetext{прим. Овчинников - В языке С тип long имеет такую же разрядность, как int (в том числе согласно Википедии), поэтому такое преобразование не имеет смысла. Вероятнее всего оно применимо для конкретной весии компилятора (для данного в курсе МК) но точно не в «общем случае»} +\subsection{Аппаратный умножитель} +(L03-14) Аппаратный умножитель работает как умножение в столбик +\[S_i = c_{i-1} \oplus a_i \oplus b_i\] + +\textbf{из книги Харрис и Харрис} \cite[стр. 252-253]{digital-design} \textit{(изображения на слайде L03-14 приведены оттуда)} +Multiplication of unsigned binary numbers is similar to decimal multiplication but involves only 1’s and 0’s. Figure \hrf{pic:h-h-mult} compares multiplication in decimal and binary. In both cases, partial products are formed by multiplying a single digit of the multiplier with the entire multiplicand. The shifted partial products are summed to form the result. +\begin{figure}[h] + \centering + \begin{subfigure}[b]{0.4\textwidth} + \centering + \begin{equation*} + \begin{arithmetic} + 230 & multiplicand\\ + \times 42 & multiplier\\ + 460 & partial\\ + + 920~ & products\\ + 9660 & result + \end{arithmetic} + \end{equation*} + \caption{decimal $230 \times 42 = 9660$} + \label{pic:h-h-m-d} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.4\textwidth} + \centering + \begin{equation*} + \begin{arithmetic} + 0101 & multiplicand\\ + \times 0111 & multiplier\\ + 0101 & partial\\ + 0101 & products\\ + 0101~ &\\ + 0101~~ &\\ + + 0000~~~ &\\ + 0100011 & result + \end{arithmetic} + \end{equation*} + \caption{binary $5 \times 7 = 35$} + \label{pic:h-h-m-b} + \end{subfigure} + \caption{Multiplication} + \label{pic:h-h-mult} +\end{figure} + +In general, an N×N multiplier multiplies two N-bit numbers and produces a 2N-bit result. The partial products in binary multiplication are either the multiplicand or all 0’s. Multiplication of 1-bit binary numbers is equivalent to the AND operation, so AND gates are used to form the partial products. +Figure \hrf{pic:h-h-44-mult} shows the symbol, function, and implementation of a $4 \times 4$ multiplier. The multiplier receives the multiplicand and multiplier, A and B, and produces the product P. Figure \hrf{pic:h-h-44-func} shows how partial products are formed. Each partial product is a single multiplier bit ($B_3, B_2, B_1, or B_0$) \code{AND} the multiplicand bits ($A_3, A_2, A_1, A_0$). With N-bit operands, there are N partial products and N − 1 stages of 1-bit adders. For example, for a $4 \times 4$ multiplier, the partial product of the first row is $B_0$ \textbf{AND} ($A_3, A_2, A_1, A_0$). This partial product is added to the shifted second partial product, $B_1$ \code{AND} ($A_3, A_2, A_1, A_0$). Subsequent rows of \code{AND} gates and adders form and add the remaining partial products. + +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.1\textwidth} + \centering + \begin{tikzpicture}[ + x=0.75pt, y=0.75pt, + yscale=-2, xscale=2 + ] + \draw (0,10) rectangle (30,40); + \node[] at (15,25) {X}; + \draw (10,0) -- (10,10) node [] at (10,-5) {\tiny{A}}; + \draw (20,0) -- (20,10) node [] at (20,-5) {\tiny{B}}; + \draw (8,3) -- (12,7) node[above left]{\tiny{4}}; + \draw (18,3) -- (22,7) node[above right]{\tiny{4}}; + \draw (13,43) -- (17,47) node[right]{\tiny{8}}; + \draw (15,40) -- (15,50) node [] at (15,55) {\tiny{P}}; + \end{tikzpicture} + \caption{symbol} + \label{pic:h-h-44-symb} + \end{subfigure} + \begin{subfigure}[b]{0.4\textwidth} + \centering + \begin{equation*} + \begin{arithmetic} + A_3 ~A_2 ~A_1 ~A_0 &\\ + \times B_3 ~B_2 ~B_1 ~B_0 &\\ + A_3B_0A_2B_0A_1B_0A_0B_0 &\\ + A_3B_1A_2B_1A_1B_1A_0B_1~~ &\\ + A_3B_2A_2B_2A_1B_2A_0B_2~~~~ &\\ + + A_3B_3A_2B_3A_1B_3A_0B_3~~~~~~ &\\ + P_7~~P_6~P_5~P_4~P_3~P_2~P_1~P_0~& + \end{arithmetic} + \end{equation*} + \caption{function} + \label{pic:h-h-44-func} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.45\textwidth} + \centering + \includegraphics[width=\textwidth]{01-mult1.png} + \caption{implementation} + \label{pic:h-h-44-impl} + \end{subfigure} + \caption{4x4 multiplier} + \label{pic:h-h-44-mult} +\end{figure} + +\section{Представление дробных чисел} +\subsection{Дробные форматы} +\textbf{Q4.12 [-8, 8)}, $\varepsilon = 2^{-12} = 2,44 \times 10^{-4}$ целые числа, старшие разряд - по формуле, под разряды целых чисел отведено 4 разряда, причём самый старший - знак. +\begin{figure}[H] + \setlength\tabcolsep{1.5pt} + \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|} + $2^{3}$ & $2^{2}$ & $2^{1}$ & $2^{-0}$ & $2^{-1}$ & $2^{-2}$ & $2^{-3}$ & $2^{-4}$ & $2^{-5}$ & $2^{-6}$ & $2^{-7}$ & $2^{-8}$ & $2^{-9}$ & $2^{-10}$ & $2^{-11}$ & $2^{-12}$ \\ [0.5ex] + $15$ & $14$ & $13$ & $12$ & $11$ & $10$ & $9$ & $8$ & $7$ & $6$ & $5$ & $4$ & $3$ & $2$ & $1$ & $0$ \\ [0.5ex] + \hline + S & X & X & X & X & X & X & X & X & X & X & X & X & X & X & X \\ + \hline + \end{tabular} +\end{figure} +\[X_{Q4.12} = -s \cdot 2^3 + \sum_{i=0}^{14} x_i \cdot 2^{(-12+i)} = 2^{-12}\big(-s \cdot 2^{15} + \sum_{i=0}^{14} x_i \cdot 2^i \big) = 2^{-12} \cdot X_{Z16}\] + +\textbf{Q1.15 [-1, 1)}, $\varepsilon = 2^{-15} = 3,05 \times 10^{-5}$ (используется чаще всего). Целая часть числа фактически состоит только из знака. +\begin{figure}[H] + \setlength\tabcolsep{1.5pt} + \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|} + $2^{0}$ & $2^{-1}$ & $2^{-2}$ & $2^{-3}$ & $2^{-4}$ & $2^{-5}$ & $2^{-6}$ & $2^{-7}$ & $2^{-8}$ & $2^{-9}$ & $2^{-10}$ & $2^{-11}$ & $2^{-12}$ & $2^{-13}$ & $2^{-14}$ & $2^{-15}$ \\ [0.5ex] + $15$ & $14$ & $13$ & $12$ & $11$ & $10$ & $9$ & $8$ & $7$ & $6$ & $5$ & $4$ & $3$ & $2$ & $1$ & $0$ \\ [0.5ex] + \hline + S & X & X & X & X & X & X & X & X & X & X & X & X & X & X & X \\ + \hline + \end{tabular} +\end{figure} +\[X_{Q1.15} = -s + \sum_{i=0}^{14} x_i \cdot 2^{(-15+i)} = 2^{-15}\big(-s \cdot 2^{15} + \sum_{i=0}^{14} x_i \cdot 2^i \big) = 2^{-16} \cdot X_{Z16}\] + +\textbf{Q1.31 [-1, 1)}, $\varepsilon = 2^{-31} = 4,66 \times 10^{-10}$ аналогично, но увеличена точность +\[X_{Q1.31} = -s + \sum_{i=0}^{30} x_i \cdot 2^{(-31+i)} = 2^{31}\big(-s \cdot 2^{31} + \sum_{i=0}^{30} x_i \cdot 2^i \big) = 2^{-31} \cdot X_{Z32}\] + +\textbf{Проблема работы с фиксированной запятой} состоит в том, что при умножении надо выполнять коррекцию результата, поскольку в результате умножения мы получили на 4 разряда больше, чем должен быть результат (разрядность результата умножения всегда в два раза больше разрядности исходных множителей) +\[0000,0001_2 = \frac{1}{16} = 0,625\] +\[0001,1000_2 = \frac{24}{16} = 1,5\] +\[\frac{a}{c} + \frac{b}{c} = \frac{a + b}{c}\] +\[\frac{a}{c} * \frac{b}{c} = \frac{{a * b} / c}{c}\] +\[1,5 * 2,5 = 3,75\] +\[0001,1000_2 * 0010,1000_2 = 0011,1100 | 0000_2\] + +\subsection{Внутренний формат Q9.31} +\textbf{Q9.31 [-256, 256)}, $\varepsilon = 2^{-31} = 4,66 \times 10^{-10}$. АЛУ работает только с беззнаковыми числами, далее весь результат умножается на $2^{-31}$ чтобы получить знак. В двоичном представлении старший разряд ($-2^8$) является знаковым, далее с 38го по 31й представлена целочисленная часть, а с 30го по 0й разряды дробная (с точностью от $2^{-1}$ до $2^{-31}$). АЛУ на вход принимает числа и перенос, возвращает результат и флаги CF, OF, SF, ZF (переноса, переполнения, знака, нуля). Поскольку представление дробных чисел с фиксированной запятой совпадает с представлением целых чисел, то вычисления с фиксированной запятой можно представить в следующем виде: +\[X_{N40} = \sum_{i=0}^{39} x_i \cdot 2^i\] +\[X_{Z40} = -s \cdot 2^{39} + \sum_{i=0}^{38} x_i \cdot 2^i \] +\[X_{Q9.31} = -s \cdot 2^{8} + 2^{-31} \sum_{i=0}^{38} x_i \cdot 2^i \] +\[X_{Q9.31} = 2^{-31}\big( -s \cdot 2^{39} + \sum_{i=0}^{38} x_i \cdot 2^i \big) = 2^{-31} \cdot X_{Z40}\] +\[X_{Q9.31} \pm Y_{Q9.31} = 2^{-31} (X_{Z40} \pm Y_{Z40})\] + +\textbf{Преобразование дробных} происходит аналогично целым числам при уменьшении разрядности - проверить старшие 9 разрядов на соответствие значению исходного, при увеличении разрядности - расширяем знак. +\[ X_{Q9.31} = -s \cdot 2^{8} + -2^{-31} \sum_{i=0}^{38} x_i \cdot 2^i \] +\[ X_{Q1.31} = -s + 2^{-31} \sum_{i=0}^{30} x_i \cdot 2^i \] +В данном случае сумма - это геометрическая прогрессия +\[ \sum_{i=0}^{n-1} aq^i = a\frac{q^n - 1}{q - 1} \] +Поэтому, преобразование в меньшую разрядность можно представить следующим образом: +\[ 2^{8} - \sum_{i=0}^{7} 2^i = 2^{8} - \frac{2^8 - 1}{2 - 1} = 2^{0} \] +А преобразование в б\'{о}льшую разрядность так: +\begin{equation*} + \begin{gathered} + X_{Q1.31} = -s \cdot 2^{0} + 2^{-31} \sum_{i=0}^{30} x_i \cdot 2^i =\\ + = -s\big(2^{8} - \sum_{i=0}^{7}2^i\big) + 2^{-31} \sum_{i=0}^{30}x_i \cdot 2^i =\\ + = -s \cdot 2^{8} + 2^{-31} \sum_{i=0}^{38} x_i \cdot 2^i + \Bigg|\substack{x_{38} = s\\x_{37} = s\\...\\x_{31} = s} + \end{gathered} +\end{equation*} + +\subsection{Насыщение (Saturation)} +Когда происходят операции с плавающей запятой существуют случаи неопределённости, например, деление на ноль - это $\pm$ бесконечность, а $\frac{0}{0}$ неопределено. При операциях с фиксированной запятой такого быть не может, но если результат непредставим - мы преобразуем его на максимально возможное представимое число (при отрицательном результате заменяем на самое маленькое число, при положительном - на самое большое доступное). +\begin{table}[H] + \centering + \begin{tabular}{lclcl} + Q9.31 & & Q1.31 & & \\ [0.5ex] + 0xFE80\_0000\_09 & $\neq$ & 0x80\_0000\_09 & & \\ + 0x0180\_0000\_09 & $\neq$ & 0x80\_0000\_09 & & \\ + Q9.31 & & Q9.31 & & Q1.31 \\ [0.5ex] + 0xFE80\_0000\_09 & $\approx$ & 0xFF80\_0000\_09 & = & 0x80\_0000\_00\\ + 0x0180\_0000\_09 & $\approx$ & 0x007F\_FFFF\_FF & = & 0x7F\_FFFF\_FF\\ + \end{tabular} +\end{table} + +\textbf{0xFF80000000} – минимальное число в Q1.31 + +\textbf{0x007FFFFFFF} – максимальное число в Q1.31 + +\subsection{Умножение дробных} +Для приведения результата умножения Z32 в Q1.31 нужно умножить результат на два (сдвинуть на разряд влево). В целочисленной арифметике нельзя умножить два 16-разрядных числа и получить 16-разрядное (в результате умножения всегда получается большее по разрядности число). В числах с фиксированной точкой это реально, но Z32 нужно сдвинуть на 15 разрядов вправо (то есть проигнорировать младшие полученные разряды). +\begin{equation*} + \begin{gathered} +X_{Q1.15} = -s_x + 2^{-15} \sum_{i=0}^{14} x_i \cdot 2^i, Y_{Q1.15} = -s_y + 2^{-15} \sum_{i=0}^{14} y_i \cdot 2^i \\ +Z = 2^{-30} \big( -s_x + 2^{15} \sum_{i=0}^{14} x_i \cdot 2^i\big) \big( -s_y + 2^{15} \sum_{i=0}^{14} y_i \cdot 2^i \big) \\ +Z = 2^{-30}(X_{Z16} \cdot Y_{Z16}) = 2^{-30} Z_{Z32}, Z_{Q1.31} = 2 \cdot Z \\ +Z_{Q1.31} = -s_Z + 2^{-31} \sum_{i=0}^{30} z_i \cdot 2^i \\ +Z_{Q1.31} = Z_{Z32} < < 1 \\ +Z_{Q1.15} = Z_{Z32} > > 15 + \end{gathered} +\end{equation*} + +\begin{lstlisting}[language=C,style=CCodeStyle] + int x, y; + long z; + x = 0xFDE3, y = 0x71A4; + z = ((long) x * y) << 1; + + int x, y, z; + x = 0xFDE3, y = 0x71A4; + z = ((long) x * y) >> 15; +\end{lstlisting} + +\subsection{Деление дробных} +Команды деления фактически нет. Но, делить числа иногда нужно, поэтому создаётся функция, которая реализует не сложения/сдвиги, а вычисляет корень функции методом касательной Ньютона: находим первое приближение, находим второе приближение производной первого приближения, рисуем касательную, значение получаем на оси Х. Повторяем фиксированное число раз. +\[f(x) = \frac{1}{x} - c, f(x) = 0 \to x = \frac{1}{c}\] +\[f(x) = 0, x_{m+1} = x_m - \frac{f(x_m)}{f'(x_m)} \] +\begin{figure}[H] + \begin{tikzpicture}[thick,yscale=0.8] + \draw[-latex,name path=xaxis] (-1,0) -- (12,0) node[above]{\large $x$}; + \draw[-latex] (0,-2) -- (0,8)node[right]{\large $y$};; + + \draw[ultra thick, orange,name path=function] plot[smooth,domain=1:9.5] (\x, {0.1*\x^2-1.5}) node[left]{$F(x)$}; + + \draw[dashed] (8,0) -- (8,4.9) node[circle,fill,inner sep=2pt]{}; + \draw[dashed, violet, name path=Tfunction] plot[smooth,domain=4.25:9.5] (\x, {1.6*\x-7.9}); + + \draw (8,0.1) -- (8,-0.1) node[below] {$x^{(m)}$}; + \draw [name intersections={of=Tfunction and xaxis}] ($(intersection-1)+(0,0.1)$) -- ++(0,-0.2) node[below,fill=white] {$x^{(m+1)}$} ; + \end{tikzpicture} +\end{figure} + +Получаем рекуррентное уравнение +\[x_{m+1} = 2x_m - x_m^2 c (|x_{m+1} - x_m | < \varepsilon) \] +Если представить С как мантиссу на 2-в-степени-порядка, известно, что мантисса будет от 1/2 до 1. +\[c = M \cdot 2^E, |M| \in [\frac{1}{2}, 1) \] +Запоминаем порядок и выполняем операцию с мантиссой. Чтобы получить требуемую погрешность нужно всего три итерации. Для того чтобы вычисление было быстрее - мы задаём правильное приближение. +\begin{equation*} + \begin{gathered} + M = 01XX...Xb, E=0YYY...Yb\\ + x_{m+1} = 2x_m - x_m^2 M (m = 0, 1, 2, 3)\\ + x_0 = (M < < 1)^{0x1FFF}\\ + E_0 = E - 1 + \end{gathered} +\end{equation*} + +\begin{lstlisting}[language=C,style=CCodeStyle] +void ldiv16(LDATA *x, DATA *y, DATA *z, DATA *zexp, ushort nx); +\end{lstlisting} + +\subsection{Формат с плавающей запятой} +Работает по стандарту IEEE 754 (1985) \footnote{https://habr.com/ru/post/112953/} +Формат подразумевает три поля (знак, 8(11) разрядов поля для смещённого порядка, 23(52) бита мантисса). Так как число может быть нормализовано поэтому старшая единица не хранится, но подразумевается. +\begin{table}[ht] + \centering + \begin{tabular}{|l|l|l|c|} + \hline + S & E & M & \\ + 1 & 8 & 23 & $F_{32} (-1)^S 2^{(E-127)} (1+M/2^{23})$ \\ + 1 & 11 & 52 & $F_{64} (-1)^S 2^{(E-1023)} (1+M/2^{52})$ \\ + \hline + \end{tabular} +\end{table} + +\begin{itemize} +\item [S] – Sign (знак числа) +\item [E] – Exponent (8 или 11 бит смещенного на 127 или 1023 порядка числа) +\item [M] – Mantissa (23 или 52 бита мантиссы, дробная часть числа) +\end{itemize} +Например: \code{0100 0011 0001 1011 1010 0000 0000 0000b 431BA000h} +\begin{table}[ht] + \centering + \begin{tabular}{|l|l|l|} + \hline + S & E & M\\ + 0 & 10000110 & 00110111010000000000000b\\ + 0 & 134 & 1810432\\ + (-1)0 & $\cdot 2^{(134-127)}$ & $\cdot(1+1810432/2^{23})$ = 155,625\\ + \hline + \end{tabular} +\end{table} + +\includegraphics[width=150mm]{04-fpointvals.png} + +Нули бывают как положительные, так и отрицательные, это касается только дробных, в целочисленных только +0 бывает. Зелёная зона - непредставимые числа (слишком большие для хранения внутри такой переменной) или настолько маленькие, что мнимая единица в мантиссе отсутствует. Бесконечность одна положительная, одна отрицательная, дальше идёт очень много не-чисел (если знать как, можно использовать нечисла для хранения собственных данных) + +\textbf{Денормализованные числа} +5-разрядный формат с плавающей запятой. +\begin{table}[ht] + \centering + \begin{tabular}{|l|l|l|c|} + \hline + S & E & M & \\ + 1 & 2 & 2 & $E: -1, 0, 1, 2 (-1 \leq E \leq 2) $ \\ + & & & $M: 1.00, 1.01, 1.10, 1.11 (1.00 \leq M \leq 1.11)$ \\ + \hline + \end{tabular} +\end{table} +\begin{table}[ht] + \centering + \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|} + \hline + 0 & & 1 & & 2 & & 3 & & 4 & 5+ \\ + \hline + \ver{00000} & 00001 & \ver{00100} & 00101 & \ver{01000} & \ver{01001} & \ver{01010} & \ver{01010} & \ver{01100} & E = 2\\ + & 00010 & & 00110 & & & & & & $M \neq 0$\\ + & 00011 & & 00111 & & & & & &до 01111\\ + \hline + \multicolumn{2}{|l|} {Денормализованные} & \multicolumn{6}{l|}{Нормализованные} & $+\infty$ & Не числа \\ + \hline + \end{tabular} +\end{table} + +Проблемы чисел с плавающей запятой (вероятнее всего имеются ввиду указанные выше 5-разрядные переменные, и/или конкретный сигнальный процессор с его странными ограничениями, поскольку никакого подобного округления в нормальном программировании происходить не будет, \textit{прим. Овчинников}) +\[ (0.5 + 1.0) + 3.5 = 5.0; 0.5 + (1.0 + 3.5) = 4 \] +На слайде показана числовая прямая, на которой после каждого действия во втором примере по какой-то причине происходит округление дробной части до целого. А в первом равенстве этого не происходит. + +\textbf{Методы округления чисел с плавающей запятой} +\begin{itemize} +\item Round to nearest, ties to even - округление в сторону ближайшего, к чётному в случае конфликтов (режим по умолчанию в IEEE 754) + \[ 01.101_2 \to 01.1_2, 01.110_2 \to 10.0_2, 01.111_2 \to 10.0_2, -01.101_2 \to -01.1_2 \] +\item Rount up - округление в сторону $+\infty$ + \[ 01.101_2 \to 10.0_2, 01.110_2 \to 10.0_2, 01.111_2 \to 10.0_2, -01.101_2 \to -01.1_2 \] +\item Rount down - округление в сторону $-\infty$ + \[ 01.101_2 \to 01.1_2, 01.110_2 \to 01.1_2, 01.111_2 \to 01.1_2, -01.101_2 \to -10.0_2 \] +\item Rount towards zero - округление в сторону 0 + \[ 01.101_2 \to 01.1_2, 01.110_2 \to 01.1_2, 01.111_2 \to 01.1_2, -01.101_2 \to -01.1_2 \] +\end{itemize} + +\textbf{Арифметические проблемы} +\begin{itemize} +\item Не все числа имеют представление. +\item Преобразование в целые: $63,0/9,0 \to 7$, $0,63/0,09 \to 6$. +\item Преобразование в символьные форматы и обратно, многие числа нельзя ввести или вывести точно: $0,2 \to 0,200000000003$. +\item Порядок вычисления может влиять на результат и его точность: не выполняются законы ассоциативности и дистрибутивности. +\item Проблемы сравнения: $x == y$. +\end{itemize} + +\textbf{Рекомендации} +\begin{itemize} +\item Выполнять вычисления в одном формате чисел. +\item Избегать лишних преобразований форматов. +\item При сравнении чисел F32, F64 использовать $abs(x − y) \leq \varepsilon$. +\item Избегать сложений чисел, экспоненты которых сильно отличаются. +\item Избегать вычитания близких чисел. +\item Функции exp, log, sin и т.д. не вычисляются точно. +\end{itemize} + +\section{Сигнальные микропроцессоры} +Сигнальные микропроцессоры занимаются обработкой только массивов данных фиксированной длины. В отличие от процессоров общего нащначения. Архитектура микропроцессоров общего назначения почти не изменилась со времён х386, суперскалярная архитектура. +\begin{figure}[ht] + \centering + \includegraphics[width=15cm]{05-intel.png} +\end{figure} + +У таких процессоров есть особенная надстройка - NUMA (non uniform memory access) - нерегулярный доступ ко внешней памяти. помогает сохранить консистентность кэшей. Архитектура является довольно сложной как в реализации, так и в программировании. + +Основное преимущество сигнальных процессоров для своих функций в том, что они специализируются на решении единственной задачи - вычисление суммы произведений двух векторов. То есть СП специально спроектирован именно для сигнальной обработки данных. По сути все виды обработки сигналов - это умножение и сложение. Для использования этих операций есть АЛУ для сложения, АЛУ для умножения и аккумулятор. Так как исходные тоже должны сохраняться в память - есть несколько магистралей (векторов) для чтения данных. Все магистрали подключены к шине памяти, то есть все операции фактически находятся во внутренней памяти. одновходовая и двухвходовая шина подключается ко внутренней памяти процессора. Это позволяет выполнять фильтрацию двух сигналов с одинаковыми коэффициентами. Это позволяет вычислять такое множество операций за один такт. и сохранять/читать команды/данные из внешней памяти. + +Российскими производителями представлены: +\begin{itemize} +\item 1967ВН044 – 32-разр. ЦОС, 230 МГц, КМОП 0,18 мкм (Миландр) +\item 1890ВМ7Я – 32-разр. ЦОС, 200 МГц, КМОП 0,18 мкм (НИИСИ РАН) +\item 1901ВЦ1Т – 2 ядра: 16-разр. ЦОС и 32-разр. RISC ARM, 100 МГц, КМОП 0,18 мкм (Миландр) +\item 1892ВМ7Я – 5 ядер: 4 ядра 32-разр. ЦОС, 32- разр. RISC MIPS, 200 МГц, КМОП 0,13 мкм (НПЦ ЭЛВИС) +\item 1879ВМ8Я – 5 ядер: 4 ядра 64-разр. ЦОС, 32- разр. RISC ARM, 1000 МГц, КМОП 0,28 мкм (НТЦ Модуль) +\end{itemize} + +\nomenclature[A]{SRAM}{Static Random Access Memory (статическая память)} +\nomenclature[A]{DMA}{Direct Memory Access (прямой доступ к памяти)} +\nomenclature[A]{BKP}{Backup (архивирование)} +\nomenclature[A]{OSC}{Oscillator (генератор)} +\nomenclature[A]{IWDG}{Independent Watch Dog (сторожевой таймер)} +\nomenclature[A]{WWDG}{Windowed Watch Dog (оконный сторожевой таймер)} +\nomenclature[A]{AHB}{Advanced High-performance Bus (внутренняя шина)} +\nomenclature[A]{McBSP}{Multichannel Buffered Serial Port (последовательный порт)} +\nomenclature[A]{MIPS}{Microprocessor without Interlocked Pipeline Stages} + +\includegraphics[width=15cm]{05-1967vn044.png} + +Важной особенностью является, что у этого (1967ВН044) микропроцессора есть аппаратный конвейер, позволяющий выполнять части команд параллельно. У сигнальных микропроцессоров всегда есть довольно большая внутренняя память с четырьмя каналами доступа, чтобы данные очень быстро передавать на обработку. + +В курсе будет идти работа с микропроцессором TMS320C5515 +\begin{itemize} +\item Тактовая частота 60 (75, 100, 120) МГц +\item Напряжение питания ядра 1,05 и 1,30 В +\item Мощность потребления 18,0-26,4 мВт +\item Быстродействие 240 миллионов команд +\item Конвейер 12 стадий, 2 команды параллельно +\item Данные с фиксированной запятой 16, 32, 40 бит +\item Встроенная основная память 320 КБ +\item Встроенная постоянная память 128 КБ +\item Внешняя память до 16 МБ +\item Периферийные устройства DMA, I2C, SPI, I2S, UART, USB, MMC/SD, GPIO, SAR, LCD +\end{itemize} + +На процессорах общего назначения это невозможно, поскольку быстродействие при такой частоте невозможно. но у сигнального микропроцессора есть 12-стадийный конвейер, что позволяет выполнять одну команду за пол-такта. Мощность потребления исчезающе мала, поэтому удобно использовать от аккумулятора. Включает в себя множество периферийных интерфейсов, сравнимых с обычным микропроцессором общего назначения. + +Внутри ядра ЦОС имеется специально встроенный вычислитель быстрого преобразования фурье. 16 каналов прямого доступа к памяти. Поскольку есть dual access и single access RAM - появляется три канала получения данных. ко внутренним шинам мультиплексируются внешние подключаемые периферийные устройства. + +\nomenclature[P]{CPU}{Central Processing Unit (центральное процессорное устройство, центральный процессор)} +\nomenclature[P]{Core}{ядро, центральная часть} +\nomenclature[P]{Bus}{шина, магистраль} +\nomenclature[P]{MMR}{Memory Mapped Register (регистр отображенный в память)} +\nomenclature[P]{INT}{Interrupt (прерывания)} +\nomenclature[P]{LDO}{Low-Drop Out (линейный регулятор с низким падением напряжения)} +\nomenclature[P]{JTAG}{Joint Test Action Group (специализированный аппаратный интерфейс для тестирования и отладки сложных дискретных устройств)} +\nomenclature[P]{FFT}{Fast Fourier Transform (быстрое преобразование Фурье)} + +\nomenclature[M]{RAM}{Random Access Memory (память со случайным доступом, ОЗУ – оперативное запоминающее устройство, основная память)} +\nomenclature[M]{mSDRAM}{Mobile Synchronous Dynamic RAM (мобильная синхронная динамическая память со случайным доступом)} +\nomenclature[M]{DARAM}{Dual Access RAM (двухвходовая основная память)} +\nomenclature[M]{SARAM}{Single Access RAM (одновходовая основная память)} +\nomenclature[M]{ROM}{Read Only Memory (память только для чтения, ПЗУ – постоянное запоминающее устройство)} +\nomenclature[M]{EEPROM}{Electrically Erasable Programmable ROM (электрически стираемое перепрограммируемое ПЗУ, флэш-память)} +\nomenclature[M]{EHPI}{Enhanced Host-Port Interface (интерфейс с другим процессором)} + +\nomenclature[I]{LCD}{Liquid crystal display (жидкокристаллический дисплей)} +\nomenclature[I]{MMC/SD}{Multi Media Card/Secure Digital (мультимедийная карта / безопасная цифровая карта)} +\nomenclature[I]{SAR}{Successive Approximation Register (регистр последовательного приближения)} + +\begin{figure}[h] + \centering + \includegraphics[width=15cm]{05-core.png} + \caption{Ядро микропроцессора} + \label{pic:dsp-core} +\end{figure} + +Функциональная диаграмма ядра микропроцессора на рисунке \hrf{pic:dsp-core} показана без модуля быстрого преобразования Фурье. У процессора нет байтовых данных. Все данные в словах, однако, код программы принимается и обрабатывается в байтах. Сам процессор внутри состоит из 4х модулей: +\begin{itemize} +\item операционное устройство Д-модуль, не занимается адресацией +\item адресацией занимается только специальное устройство А-модуль +\item адрес для команд формируется специальным Р-модулем +\item чтение не происходит явно, все команды сразу пишутся в I-модуль. +\end{itemize} +Это разные устройства, они разделены физически, у них есть регистровые файлы, но у них есть взаимосвязи. Основное общение устройств происходит через шины адреса и данных, иногда одни устройства могут задействовать простаивающие ресурсы других (например, может быть задействован умножитель из операционного устройства для вычисления адреса) + +\begin{wrapfigure}{l}{0.4\textwidth} + \includegraphics[width=0.35\textwidth]{05-triread.png} +\end{wrapfigure} + +Как именно происходит тройное чтение и двойная запись: данные поступают на два независимых АЛУ и сохраняют данные по независимым шинам (2 команды, 2 параллельных процесса обработки данных), управление АЛУ происходит независимо по шине команд, в случае необходимости одно из АЛУ пишет в SARAM. Фактически, команда, подаваемая на АЛУ определяет, куда будут переданы результаты вычислений АЛУ + +\subsection{Адресные пространства} +\begin{table}[ht] + \renewcommand{\arraystretch}{0.5} + \centering + \begin{tabular}{R|C|L} + \cline{2-2} 000000h & Внутренняя MMR & 192б \\ + \cline{2-2} 0000C0h & Внутренняя DARAM & 64Кб - 192б \\ + \cline{2-2} 010000h & Внутренняя SARAM & 256Кб \\ + \cline{2-2} 050000h & Внешняя синхронная CS0-1 & 8Мб - 320Кб \\ + \cline{2-2} 800000h & Внешняя асинхронная CS2 & 4Мб \\ + \cline{2-2} C00000h & Внешняя асинхронная CS3 & 2Мб \\ + \cline{2-2} E00000h & Внешняя асинхронная CS4 & 1Мб \\ + \cline{2-2} F00000h & Внешняя асинхронная CS5 & 1Мб - 128Кб \\ + \cline{2-2} FE0000h & ROM (MPNMC=0)+ Резерв(MPNMC=1) & 128Кб \\ + \cline{2-2} \multicolumn{3}{L}{FFFFFFh} \\ + \end{tabular} +\end{table} + +В микропроцессорах, предназначенных для цифровой обработки сигналов, есть два адресных пространства. Плавающих адресов нет, потому что состав устройств постоянный. + +\begin{table}[ht] + \renewcommand{\arraystretch}{0.5} + \centering + \begin{tabular}{R|C|} + \cline{2-2} 0000h & Управление простоем (Idle Control)\\ + \cline{2-2} 0C00h & Канал прямого доступа DMA0\\ + \cline{2-2} 0D00h & Канал прямого доступа DMA1\\ + \cline{2-2} 0E00h & Канал прямого доступа DMA2\\ + \cline{2-2} 0F00h & Канал прямого доступа DMA3\\ + \cline{2-2} 1000h & Интерфейс внешней памяти EMIF\\ + \cline{2-2} 1800h & Таймер Timer0\\ + \cline{2-2} 1840h & Таймер Timer1\\ + \cline{2-2} 1880h & Таймер Timer2\\ + \cline{2-2} 1900h & Часы реального времени RTC\\ + \cline{2-2} 1A00h & Контроллер I2C\\ + \cline{2-2} 1B00h & Контроллер UART\\ + \cline{2-2} 1C00h & Управление микропроцессором\\ + \cline{2-2} 2800h & Контроллер I2S0\\ + \cline{2-2} 2900h & Контроллер I2S1\\ + \cline{2-2} 2A00h & Контроллер I2S2\\ + \cline{2-2} 2B00h & Контроллер I2S3\\ + \cline{2-2} 2E00h & Контроллер LCD\\ + \cline{2-2} 3000h & Контроллер SPI\\ + \cline{2-2} 3A00h & Контроллер MMC/SD0\\ + \cline{2-2} 3B00h & Контроллер MMC/SD1\\ + \cline{2-2} 7000h & Аналогово-цифровой преобразователь SAR\\ + \cline{2-2} 8000h & Контроллер USB\\ + \cline{2-2} \multicolumn{2}{L}{FFFFh} \\ + \end{tabular} +\end{table} + +\textbf{(слайды с 20 по 26 на лекции не объяснялись)} + +\subsection{Операционное устройство} +\subsubsection{Физическое устройство} +Как видно на рисунке \hrf{pic:dsp-core}, от магистрали BB, CB, DB есть три входа в операционное устройство. Модуль работает с операндами, находящимися в памяти (стрелки к A-модулю и P-модулю). Прямо в коде могут быть команды, полученные из буфера команд. То есть можем обрабатывать данные, находящиеся в любом регистре любого модуля. Ответы уходят к EB и FB. + +\begin{figure}[ht] + \centering + \includegraphics[width=10cm]{06-oper-phys.png} + \caption{Операциооное устройство} + \label{pic:dsp-dunit} +\end{figure} + +Операционное устройство - это чать ядра микропроцессора. Видно, что операционное устройство не обрабатывает адреса, адреса получаем из устройства адресации, операционное устройство они не касаются. Все данные содержатся в регистровом файле. Арифметико-логический блок выполняет арифметико-логические операции. Также есть двойной умножитель-аккумулятор. Часто нужно выполнять операцию сдвига, поэтому есть сдвигатель. Важный блок - блок битовых операций. Адрес бита - это адресуемая область в 40 разрядов из ячейки памяти. Операционное устройство взаимодействует с другими модулями. Может хранить свои данные в A, P и I модулях. При этом, например, из АЛУ данные брать нельзя. + +\includegraphics[width=10cm]{06-blocks-conn.png} + +Блоки соединены параллельно. Регистровый файл со всего четырьмя основными аккумуляторами, два 17-битных умножителя, один 40-битный АЛУ и сдвигатель, то есть многое можно выполнить параллельно. Все модули работают параллельно, но не все данные можно одновременно подавать везде. этим Арифметико-логический блок похож на архитектуру VLIW. + +\subsubsection{Регистровый файл} +Изображён на рисунке \hrf{pic:dsp-dunit} +\begin{itemize} +\item Хранение промежуточных данных D модуля +\item Двухсторонний обмен данными с блоками D модуля +\item Запись непосредственных данных из кода команды I модуля +\item Обмен промежуточными данными с модулями I, P, A и памятью +\end{itemize} + +\begin{table}[ht] + \centering + \begin{tabular}{R|C|C|C|} + & 39-32 & 31-16 & 15-0 \\ + \cline{2-4} + AC0 & AC0G & AC0H & AC0L \\ + AC1 & AC1G & AC1H & AC1L \\ + AC2 & AC2G & AC2H & AC2L \\ + AC3 & AC3G & AC3H & AC3L \\ + \cline{2-4} + \end{tabular} +\end{table} +\begin{itemize} +\item Регистры-аккумуляторы AC0, AC1, AC2, AC3 (Accumulators, Low, High, Guard) +\item Переходные регистры TRN0, TRN1 (TRaNsition registers) +\end{itemize} + +\subsubsection{Арифметико-логический блок} +\begin{itemize} +\item Получение непосредственных данных от I модуля +\item Двухсторонний обмен данными с регистрами модуля A и D, а также с ячейками памяти +\item Арифметические операции с данными в формате N40, Z40, Q9.31 +\item Многоразрядные логические операции +\end{itemize} + +\textbf{Операции арифметико-логического блока} + +\begin{wrapfigure}{r}{0.45\textwidth} + \begin{tikzpicture} + \draw (0,0)coordinate (O)--++(30:1)coordinate (A)--++(90:2)coordinate (B)--++(150:1)coordinate (C)--cycle; + \draw [->]($(A)!0.5!(B)$)--++(0:1)node[right]{$Z(N40)$}; + \draw [->]($(O)!0.5!(A)$)--++(-90:1)--++(0:2)node[right]{$CF, OF$}; + \draw [->]($(O)!0.25!(A)$)--++(-90:1.5)--++(0:2.25)node[right]{$SF$}; + \draw [->]($(O)!0.75!(A)$)--++(-90:0.5)--++(0:1.75)node[right]{$ZF$}; + \draw [<-]($(B)!0.5!(C)$)--++(90:0.5)--++(180:1.75)node[left]{$C_0$}; + \draw [<-]($(C)!0.33!(O)$)--++(180:0.5) node[left]{$X(N40)$}; + \draw [<-]($(C)!0.67!(O)$)--++(180:0.5) node[left]{$Y(N40)$}; + \end{tikzpicture} +\end{wrapfigure} + +АЛБ работает с натуральными числами, но мы можем интерпретироать результат как работу с числами с фиксированной запятой. Выполняет следующие операции: +\begin{itemize} +\item Поразрядные логические: + \begin{itemize} + \item отрицание – NOT; + \item конъюнкция – AND; + \item дизъюнкция – OR; + \item неэквиваленция – XOR. + \end{itemize} +\item Арифметические: + \begin{itemize} + \item изменение знака NEG; + \item абсолютное значение ABS; + \item сложение ADD; + \item вычитание SUB; + \item вычитание и сложение SUBADD; + \item сложение и вычитание ADDSUB; + \item сравнение CMP; + \item сравнение с конъюнкцией CMPAND; + \item сравнение с дизъюнкцией CMPOR; + \item максимум MAX, MAXDIFF; (maxdiff получаем максимальное из трёх) + \item минимум MIN, MINDIFF. + \end{itemize} +\item Округления: + \begin{itemize} + \item округление – ROUND; + \item насыщение – SAT. (если есть переполнение для знакового или переноса для беззнакового делаем адекватный результат) + \end{itemize} +\end{itemize} + +\subsubsection{Битовый блок} +\begin{itemize} +\item Выполнение операций манипуляции двоичными разрядами (битами): сброс, установка, инверсия (по его адресу), проверка. +\item Подсчет числа бит (за один такт, параллельно на комбинационной схеме) +\item Выполнение операций над битовыми полями (экономит скорость для битовых операций) +\item Нормализация чисел в формате с фиксированной запятой +\end{itemize} + +Адресация бит в регистрах: Используются те же методы, что и для адресации слов в памяти, например: \#3 – номер бита 3, *AR0+ – номер бита в регистре AR0 с увеличением на 1. + +\begin{itemize} +\item Битовые операции: + \begin{itemize} + \item очистка бит – BCLR; + \item инверсия бит – BNOT; + \item установка бит – BSET; + \item проверка бит – BTST; + \item проверка битовой пары – BTSTP; + \item установка бит с проверкой – BTSTSET; + \item очистка бит с проверкой – BTSTCLR; + \item инверсия бит с проверкой – BTSTNOT. + \end{itemize} +\item Операции с битовыми полями: + \begin{itemize} + \item извлечение бит BFXTR; (на слайде справа) + \item расширение бит BFXPA; + \item число бит – BCNT. (те биты, которые считаются - это данные непосредственно в коде команды) + \end{itemize} +\item Операции нормализации: + \begin{itemize} + \item порядок EXP; (выясняем число сдвигов, например, в зависимости от значений У нужно сдвинуть число, чтобы оно не потеряло значения. нормализуем число, преобразуем к числу с фиксированной запятой) + \item мантисса и порядок MANT::NEXP. (кроме порядка получает ещё и сдвинутую на нужное числу мантиссу) + \end{itemize} +\end{itemize} + +(06-11) +\begin{itemize} +\item Арифметические сдвиги 40-разрядных данных в форматов N40, Z40, Q9.31 от -31 до 32 разряда. +\item Арифметические сдвиги 16-разрядных данных форматов N16, Z16, Q1.15 от -31 до 32 разряда и сохранение результата в аккумуляторе. +\item Циклические сдвиги 16- и 40-разрядных данных в регистрах AC0-AC3 и TRN0, TRN1 +\end{itemize} + +(06-12) +Циклические сдвиги: влево ROL; вправо ROR. +F1, F2: CARRY, TC1, TC2 +\begin{lstlisting}[language=C,style=CCodeStyle] + unsigned int x, y; + x = (x & 0x1 ? 0x8000 : 0) | y >> 1; + y = (y & 0x8000 ? 0x1 : 0) | y << 1; +\end{lstlisting} + +Логические сдвиги: влево-вправо SFTL. +\begin{lstlisting}[language=C,style=CCodeStyle] + unsigned int x, y; + x = x << 3; y = y >> 2; +\end{lstlisting} + +Арифметические сдвиги: shts влево-вправо SFTS. +\begin{lstlisting}[language=C,style=CCodeStyle] + signed int x, y; + x = y << 3; y = y >> 2; +\end{lstlisting} + +(06-13) +Используются два 17-разрядных умножителя. Умножитель работает с 4мя форматами данных. форматы задаются 2мя флагами - знак-беззнак (sxmd) и целые-дробные (frc). +\begin{itemize} +\item Предварительное преобразование множителей в 17-разрядный формат (16 разрядов числа и один разряд знака). +\item Выполнение одинарных и двойных операций умножения со сложением (вычитанием) целых со знаком (SXMD=1) и без знака (SXMD=0), а также и дробных чисел (SXMD=1, FRC=1). +\end{itemize} +Примечание. 17-ти разрядный умножитель требуется для умножения целых чисел со знаком (флаг расширения знака SXMD равен нулю). + +(06-14) +первоначально выполняется коррекция результата (умножение на два), для этого используется 32 и 16й разряд. не можем подать 4 операнда, поэтому умножитель должен быть общий. +ACx, ACz,(40 разрядов): AC0, AC1, AC2, AC3 Ty, Tz (16 разрядов): T0, T1, T2, T3 +mac: ACx = ACy + (ACx * Tz ) +mac: ACy = (ACy * Tz ) + ACx +когда один из операндов константный +mack: ACy = ACx + (Tz * k8) +mack: ACy = ACx + (Tz * k16) + + +Встроенный параллелизм: +\begin{itemize} +\item MAC::MAC, MAC::MAS, MAC::MPY; +\item MAS::MAC, MAS::MAS, MAS::MPY; +\item MPY::MAC, MPY::MAS, MPY::MPY. +\end{itemize} + +Умножение – mpy (multiply) +Умножение со сложением (вычитанием) – mac (mas) (multiply and accumulate (subtract)) + +(06-15) +Подстановочные функции +\begin{lstlisting}[language=C,style=CCodeStyle] + int _sadd(int, int) + long _lsadd(long, long) + long long _llsadd(long long, long long) + int _ssub(int, int) + long _lssub(long, long) + long long _llssub(long long, long long) + int _smpy(int, int) + long _lsmpy(int, int) + long _smac(long, int, int) + long _smas(long, int, int) + int _abss(int) + long _labss(long) + long long _llabss(long long) + int _sneg(int) + long _lsneg(long) + long long _llsneg(long long); + long _smpyr(int, int) + long _smacr(long, int, int) + long _smasr(long, int, int) + int _norm(int) + int _lnorm(long) + long _rnd(long) + int _sshl(int, int) + long _lsshl(long, int) + int _shrs(int, int) + long _lshrs(long, int) +\end{lstlisting} + +например, \code{\_sadd:} +\begin{lstlisting}[language=C,style=CCodeStyle] + BSET SATA + ADD T1, T0 + BCLR SATA + RET +\end{lstlisting} + +\subsection{Устройство адресации (07)} +02. используется для формирования адресов на пяти шинах (все, кроме адреса для программ). чтобы операционное устройство записывало свои данные, которые вычислило в правильные места. + +03. используется магистралями данных, чтобы можно было использовать данные в регистровый файл и алу. имеется свой алу, который нужен для формирования сложных адресов. + +04. регистровый файл используется для +\begin{itemize} +\item Хранение промежуточных данных +\item Предоставление операндов и получение результатов операций +\item Обмен промежуточными данными с другими модулями и памятью +\end{itemize} + +В файле есть регистры +Регистры страниц данных: +DPH (7 бит), DP (16 бит), PDP (9 бит). +Регистры-указатели: +XSP (23 бита), XSSP (23 бита), XARx (8*23 бита), XCDP (16 бит). +Регистры циклического буфера: BSAxx (5*16 бит), BKxx (3*16 бит). +Временные регистры: Tx (4*16 бит). + +в РУ и ВР используются аргументы функции. + +05. генератор адресов +• Формирование физических адресов операндов +• Передача физических адресов на шины адреса для чтения и для записи данных + +06. АЛбА +• Сложение, вычитание, сравнение адресов. для умножения есть Д-юнит с двумя умножителями +• Логические и битовые операции с адресами +• Операции арифметических, логических и циклических сдвигов адресов +• Операции модификации регистров в косвенных методах адресации + +07. Регистры модуля А. +Регистры страниц данных (23 и 9 бит) +\begin{itemize} +\item DPH, DP - Data Page (High) +\item PDP - Peripheral Data Page +\end{itemize} +Регистры-указатели (23 бита) +\begin{itemize} +\item CDPH, CDP - Coefficient Data Pointer (High) +\item SPH, SP, SSP - (System) Stack Pointer (High) в системе есть два независимо работающих аппаратных стека. +\item XAR0-XAR7 - Extended Auxiliary Registers +\end{itemize} +Регистры циклического буфера (16 бит) +\begin{itemize} +\item BK03, BK47, BKC - Buffer size registers +\item BSA01, BSA23, BSA45, BSA67, BSAC - circular Buffer Start Address registers +\end{itemize} +Временные регистры (16 бит) +\begin{itemize} +\item T0-T3 - Temporary registers +\end{itemize} + +08. Регистры страниц данных +нужен чтобы оперировать короткими адресами относительно страницы, заданной в этом регистре. механизм «начальных адресов» в сигнальном режиме. по адресу 2Б находится старшая часть адреса страницы данных. + +Адресуем слова. если бы адресовали байты, то младший бит всегда был 0, поскольку слова это два байта и начало слов всегда было бы чётным. + +00 002Bh – 23-разрядный адрес 16-разрядного слова данных (BAB, CAB, DAB) +00 002Bh – 0000 0000 0000 0000 0010 1011 – адрес слова + +09. Регистры-указатели. +нельзя обратиться куда-то в область памяти, чтобы прочитать AR0H-AR7H. Поскольку мы не можем туда писать, если произошедший сбой запишет туда данные, получим ошибки адресаций. + +10. Временные регистры + +11. Регистры циклического буфера. Чтобы не нужно было писать на С код +\begin{lstlisting}[language=C,style=CCodeStyle] +#define H 131 +#define BK 1024 +int h[H], x[BK]; +y[BK], s; + +for (t = 0, t++, t < BK) { + s = 0; + for (i = 0; i++; i < H) { + s += ((long) h[i] * x[(t - i + BK) % BK]) >> 15; + } + y[t] = s; +} +\end{lstlisting} + +адреса считаются по формуле + +\[ + y (\tau) = \sum_{i=0}^{H-1} h(i) \times x(\tau - i) +\] + +и есть регистры, которые проверяют адресацию. для каждой группы регистров есть свои регистры размера и начального адреса. + +12. Методы адресации +непоср = команда находится в операнде +абсолют = адрес находится в коде команды +регистровая = в коде команды хранится регистр, а в регистре операнд +прямая = в команде есть смещение, добавляем к подразымеваемому базовому адресу +косвенная = в регистре адрес +базовая = в команде есть регистр и смещениее +бит-реверсивность это обратное распространение переноса при сложении, для БПФ. +циклическая когда указывается регистр относительно которого производим адресацию, остальное - по-умолчанию. + +13. Прямая адресация +если в сигнальной обработке стек не используется как привычно и команда засылает в регистр Т0 операнд, который отсчитывается смещением. память линейная, а не стековая. в режиме компилятора КПЛ 0 даже сложение упраздняется, и внутри стека используется прямая адресация. +\begin{verbatim} +CPL=0: MOV @2, T0 -> MOV *DP(2), T0 +CPL=1: MOV @2, T0 -> MOV *SP(2), T0 +\end{verbatim} + +14. Косвенная адресация +адрес хранится прямо внутри регистра с модификацией адреса во время разрешения +\begin{table}[h!] + \centering + \begin{tabular}{||p{25mm}|p{150mm}||} + \hline +Операнд & Модификация\\ + \hline +*ARx, *CDP & ARx, CDP не изменяется\\ +*ARx+, *CDP+ & XARx, CDP увеличивается на 1 (2)\footnote{Изменение регистра на 1 происходит, если операнд слово, на 2 – если двойное слово} после генерации адреса\\ +*ARx–, *CDP– & XARx, CDP уменьшается на 1 (2) --сноска1 после генерации адреса\\ +*+ARx & XARx увеличивается на 1 (2) --сноска1 перед генерацией адреса\\ +*–ARx & XARx уменьшается на 1 (2) --сноска1 перед генерацией адреса\\ +*(ARx + T0), *(ARx + T0B)\footnote{Режим адресации с обратным порядком бит, при котором 0 бит – старший, а 15 (31, 39) – младший;} & XARx увеличивается на T0 после генерации адреса\\ +*(ARx – T0), *(ARx – T0B)--сноска2 & XARx уменьшается на T0 после генерации адреса\\ +*ARx(T0) & XARx не изменяется, T0 используется как базовый\footnote{При базовой адресация адрес операнда равен XARx плюс T0, расширенный со знаком до 23 бит}\\ +*(ARx + T1) & XARx увеличивается на T1 после генерации адреса\\ +*(ARx – T1) & XARx уменьшается на T1 после генерации адреса\\ +*ARx(T1) & XARx не изменяется, T1 используется как базовый--сноска3\\ +*ARx(\#k16), *CDP(\#k16) & XARx, CDP не изменяется, k16 используется как смещение\footnote{Адрес операнда равен XARx плюс k16, расширенная со знаком до 23 бит.}\\ +*+ARx(\#k16) ,*+CDP(\#k16) & XARx, CDP увеличивается на k16 перед генерацией адреса\\ + \hline + \end{tabular} + \caption{Table to test captions and labels.} + \label{table:1} +\end{table} + +15. Циклическая адресация. + +Её надо включать в регистре АР1. используется специльная команда для загрузки адреса и смещения. + +; Размер циклического буфера в BK03 +; Настройка циклической адресации через AR1 +; Загрузка номера страницы в AR1H и очистка AR1 +; Загрузка стартового адреса буфера в BSA01 +; Пересылка в AC0 из 01 0A02 + AR1 = 01 0A02h +; Пересылка в AC0 из 01 0A02 + AR1 = 01 0A03h +; Пересылка в AC0 из 01 0A02 + AR1 = 01 0A04h +; Пересылка в AC0 из 01 0A02 + AR1 = 01 0A02h + + +16. Бит-реверсивная адресация +Как вычисляется БПФ? по формуле +\[ c(i) = \sum_{\tau=0}^{N-1} x(\tau) \times \omega_N^i(\tau), \omega_N^i = exp(-2\pi ji\tau / N), \omega_N^i = exp(-2\pi ji / N) \] +Примечание. Реализована путем сложения (вычитания) с обратным распространением переноса (заема). + +по этой формуле получается, что + 01100000 (+0) ++ 00000100 += 01100100 (+4) + 00000100 += 01100010 (+2) + 00000100 ..перенос ушёл не влево, а вправо += 01100110 (+6) + 00000100 += 01100001 (+1) + 00000100 += 01100101 (+5) + 00000100 += 01100011 (+3) + 00000100 += 01100111 (+7) +индексы выборки из массива получаем обратным распространением переноса. алгоритм требует непоследовательной выборки данных. + +17. режимы адресации меняются относительно режима работы процессора. прямоугольниками выделены режимы в виде прямой адресации и пропадают при переходе из сигнального режима в обычный и наоборот. + +18. Кодирование адресов при разных способах адресации +\begin{itemize} +\item Непосредственная: \#k3, ..., \#k16, \#k16, \#k23. +\item Абсолютная: *abs(\#a16) [DPH], *\#a23, port(\#a16). // старшая часть берётся из регистра DPH +\item Регистровая: ACx, TRNx, Tx, ARx, CDP, ... +\item Прямая: @a7 [XDP, XSP], port(@a7) [PDP]. +\item Косвенная:*ARx, *CDP, *ARx$\pm$, *CDP$\pm$, *$\pm$ARx. +\item Базовая: *ARx(k16), *CDP(k16), *+ARx(k16). +\item Индексная: *ARx(Tx), *(ARx$\pm$Tx), *+CDP(k16). +\item Циклическая: [CR.] *ARx$\pm$,*$\pm$ARx,*(ARx$\pm$Tx), *CDP$\pm$, *+ARx(k16), *+CDP(k16) [BSAxx, BKxx]. +\end{itemize} +19. Примеры адресации +• Непосредственная адресация \#: - константа (k3, k4, k5, k6); +- байт (K8, k8); +- слово (k9, k12, k16, K16); +- полуторное слово (k23). +MOV \#1Fh, DPH +• Регистровая адресация R. +BCLRAR0, AC0 +• Абсолютная адресация *\#: +- *abs(\#a16); - *\#a23; +- port(\#a16). +PSH *abs16(\#1234h) +• Прямая адресация @a7: +- через DP @a7 (CPL=0); - через SP @a7 (CPL=1); - через PDP port(@a7); +- битовая @k5. +MOV @\#–12, T0 +AND \#FFEFh, port(@\#1232h) +BTST @30, AC3 +• +Косвенная адресация *R, *±R, *R±: - не модифицирующая *R; +- постфиксная *R+, *R-; +- префиксная *+R, *-R. +MOV *CDP+, T2 +BSET *-AR2, AC1 +• Базовая адресация *+R(k16): +• +-немодифицирующая *R(k16); - модифицирующая *+R(k16). +MOV AR3, high\_byte(*CDP(\#4)) +BNOT *+AR4(\#3), AC2 +Индексная адресация *(R±R), *R(R): - знаковая *R(R); +- беззнаковая *(R±R); +- реверсивная *(R±RB). +MOV *AR1(T1) < < \#16, AC0 MAS *(AR6–T0), *CDP, AC2 BNOT *(AR2+T0B), AC3 +Циклическая адресация. ADD.CR dual(*CDP+), AC0, AC1 +• +BSET *(AR7+T0), AR5 + +20. Мнемоника команд +BTSTCLR k4, Smem, TCx +MOV HI(ACy < < T2), Ymem +MOV [uns(]high\_byte(Smem)[)], dst +MOV high\_byte(Smem) < < \#SHIFTW, ACx +ADD.CR dual(Lmem), ACx, Acy +MPY[R][40] [uns(]Ymem[)], [uns(]Cmem[)], Acx +MOV [uns(] [rnd(]HI[(saturate](ACx < < Tx)[)))], Smem +Smem, Lmem, Cmem, Xmem, Ymem – метод адресации операнда в памяти Baddr – метод адресации бита в регистре +kx (Kx) – непосредственная беззнаковая (знаковая) константа разрядности x U, uns – беззнаковый операнд +low\_byte (high\_byte) – младший (старший) байт \#SHIFTW – знаковая константа числа сдвигов mmap() – память отображения регистров +port() – адресное пространство ввода-вывода dbl – 32-разрядный операнд в памяти +dual – двойной доступ к памяти +HI (LO)– старшие (младшие) 16 разрядов аккумулятора pair – регистровая пара +R, rnd – округление, saturate - насыщение +.CR (.LR) – принудительная циклическая (линейная) адресация + +21. Кодирование команд +первые 4 бита говорят о коде команды, дальше 4 назначение и 7 смем (методы адресации) + +22. Вычисление адресов + +\subsection{Устройство управления (08)} +выбирает команды, которые нужно выполнять и организует как параллельное так и конвейерное исполнение. не имеет никакого отношения к шинам данных и адреса. извлекает команды из буфера команд. то есть выполняется кэширование команд (не из основной памяти, а из буфера). считывая код из буфера управляет остальными устройствами. также может передавать данные в устройства адресации и операционное, реализуется распределённая регистровая память. + +3. состоит из регистрового файла. можем читать 32разрядные данные. есть логика, которая может осуществлять переходы и генератор адреса. позволяет вызывать из двух команд одну. + +4. регистровый файл +\begin{itemize} +\item Хранение промежуточных данных P модуля +\item Двухсторонний обмен данными с генератором +\item Обмен промежуточными данными с модулями A, D и памятью +\end{itemize} + +5. внутри файла есть регистры +\begin{itemize} +\item Регистры потока команд: + \begin{itemize} + \item PC – Program Counter (счетчик команд); + \item RETA – RETurn Address (адреса возврата); + \item CFCT – Control Flow ConText (контекст потока управления). + \end{itemize} +\item Регистры статуса: ST0 - ST3 – Status (состояние микропроцессора). +\item Регистры повторения команды: (сколько раз надо повторить текущую команду) + \begin{itemize} + \item RPTC – RePeaT Counter (счетчик повторения); + \item CSR – Computed Single-Repeat (число повторений). + \end{itemize} +\item Регистры повторения блока: (аппаратурно реализуется цикл исполнения команд) + \begin{itemize} + \item BRC0, BRC1 – Block-Repeat Counter (счетчик повторения блока команд); + \item BRS1 – Block-Repeat Save (сохранение BRC1); + \item RSA0, RSA1 – Repeat Start Address (начальный адрес блока команд); + \item REA0, REA1 – Repeat End Address (конечный адрес блока команд). + \end{itemize} +\item Регистры прерываний: + \begin{itemize} + \item IVPD, IVPH – Interrupt Vector Page D, H (страницы векторов прерываний); + \item IFR0, IFR1 – Interrupt Flag Register (флаги прерываний); + \item IER0, IER1 – Interrupt Enable Register (разрешения прерываний); + \item DBIER0, DBIER1 – Debug Interrupt Enable Register. + \end{itemize} +\end{itemize} + +6. Регистр потока команд нужен чтобы запомнить текущее состояние блока повторений. +CFCT – Control Flow Context (контекст потока управления): +– A – Active (активность повторения текущей команды); +– C – Condition (состояние условия повторения текущей команды); +– S – Status (состояния двух уровней блочного повторения команд): активности, локальность (блок помещен в очередь команд или нет). +на примере указано как его читать и писать. + +7. Регистры простого повторения +имеются две команды, которые вычисляют значение цифрового фильтра. для умножения с аккумулированием. обращается к памяти, выполняет умн-слож и меняет адреса операндов для следующего чтения. по всем компонентам выходного вектора тоже нужен цикл. например, (на слайде слева). Е - это флаг параллельности. VLIW архитектура и параллельность на этапе компиляции. + +8. регистры блочного повторения +повторяется последовательность команд со вложенностью 2. в регистр загружаем константу кол-во повторений-1, потому что проверяется после тела. получается, что для оргагизации цикла нужна всего одна команда. в брц0 внешний блок в брц1 внутренний внутри брс - сохраняем текущее. в регистрах сохранения сохраняем откуда пришли и куда возвращаться. + +9. Регистры страниц прерываний +ISRx – Interrupt Service Routine x (двойное слово с адресом процедуры обработки прерывания и конфигурацией стека). +есть два вектора прерываний, то есть две таблицы адресов прерываний. для системных и пользовательских прерываний. если указать одинаковые адреса таблицы совместятся, но для того чтобы не было коллизий у них не пересекаются векторы. + +10. регистры прерываний +есть регистры флагов и разрешения прерываний. есть также регистры аппаратурной отладки. некоторые прерывания можно отлаживать, а некоторые нет. +INT2-INT23 – Interrupt 2-23 (флаги прерываний 2-23). +RTOSINTF – Real Time Operation System Interrupt Flag (флаг прерывания операционной системы реального времени). +DLOGINTF – Data log Interrupt Flag (флаг прерывания протоколирования данных). +BERRINTF – Bus Error Interrupt Flag (флаги прерывания по ошибке обмена по шинам и магистралям). +DBIERx – Debug Interrupt Enable Register (регистры аппаратурной отладки, флаги указывают, какие прерывания вызывают переход в отладочный режим) + +11. Конфигурация стеков +есть две конфигурации - для медленного вызова и возврата функций и для быстрого вызова. чтобы это регулировать используются разные коды ЦА и ДА. есть возможность задавать для того процесса, который будет запускаться прерываний свою конфигураци. если используется медленный вызов - это похоже на обычные процессоры. при быстром вызове и возврате извлекается из стека счётчик команд. используется регистр контекста повторения для сохранения адреса возврата. перед записью новых данных нужно сохранять существующие на стеке. чтение и запись выполняется параллельно. инициируем процесс чтения и одновременно параллельно записывается старшая часть регистра и контекста. Пока получаем следующую команду первая уже запишется. при возврате происходит обратный процесс, регистры заполняются из стека. на слайде ошибка стек должен при завершении увеличиваться. + +12. в зависимости от текущих условий можем вызывать подпрограмму или нет, которая находится по относительному адресу в регистрах. возврат также бывает по условию. + +Соглашения о вызове +\begin{itemize} +\item сdecl - аргументы передаются через стек справа налево, очистку стека производит вызывающая функция. позволяет ellipsis-notation +\item stdcall - аргументы передаются через стек справа налево, очистку стека производит вызываемая функция. +\item pascal - аргументы передаются через стек слева направо, очистку стека производит вызываемая функция. +\item fastcall - аргументы передаются через регистры и через стек. если не помещаются только в регистры. +\item r = fun(a1, a2, a3, ...); +\end{itemize} + +Передача аргументов +\begin{itemize} +\item Аргументы функции передаются через стек или через регистры в следующем порядке: + \begin{itemize} + \item указатели - (X)AR0, (X)AR1, ..., (X)AR4; + \item данные 16 бит - T0, T1, AR0, ..., AR4; + \item данные 32 или 40 бит - AC0, AC1, AC2; + \item аргумент перед многоточием – в стеке. + \end{itemize} +\item Структуры более 32 бита передаются через указатель. +\item Аргументы в стеке размещаются в порядке, обратном вызову: *SP(0) – адрес возврата, *SP(1) - 1-й аргумент, ... +\end{itemize} + +15. Возврат результата +\begin{itemize} +\item Данные 16 бит – в T0. +\item Данные 32 или 40бит – в AC0. +\item Указатель (24) 16 бит – в (X)AR0. +\item Структура более 32 бита – в первом аргументе – указатель на структуру, если он 0x0, то структура не возвращается. +\end{itemize} +\begin{verbatim} +struct x func(char, int*, long, long long, int, ...) +\end{verbatim} +поскольку данные на стеке выравниваются по два слова, смещение на чётное число. + +Сохранение регистров +\begin{itemize} +\item Вызываемая функция: + \begin{itemize} + \item должна сохранять и восстанавливать T2, T3, AR5-AR7 при использовании; + \item может использовать T0, T1 , AR0, AR1, ..., AR4, AC0, AC1, ..., AC3 без сохранения. + \end{itemize} +\item Вызывающая функция должна сохранять перед вызовом используемые ей регистры T0, T1, AR0, AR1, ..., AR4, AC0, AC1, ..., AC3. +\item При использовании сохраняются регистры RETA, BKx, BRCx, BRS1, BSAx, RSAx, REAx, RPTC, CSR, TRNx, (X)DP, (X)CDP, STx\_55. +\end{itemize} +17. Локальные переменные +• При установленном флаге CPL в ST1 доступ к данным осуществляется через SP, в противном случае – через DP. +• Выделение (освобождение) локальной +памяти: ASUB \#n, SP (AADD \#n, SP). + +\subsection{Буфер команд (09)} +(02, 03) +представляет собой 128байтный сдвиговый регистр. все команды поступают на дешифратор и соответствующие данные поступают в P- A- D-модули. У некоторых моделей также есть кэш память команд для ускорения повторного обращения. + +(04) для управления кэш-памятью есть специальные биты в регистре статуса. флаг замораживания позволяет задержать данные в кэше. П-модуль выдаёт адреса для чтения текущей команды и данные должны поступить в И-юнит. К-контроллер изначально просто транслирует эти данные в буфер команд по магистрали. помимо этого данные пишутся в К-память (где хранятся как данные, так и адрес). Если П-юнит снова запросит данные, сначала проверяем кэш. + +(05) кэш память прямого отображения. все данные разбиваются на три части тэг, набор и смещение по адресу. у нас 2 бита сдвига поэтому блоки будут по 4 байта. сет - это 512 возможных значений. так как в одном месте хранятся разные теги их надо различать (12 разрядов). адрес вызывает коммутацию на компаратор тэга. если тег совпал с тем, которых хранится в этом месте - получаем кэш хит. если хит - данные поступают на магистраль для очереди команд. если промах - ждём несколько тактов пока не поступят данные со внешней памяти. узкое место это использование одной памяти для разных тегов. то есть если у нас будут разные теги каждый раз - всегда будет необходимость брать новые данные и кэширование сведётся к нулю. + +(06) ассоциативная КП. является развитием КП с ПО. появилась из-за того что мы хотим расширить объём кэша с одним тэгом. имеем 4 КППО. получается может быть несколько данных с одним и тем же тегом. то есть имеем устройство сравнения тегов. +\begin{itemize} +\item С5501, C5502 – ассоциативная кэш-память с двумя наборами +\item С5510 – режим ассоциативной кэш-памяти с двумя наборами и режим кэш-памяти с прямым отображением +\end{itemize} + +(07) Очередь команд +есть кэш или нет - происходит наполнение очереди команд. максимальная длина команды 6 байт. магистраль 4, поэтому команда может не поместиться и будем читать её в два захода. для этого и нужна очередь. + +Загрузка 32-битных слов в конец очереди. +\begin{itemize} +\item Сдвиг команд в буфере к началу очереди. очередь загружает по 32бита последовательно сдвигая предыдущие данные. +\item Передача первых 6 байт в декодер команд. каждые полученные 6 байт являются командой. +\item Хранение локальных блоков повторения (до 128 байт). Если в 128 байтах нет вызовов процедур то они не будут вытеснены из кэша. +\item Очистка буфера при ветвлениях в программе (переходы, вызов и возврат подпрограмм, прерывания) +\end{itemize} + +(09) Декодер команд +\begin{itemize} +\item Получение 6 байт кода для декодирования команды и определения ее размера. +\item Передача команд другим устройствам. +\item Выявление и декодирование команд, которые могут выполнятся параллельно. +\item Передача устройствам непосредственных данных. +\item Передача длины команды для сдвига очереди команд. +\end{itemize} + +(10) Чтобы ускорить выполнение применяется конвейеризация. +(11) у конвейера выборки есть 4 стадии +\begin{itemize} +\item PF1 – Prefetch 1 (выдача адреса на шину PAB) +\item PF2 – Prefetch 2 (ожидание устройства памяти) целый такт +\item F – Fetch (получение данных и запись в очередь) +\item PD – Predecode (предварительное декодирование команды в очереди: определение начала и окончания, обнаружение параллельности) +\end{itemize} +чем-то напоминает суперскалярные архитектуры, например х86. + +(12) понятно, что параллельно будут несколько операций загрузки, но на разных стадиях. если мы изменяем последовательность команд конвейер очищается и по новому адресу загружается новая последовательность команд с 1й стадии + +(13) конвейер выполниения содержит 8 стадий +• D – Decode (декодирование команды) +• AD – Address (вычисление адреса) +• AC1 – Access 1 (доступ 1) +• AC2 – Access 2 (доступ 2) +• R – Read (чтение) +• X – Execute (выполнение) +• W – Write (запись в регистры) +• W+ – Write (запись в память) + +если операнд в регистре то ас1 ас2 не нужны и будут холостые такты. третья стадия записи совпадает с декодированием для следующей команды + +(14) Декодирование команды (D) + Чтение 6 байт из буфера команд +• Декодирование одной или двух команд +• Передача команд устройствам +• Чтение режимов адресации: +CPL – режима адресации компилятора; ARMS – режим косвенной адресации; ARxLC, CDPLC – циклическая адресация. + +(15) Вычисление адреса(AD) +Чтение регистров, используемых для адресации операндов +• Вычисление адреса операнда – выполнение операции ALU устройства адресации +• Выполнение префиксной операции адресации – модификация регистров +• Вычисление условий ветвления и перезагрузка конвейера при ветвлении, вызове подпрограммы, прерывании) + +(16) доступ ас1 и ас2 +• AC1 – передача адреса операнда на соответствующую шину адреса (BAB, CAB, DAB) +• AC2 – ожидание данных из памяти один такт + +(17) чтение (сигнальный процессор умеет в аппаратные условные операции, которые выполняются как раз на этой стадии). +• Считывание данных из памяти или отображаемых в память регистров (магистрали данных BB, CB, DB) +• Чтение регистров устройства адресации, участвующих в операции обработки данных +• Вычисление условий для условных операций обработки данных + +(18) Выполнение +• Чтение и модификация регистров, участвующих в операции, кроме регистров, отображаемых в память (изменение регистров операционного устройства) +• Чтение и модификация отдельных бит (устройство битовых операций DB\_BIT) +• Установка условий по результату операции обработки данных + +(19) Запись результата +• W – Запись данных в регистры, отображаемые в память, регистры периферийных устройств или начало записи данных в ячейку памяти +• W+ – Завершение записи данных в ячейку памяти + +(20) так как параллельность из 8 этапов - каждая команда будет выполняться примерно один такт. каждое ветвление это перезагружка конвейера, то есть теряется 8 тактов. + +(21) почему возникает перезагрузка +• Команды условных переходов ВСС +• Команда безусловного перехода B +• Команда вызова подпрограммы CALL +• Программное прерывание INTR +• Внешние прерывания по сигналу INT0, INT1 +• Внутренние немаскируемые прерывания по сигналу NMI +• Сброс процессора по сигналу RESET или командой программного сброса RESET + +(22) Конфликты записи до чтения +конфликт - это когда две соседние команды не могут выполняться подряд из-за зависимости результатов предыдущих команд. способа кроме добавления холостых циклов нет + +уязвимость Meltdown + +(23) Конфликты доступа +При параллельном выполнении команд забота о предотвращении конфликтов в конвейере ложится на компилятор (на программиста) + +(24) параллельное выполнение нескольких команд +независимые устройства - каждый юнит из изученных. + +(25) виды параллелизма +• Встроенный (нет бита параллельности E) MPY *AR0, *CDP, AC0 ; 1-й умножитель :: MPY *AR1, *CDP, AC1 ; 2-й умножитель +это команды со сверхдлинным командным словом. это сцепленные между собой команды. + +• Пользовательский (бит E во 2-ой команде) ADD AC0, AC1 ; AЛУ D-блока +|| XOR AR2, CDP ; AЛУ A-блока, E=1 +можем использовать две команды для выполнения операции. компилятор добавляет специальный бит XOR и используем АЛУ блока адресации + +• Комбинированный (бит E в 3-ей команде) MPY *AR3+, *CDP+, AC0 ; 1-й умножитель :: MPY *AR4+, *CDP+, AC1 ; 2-й умножитель || MOV \#5, AR1 ; РФ А-блока, E=1 +засылает команду в регистровый файл и тогда одновременно выполняется три команды. + +• Двойной доступ (доступ к памяти, нет E) MOV *AR-, AC1 ; CAB/BB, DAB/DB MOV *CDP+, AC2 ; BAB/BB + + +\newpage +\subsection{Обработка прерываний (10)} +\textbf{Прерывание (Interrupt)} – переключение микропроцессора на выполнение программ обработки асинхронно возникающих внутренних или внешних событий. Прерывание может иметь как внешние, так и внутренние причины. Чтобы программа могла нормально выйти из обработки прерывания и восстановить работ, нужно сохранить текущий контекст, а затем его восстановить, это часть времени реакции на прерывание. + +\subsubsection{Источники прерываний} +\begin{itemize} +\item Источники прерываний: – немаск\'{и}руемые: + \begin{enumerate} + \item внутреннее – от схем контроля \code{NMI}; + \item сброс по входу \code{RESET}; + \end{enumerate} +\item маск\'{и}руемые: + \begin{enumerate} + \item внешние – по входу \code{INT0}, \code{INT1}; + \item аппаратурные – от модулей; + \end{enumerate} +\item программные – по командам \verb|INTR #k4|, \verb|TRAP #k4|. Фактически входят в состав маск\'{и}руемых +\end{itemize} +(04) + +\subsubsection{Последовательность прерывания} +\begin{enumerate} +\item Аппаратурные средства + \begin{enumerate} + \item Контроллер устройства генерирует запрос на прерывание + \item Процессор прекращает исполнение текущей программы + \item Процессор сигнализирует о получении прерывания и считывает вектор прерывания + \item Процессор заносит слово состояния и программный счётчик в стек + \item в программный счётчик загружается новое значение, пределяемое прерыванием + \end{enumerate} +\item Программные средства + \begin{enumerate} + \item Сохранение данных состояния процессора + \item Обработка прерывания + \item Восстановление данных состояния процессора + \item Восстановление старого слова состояния программы и содержимого программного счётчика + \end{enumerate} +\end{enumerate} + +(6) +5000-стек50001-вектор0004-6000-обработчик6000-6100-RETI-стекST-5001 + +\textbf{Вложенные прерывания} +(7) +как правило нет систем без глубины вложенности прерываний и без приоритетов прерываний. + +\subsubsection{Вектор прерываний} +\begin{table}[h!] + \centering + \begin{tabular}{r|lr|} + \cline{2-3} + & 15 & 0 \\ [0.5ex] + \cline{2-3} + IVPD & 00 0049h & Страница векторов 0-15, 24-31 \\ + IVPH & 00 004Ah & Страница векторов 16-23 \\ + \cline{2-3} + \end{tabular} +\end{table} +Обе эти таблицы могут обрабатывать 32 прерывания. разнесены для организации отдельно обработки пользовательских Human и ОС Device прерываний. +\begin{table}[h!] + \centering + \begin{tabular}{r|r|r} + Вектор & \textbf{IVPD}|00h & Байт \\ [0.5ex] + \cline{2-2} + (8) + \end{tabular} +\end{table} + +Процедура прерываний +(9) +ISR – Interrupt Service Routine (процедура обработки прерывания). +SC – Stack Configuration (байт конфигурации стека, игнорируется для всех векторов, кроме RESET): CAh – быстрый вызов-возврат и два независимых 16- разрядных стека; DAh – медленный вызов-возврат и два независимых 16- разрядных стека; EAh – медленный вызов-возврат и единый 32-разрядный стек. +EP – Entry Point (точка входа, или 24-разрядный адрес процедуры). + +Чтобы разрешить или зарпетить маскируемые прерывания выставляем 11й бит в регистре ST1\_55. В этом регистре мы можем также задавать разные режимы работы прерываний. + +\subsubsection{Конфигурация стеков} +Медленный вызов и возврат \code{NO_RETA} (ISR DAXX:XXXXh) регистр возврата не используется +Быстрый вызов и возврат \code{USE_RETA} (ISR CAXX:XXXXh) регистр возврата используется +(10) +\begin{itemize} +\item \textbf{CALL}: [PC, Контекст повторения]$\to$[RETA, CFCT] :: [RETA, CFCT]$\to$[*-SP, *-SSP] +\item \textbf{RET}: [RETA, CFCT]$\to$[PC, Контекст повторения] :: [*SP-, *SSP-]$\to$[RETA, CFCT] +\end{itemize} + +\subsubsection{Регистры и источники прерываний} +(11) +\begin{itemize} +\item [] \textbf{INT2-INT23} – Interrupt 2-23 (флаги прерываний 2-23). +\item [] \textbf{RTOSINTF} – Real Time Operation System Interrupt Flag (флаг прерывания операционной системы реального времени). +\item [] \textbf{DLOGINTF} – Data log Interrupt Flag (флаг прерывания протоколирования данных). +\item [] \textbf{BERRINTF} – Bus Error Interrupt Flag (флаги прерывания по ошибке обмена по шинам и магистралям). +\item [] \textbf{DBIERx} – Debug Interrupt Enable Register (регистры аппаратурной отладки, флаги указывают, какие прерывания вызывают переход в отладочный режим) +\end{itemize} + +\begin{table}[H] + \centering + \begin{tabular}{|c|c|c|c|} + \hline + Вектор & Адрес & Приор. & Обозначение и источник прерывания \\ [0.5ex] + \hline + ISR00 & IVPD:00h & 1 & RESET, по сбросу и инициализации \\ + ISR01 & IVPD:08h & 3 & NMI, от схем контроля (внутреннее немаскируемое)\\ + ISR02 & IVPD:10h & 5 & INT0, внешнее прерывание по входу INT0 \\ + ISR03 & IVPD:18h & 7 & INT1, внешнее прерывание по входу INT1 \\ + ISR04 & IVPD:20h & 8 & TINT, агрегированное прерывание от таймеров \\ + ISR05 & IVPD:28h & 9 & PROG0, от контроллера I2S0 и MMC/SD0 по передаче \\ + ISR06 & IVPD:30h & 11 & UART, от приемо-передатчика UART \\ + ISR07 & IVPD:38h & 12 & PROG1, от контроллера I2S0 и MMC/SD0 по приему \\ + ISR08 & IVPD:40h & 13 & DMA, от канала прямого доступа к памяти \\ + ISR09 & IVPD:48h & 15 & PROG2, от контроллера I2S1 и MMC/SD1 по передаче \\ + ISR10 & IVPD:50h & 16 & FFT, от аппаратного ускорителя БПФ \\ + ISR11 & IVPD:58h & 17 & PROG3, от контроллера I2S1 и MMC/SD1 по приему \\ + ISR12 & IVPD:60h & 19 & LCD, от контроллера дисплея \\ + ISR13 & IVPD:68h & 20 & SAR, агрегированное от АЦП \\ + ISR14 & IVPD:70h & 23 & XTM2, от контроллера I2S2 по передаче \\ + ISR15 & IVPD:78h & 24 & RCV2, от контроллера I2S2 по приему \\ + \hline + \end{tabular} + \caption{Источники прерываний IVPD.} +\end{table} + +\begin{table}[H] + \centering + \begin{tabular}{|c|c|c|c|} + \hline + Вектор & Адрес & Приор. & Обозначение и источник прерывания \\ [0.5ex] + \hline + ISR16 & IVPH:80h & 6 & XMT3, от контроллера I2S3 по передаче \\ + ISR17 & IVPH:88h & 10 & RCV3, от контроллера I2S3 по приему \\ + ISR18 & IVPH:90h & 14 & RTC, от часов реального времени \\ + ISR19 & IVPH:98h & 18 & SPI, от контроллера SPI \\ + ISR20 & IVPH:A0h & 21 & USB, от контроллера USB \\ + ISR21 & IVPH:A8h & 22 & GPIO, от портов ввода-вывода общего назначения \\ + ISR22 & IVPH:B0h & 23 & EMIF, от интерфейса внешней памяти при ошибках \\ + ISR23 & IVPH:B8h & 26 & I2C, от контроллера I2C \\ + ISR24 & IVPD:C0h & 4 & BERR, при ошибке обмена по шинам и магистралям \\ + ISR25 & IVPD:C8h & 27 & DLOG, протоколирование данных (программное) \\ + ISR26 & IVPD:D0h & 28 & RTOS, вызов операционной системы (программное) \\ + ISR27 & IVPD:D8h & – & RTDRCV, от эмулятора по приему \\ + ISR28 & IVPD:E0h & – & RTDXMT, от эмулятора по передаче \\ + ISR29 & IVPD:E8h & 2 & EMUINT, от монитора эмулятора \\ + ISR30 & IVPD:F0h & – & SINT30, пользовательское (программное) \\ + ISR31 & IVPD:F8h & – & SINT31, пользовательское (программное) \\ + \hline + \end{tabular} + \caption{Источники прерываний IVPD.} +\end{table} + +\subsubsection{Секция vectors} +\begin{lstlisting}[style=ASMStyle] + .sect "vectors" + .ref _c_int00, _nmi_isr, _sarISR, _int0_isr, _int1_isr, _tim_isr + .ref _i2s0_mmc0_tx_isr, _uart_isr, _i2s0_mmc0_rx_isr, _dma_isr .ref _i2s1_mmc1_tx_isr, _coprocfft_isr, ..., _sint31_isr + .def _VECSTART, _no_isr +_VECSTART: ; USE_RETA, NO_RETA, C54X_STK +RST: .ivec _c_int00, USE_RETA ; 00 Reset / Software Interrupt #0 +NMI: .ivec _nmi_isr ; 01 Nonmaskable Interrupt +INT0: .ivec _int0_isr ; 02 External User Interrupt #0 +INT1: .ivec _int1_isr ; 03 External User Interrupt #1 +TINT: .ivec _tim_isr ; 04 Timer #0 / Software Interrupt #4 +PROG0: .ivec _i2s0_mmc0_tx_isr ; 05 Programmable 0 Interrupt +UART: .ivec _uart_isr ; 06 IIS #1 Receive Interrupt +PROG1: .ivec _i2s0_mmc0_rx_isr ; 07 Programmable 1 Interrupt +DMA: .ivec _dma_isr ; 08 DMA Interrupt +PROG2: .ivec _i2s1_mmc1_tx_isr ; 09 Programmable 2 Interrupt +FFT: .ivec _coprocfft_isr ; 10 Coprocessor FFT Module Interrupt +PROG3: .ivec _i2s1_mmc1_rx_isr ; 11 Programmable 3 Interrupt +LCD: .ivec _lcd_isr ; 12 LCD Interrupt +SAR: .ivec _saradc_isr ; 13 SAR ADC Interrupt +XMT2: .ivec _i2s2_tx_isr ; 14 I2S2 Tx Interrupt +RCV2: .ivec _i2s2_rx_isr ; 15 I2S2 Rx Interrupt +XMT3: .ivec _i2s3_tx_isr ; 16 I2S3 Tx Interrupt +RCV3: .ivec _i2s3_rx_isr ; 17 I2S3 Rx Interrupt +RTC: .ivec _rtc_isr ; 18 RTC interrupt +SPI: .ivec _spi_isr ; 19 SPI Receive Interrupt +USB: .ivec _usb_isr ; 20 USB Transmit Interrupt +GPIO: .ivec _gpio_isr ; 21 GPIO Interrupt +EMIF: .ivec _emif_error_isr ; 22 EMIF Error Interrupt +I2C: .ivec _i2c_isr ; 23 IIC interrupt +BERR: .ivec _berr_isr ; 24 Bus Error Interrupt +DLOG: .ivec _dlog_isr ; 25 Emulation Interrupt - DLOG +RTOS: .ivec _rtos_isr ; 26 Emulation Interrupt - RTOS +RTDRCV: .ivec _rtdxrcv_isr ; 27 Emulation Interrupt - RTDX receive +RTDXMT: .ivec _rtdxxmt_isr ; 28 Emulation Interrupt - RTDX transmit +EMUINT: .ivec _emuint_isr ; 29 Emulation monitor mode interrupt +SINT30: .ivec _no_isr ; 30 Software Interrupt #30 +SINT31: .ivec _sint31_isr ; 31 Software Interrupt #31 + .text +_no_isr: nop +label: jmp label +\end{lstlisting} + +\begin{lstlisting}[language=C,style=CCodeStyle, caption={Описание регистров}] +#define Uint16 unsigned int +typedef struct { + volatile Uint16 IER0; /*0000h – <@\lh{dkgreen}{разрешения прерываний}@> 0 */ + volatile Uint16 IFR0; /*0001h – <@\lh{dkgreen}{флаги прерываний}@> 0 */ + volatile Uint16 ST0_55; /*0002h – <@\lh{dkgreen}{состояние процессора}@> 0 */ + volatile Uint16 ST1_55; /*0003h – <@\lh{dkgreen}{состояние процессора}@> 1 */ + volatile Uint16 ST3_55; /*0004h – <@\lh{dkgreen}{состояние процессора}@> 3 */ + volatile Uint16 Res0[64]; /*0008h – <@\lh{dkgreen}{регистры микропроцессора}@> */ + volatile Uint16 IER1; /*0045h – <@\lh{dkgreen}{разрешения прерываний}@> 1 */ + volatile Uint16 IFR1; /*0046h – <@\lh{dkgreen}{флаги прерываний}@> 1 */ + volatile Uint16 DBIER0; /*0047h – <@\lh{dkgreen}{разрешения отладки}@> 0 */ + volatile Uint16 DBIER1; /*0048h – <@\lh{dkgreen}{разрешения отладки}@> 1 */ + volatile Uint16 IVPD; /*0049h – <@\lh{dkgreen}{таблица прерываний}@> D */ + volatile Uint16 IVPH; /*004Ah – <@\lh{dkgreen}{таблица прерываний}@> H */ + volatile Uint16 ST2_55; /*004Bh – <@\lh{dkgreen}{состояние процессора}@> 2 */ + volatile Uint16 Res1[4]; /*004Ch – <@\lh{dkgreen}{регистры микропроцессора}@> */ +} INT_Registers; + +#define INT_REGS ((INT_Registers*)0x0000) + +INT_REGS->IVPD = (Uint16)(VECTSTART >> 8); +INT_REGS->IVPH = INT_REGS->IVPD; +\end{lstlisting} + +(17-18-19) +\begin{lstlisting}[language=C,style=CCodeStyle, caption={Установка вектора (C)}] + typedef void (*isr)(void); + isr ISR_plug(int num, isr iep) { + unsigned long old, *ivp; + unsigned int *reg; + reg = (unsigned int*)(num >= 16 && num <= 23 ? 0x49 : 0x4A); + ivp = (unsigned long*)(*reg << 3 + num << 2); + asm(" BSET INTM"); + + asm(" BCLR INTM"); + } +\end{lstlisting} + +\section{Прямой доступ к памяти} +(11-06) В домашке 3 входные данные могут поступать на плату или с микрофона или с кабеля. Необходимо осуществить двойную буферизацию и конвейер. +\begin{frm} + getSample + заполнить буфер + обработать буфер + putSample +\end{frm} + +В реальных системах такая обработка делается не через прерывания, а через систему прямого доступа к памяти. У современных систем 16 каналов для обработки. Из них слышимые канальные данные 12+1. +Если используем прерывания то данные идут через CPU, если нет, то напрямую. +RAM – Random Access Memory (память с произвольным доступом). +CPU – Central Processor Unit (центральный процессор). +DMA – Direct Memory Access (прямой доступ к памяти). +PIO – Programmable Input-Output (программный ввод-вывод данных). + +(11-03) Прямой доступ к памяти +У всех микропроцессоров есть канал DMA. В случае ЕМИФ МП получает доступ к общей внешней памяти многопроцессорной системы. HPI - специальный тип доступа ко внутренней памяти кристалла. у интел это называется non-uniform memory access. у арма есть аналог. +Direct Memory Access (прямой доступ к памяти) – режим обмена данными между микропроцессорами, устройствами микропроцессора или же между устройством и основной памятью, в котором центральный процессор не участвует: +• Direct memory access (DMA) – доступ устройств к основной памяти; +• Extended memory interface (EMIF) – доступ микропроцессора к внешней и общей памяти мультипроцессорной системы; +• Host port interface (HPI) – доступ микропроцессора к основной памяти другого микропроцессора. + +(11-04) Канал прямого доступа +Канал прямого доступа получает доступ через внутреннюю шину. арбитр регламентирует доступ к шине. Обычно это два такта, но можно сделать и за один при этом канал выдаёт устройству сигнал чтения, а основной памяти сигнал записи. +DRQ – DMA Request (запрос прямого доступа к памяти). +DACK – DMA Acknowledge (предоставление прямого доступа). +A (D) – Address (Data) Bus (шина адреса и магистраль данных). +R (W) – Read (Write) command (сигналы чтения и записи). + +(11-05) в нашем МП есть 4 контроллера по 4 канала прямого доступа к памяти. всего 16 каналов, помимо регистров для настройки чтения и записи имеется ещё и буфер, в зависимости от готовности устройств можем читать быстрее, чем записали. Внутри такой буфер устроен как очередь. Переключение буферов происходит как в домашке. Чем меньше размер буфера, тем больше накладные расходы, но чем больше буфер, тем дольше сама обработка. + +Интерфейс внешней и внутренней памяти. +Канал прямого доступа считывает данные из одного контроллера (из одного сегмента) и записывает, например, в память двойного доступа. После чего переходит в режим ожидания. Важно, что адресация данных и адресация устройств - разная. + +% (11-09) Интерфейс памяти EMIF +% EM_WE – Write enable; EM_BA[1:0] – Bank Address; EM_A[20:0] – Address bus; EM_D[15:0] – Data bus; EM_DQM[1:0] – Byte enables; +% EM_SDCKE – Clock Enable; EM_SDCLK – Clock; +% EM_CS[1:0] – Chip Select; EM_SDRAS – Row Address Strobe; EM_SDCAS – Column Address Strobe; +% EM_CS[5:2] – Chip Select; EM_OE – Output Enable; EM_RW – Read/Write; EM_WAIT[3:0] – Wait signals; + +У емиф есть некоторый центральный контроллер, который подключается к процессору, память, юсб, дисплей. Пассивными устройствами внутренней памяти являются САРАМ и ДАРАМ. можем читать из внутренней памяти. Устройство имеет регистры, чтобы можно было регулировать интерфейс внешней памяти. Возможно подключить два типа внешней памяти синхронную и асинхронную. Есть общие линии для обоих этих интерфейсов. При асинхронном обмене есть обратная связь от внешней памяти поскольку память работает медленнее микропроцессора. + +Схемы включения: (11-19)(11-22)(11-29) +в асинк есть сигнал ожидания +в общей есть сигналы синхронизации + +(11-10) Динамическая память +статическая память хранит постоянно, а динамическая максимум 4мсек и поэтому нужно постоянно её обновлять, в МП этим занимается специальный контроллер-регенератор. Любое чтение строки восстанавливает состояние в этой строке. Если чтения не было конденсатор обнуляется. Для получения конкретного бите есть мультиплексор, на который подключен сигнал номера колонок. +RAS – Row Address Strobe (строб адреса строки) +CAS – Column Address Strobe (строб адреса столбца) +RG – Register (регистр с параллельной записью) +CT – Counter (счетчик с параллельной записью) +DC – Decoder (дешифратор, декодер) +MUX – Multiplexor (мультиплексор, коммутатор) + +(11-11) Режимы работы ДП. +Страничный - читаем сразу блок, и потом уже читаем из кэша. +пакетный - если номера столбцов меняются последовательно, то зачем их задавать. и так с каждым следующим тактом будет поступать сразу следующий бит данных. + +(11-13) таким образом команды RAS CAS BA стали частью кода команд процессора для работы с памятью. + + + +\section{Взаимодействие микропроцессора со внешними устройствами} +\subsection{Входы-выходы общего назначения(12)} +снизу справа 3 вторичных источника внутреннего питания (3 LDO), двухканальный ЦАП резистивного экрана (SAR), LCD индикатор 400х200, UART, два $I^2S$ (и ещё два сверху) двунаправленный двухканальный интерфейс, SPI, GPIO. Последовательный интерфейс I2S ни с кем не конкурирует, но для этого остальные интерфейсы (особенно внизу микропроцессора) значительно намешаны. То есть возможно комбинировать SPI, UART, I2C или GPIO, например. Часть выводов для графического дисплея могут забираться от SPI и GPIO. Очевидна проблема, что число выводов недостаточно. Для полного описания таких комбинаций вводят таблицу альтернативных функций. + +\begin{table}[h!] + \centering + \begin{tabular}{||r|c|c||} + \hline +Имя & Вывод & Альтернативная функция\\ +GP[0] & L10 & MMC0\_CLK, I2S0\_CLK\\ +GP[1] & M11 & MMC0\_CMD, I2S0\_FS\\ +GP[2] & L9 & MMC0\_D0, I2S0\_DX \\ +GP[3] & M10 & MMC0\_D1, I2S0\_RX \\ +GP[4] & L12 & MMC0\_D2 \\ +GP[5] & L11 & MMC0\_D3 \\ +GP[6] & M13 & MMC1\_CLK, I2S1\_CLK \\ +GP[7] & L14 & MMC1\_CMD, I2S1\_FS \\ +GP[8] & M14 & MMC1\_D0, I2S1\_DX \\ +GP[9] & M12 & MMC1\_D1, I2S1\_RX \\ +GP[10] & K14 & MMC1\_D2 \\ +GP[11] & L13 & MMC1\_D3 \\ +GP[12] & P7 & LCD\_D[2] \\ +GP[13] & N7 & LCD\_D[3] \\ +GP[14] & N8 & LCD\_D[4] \\ +GP[15] & P9 & LCD\_D[5] \\ +GP[16] & N9 & LCD\_D[6] \\ +GP[17] & P10 & LCD\_D[7] \\ +GP[18] & N10 & LCD\_D[8], I2S2\_CLK, SPI\_CLK \\ +GP[19] & P11 & LCD\_D[9], I2S2\_FS, SPI\_CS0 \\ +GP[20] & N11 & LCD\_D[10], I2S2\_RX, SPI\_RX \\ +GP[21] & N1 & EM\_A[15] \\ +GP[22] & E2 & EM\_A[16] \\ +GP[23] & G1 & EM\_A[17] \\ +GP[24] & G2 & EM\_A[18] \\ +GP[25] & G4 & EM\_A[19] \\ +GP[26] & J3 & EM\_A[20] \\ +GP[27] & P12 & LCD\_D[11], I2S2\_DX, SPI\_TX \\ +GP[28] & N12 & LCD\_D[12], I2S3\_CLK, UART\_RTS \\ +GP[29] & P13 & LCD\_D[13], I2S3\_FS, UART\_RTS \\ +GP[30] & N13 & LCD\_D[14], I2S3\_RX, UART\_RXD \\ +GP[31] & P14 & LCD\_D[15], I2S3\_DX, UART\_TXD \\ + \hline + \end{tabular} +\end{table} + +Почему возможно подключение нескольких источников к одному входу? каждый вывод подключен через регистр и триггер шмитта, поэтому мы можем осуществлять как аналоговый так и цифровой вывод. аналогично ввод мультиплексируется и подтягивается либо к напряжению питания, либо к земле. Есть коммутатор, позволяющий забирать данные с разных интерфейсов МП. Возможно, отключив стандартную схему контроля использовать вывод как аналоговый (12-04). + +Регистр выбора шин находится в адресном пространстве ввода-вывода. +EBSR (1C00h) – External Bus Selection Register (регистр выбора внешних шин) +(12-06) + +С помощью этого регистра можем регулировать назначение выводов МП. + +PPMODE – Parallel Port Mode (режим параллельного порта, 21 вывод): +\begin{itemize} +\item 000 – LCD[21 вывод]; +\item 001 – SPI[7 выводов], GPIO[29:27, 20:18], UART[4 вывода] и I2S2 [4 вывода]; +\item 010 – LCD[13 выводов] и GPIO[31:27, 20:18]; +\item 011 – LCD[13 выводов], SPI [4 вывода] и I2S3 [4 вывода]; +\item 100 – LCD[13 выводов], I2S2 [4 вывода] и UART [4 вывода]; +\item 101 – LCD[13 выводов], SPI[4 вывода] и UART[4 вывода]; +\item 110 – SPI[7 выводов], I2S2[4 вывода], I2S3[4 вывода] и GPIO[29:27, 20:18]; +\item 111 – зарезервировано) +\end{itemize} + +SP1MODE – Serial Port 1 Mode (режим последовательного порта 1, 6 выводов: +\begin{itemize} +\item 00 – MMC/SD1[6 выводов]; +\item 01 – I2S1[4 вывода] and GPIO[11:10]; +\item 10 – GPIO[11:6]; +\item 11 – зарезервировано) +\end{itemize} + +SP0MODE – Serial Port 0 Mode (режим последовательного порта 1, 6 выводов: +\begin{itemize} +\item 00 – MMC/SD0[6 выводов]; +\item 01 – I2S0[4 вывода], GPIO[5:4]; +\item 10 – GPIO[5:0]; +\item 11 – зарезервировано) +\end{itemize} + +Ax\_MODE – Аx Mode (режим адресных выводов A[20:15]: +\begin{itemize} +\item 0 – интерфейс расширенной памяти, +\item 1 – входы-выходы общего назначения GPIO[26:21]) +\end{itemize} + +Подтягивающие регистры +При использовании I2S нельзя работать без подтягивающих регистров, поскольку это выводы с открытым коллектором. Входы могут быть подключены к резисторам, подтягивающим к питанию или земле. Это можно использовать для линий прерываний. Для управления используются соответствующие регистры, в которые необходимо выставить управляющие биты. + +(12-07) + +• PU – Pull-Up (подтягивание к питанию) +• PD – Pull-Down (подтягивание к земле) +• S – Serial port (выводы последовательных портов) +• INTx – Interrupt x (выводы прерывания микропроцессора) • RESET – Reset (вывод сброса микропроцессора) +• EMU01 – Emulator (выводы 0 и 1 прерывания эмулятора) • TDI – Test data input (JTAG, вывод входных данных) +• TMS – Test mode select (JTAG, вывод выбора режима) +• TCK – Test clock (JTAG, вывод тактового сигнала) +• A – Address (адресные выводы EMIF) + +Регистры входов-выходов. Если мы настроили регистры на использование ГПИО, то можно этими входами-выходами управлять вспомогательными регистрами + +\begin{table}[h!] + \centering + \begin{tabular}{||r|c|p{10cm}||} + \hline +Адрес в памяти & Обозначение & Описание \\ +1C06h & IODIR1 & Регистр направления 1 (0 – ввод данных, 1 – вывод данных) \\ +1C07h & IODIR2 & Регистр направления 2 (0 – ввод данных, 1 – вывод данных) \\ +1C08h & IOINDATA1 & Регистр входных данных 1 (0 – вход “0”, 1 – вход “1”) \\ +1C09h & IOINDATA2 & Регистр входных данных 2 (0 – вход “0”, 1 – вход “1”) \\ +1C0Ah & IODATAOUT1 & Регистр выходных данных 1 (0 – выход “0”, 1 – выход “1”) \\ +1C0Bh & IODATAOUT2 & Регистр выходных данных 2 (0 – выход “0”, 1 – выход “1”) \\ +1C0Ch & IOINTEDG1 & Регистр полярности прерываний 1 (0 – передний фронт, 1 – задний) \\ +1C0Dh & IOINTEDG2 & Регистр полярности прерываний 2 (0 – передний фронт, 1 – задний) \\ +1C0Eh & IOINTEN1 & Регистр разрешения прерываний 1 (0 – запрещено, 1 – разрешено) \\ +1C0Fh & IOINTEN2 & Регистр разрешения прерываний 2 (0 – запрещено, 1 – разрешено) \\ +1C10h & IOINTFLG1 & Регистр флагов прерываний 1 (0 – нет события, 1 – событие есть) \\ + 1C11h & 7IOINTFLG2 &Регистр флагов прерываний 2 (0 – нет события, 1 – событие есть) \\ + \hline + \end{tabular} +\end{table} + +• IO – Input-Output (входы-выходы) +• DIR – Direction (направление) +• IN, OUT – Input, Output (вход, выход) +• INT – Interrupt (прерывание) 15 0 • EDG – Edge (фронт) REG1 +• EN – Enable (разрешение) 15 0 +• FLG – Flag (флаг) + +Вектор прерываний +\begin{table}[h!] + \centering + \begin{tabular}{|c|c|c|c||} + \hline +Вектор &прерывание &приоритет &адрес\\ +00 RESET &сброса и инициализации &00& IVPD:00h\\ +04 TINT &агрегирование таймера &06& IVPD:20h\\ +08 DMA& Прямого доступа к памяти &11& IVPD:40h\\ +13 SAR& Агрегированное АЦП &18& IVPD:68h\\ +18 RTC& Часов реального времени &12& IVPH:90h\\ +21 GPIO& Портов ввода-вывода &20& IVPH:A8h\\ + \hline + \end{tabular} +\end{table} + +(12-09) +IFR1 +00 0046h + +IER1 +00 0045h + +пример программы (12-12,13,14) + +\subsection{Приборный интерфейс (13)} +I2C – Inter-Integrated Circuit (межмикросхемный интерфейс) Master – ведущее устройство +Slave – ведомое устройство +SDA – Serial Data (последовательные данные) +SCL – Serial Clock (последовательные тактовые сигналы) GND – Ground (общий проводник) +Vcc – Voltage Common Collector (напряжение питания) + +Без программирования I2C не получится запустить никакие периферийные устройства, поскольку интерфейс является связующим звеном между микросхемами. + +(13-04). На физическом уровне есть два подтягивающих к питанию резистора управляющих ног SDA и SCL. Применяется для управления любыми периферийными устройствами. любое из устройств может управлять линией данных. Если два устройства установили низкий уровень, то мы не поймём, какое именно. + +(13-05,06) Интерфейс может находиться в 4 состояниях +\begin{enumerate} +\item пассивное, когда управляющие на высоком уровне +\item переход к получению данных (падение СДА в низкий уровень). все на шине видят, что появился мастер. +\item смена данных (тактовый сигнал в низком уровне) +\item передача данных +\item смена данных (снова низкий уровень тактового сигнала) +\item отпустить клок (выставиться на высоком уровне) и выставить СДА на высокий, переход в пассивное состояние. +\end{enumerate} +Подтверждение получения данных - получатель отправляет подтверждение, отправив СДА в низкий уровень. при получении подтверждения ведущий или ведомый отправляет данные, в зависимости от режима (читать хочет мастер или писать). + +(13-07) для синхронизации быстрых и медленных устройств ведомый удерживает своим клоком быстрые клоки ведущего. Устройство, удерживающее низкий уровень тактового сигнала в линии, перекрывает такое удержание от всех других устройств. Если ведомое устройство удерживает низкий уровень тактового сигнала, остальные устройства переходят в состояние ожидания. Медленные ведомые устройства притормаживают быстрые ведущие устройства на время удержания тактового сигнала, достаточное для приема и сохранения данных (подготовки и передачи данных). + +(13-08) два разных мастера могут захотеть отправлять данные. возникает необходимость арбитража. Устройство, передающее данные с меньшим значением имеет больший приоритет на интерфейсе. Если несколько устройств передают похожие данные, то арбитраж наступает тогда, когда данные становятся различными. То есть кто передал не тоже самое, что находится на линии отключается от линии и потеря арбитража. + +(13-09) Существует несколько протоколов I2C +\begin{itemize} +\item формат 7-битной адресации +\item формат 10-битной адресации: для адреса передаются 2 байта, но для совместимости с 7-битным в 7-битной зарезервированы (11110ХХ) значит что адресация 10-битная +\item свободный формат: используется когда один ведущий и один ведомый, всегда можем передавать только данные. +\item формат повторения: захватываем линию, передаём данные, получаем подтверждение, снова передаём старт, а не стоп и продолжаем пока не надоест +\end{itemize} + +Режимы работы: +- ведомый приемник (slave-receiver mode); +- ведомый передатчик (slave-transmitter mode); +- ведущий приемник (master-receiver mode); +- ведущий передатчик (master-transmitter mode). + +(13-10) контроллер встроен в микропроцессор, поэтому связан с остальным процессором и внутренней шиной данных. у контроллера всегда есть своя тактовая частота и прескалер чтобы формировать синхросигнал тактов. арбитр определяет арбитраж. учитывая, что интерфейс последовательный, имеется сдвиговый регистр, регистр передатчика и приёмника. приёмник и передатчик работают идентично, кто именно будет работать определяет арбитр. + +(13-11) в нормальном состоянии все устройства всегда отключены. Для включения контроллера необходимо осуществить формирование тактового питания контроллера. То есть записать в 6й бит регистра PCGCR1 (1C02h) – Peripheral Clock Gating Configuration Register 1. Это сформирует разрешение использование внешнего или внутреннего тактового сигнала. +\[ f_{SCL} = \frac{f_{ICPSC}}{(N_{ICCLKH} + d)(N_{ICCLKL} + d)}, d \in \{7,6,5\} \] + +Прескалер отличается от делителя тем, что не важно какая частота на входе, можно делением или умножением получить любую другую. Далее регистр делителя формирует интерфейсную. + +Вектор прерываний по счёту 23 Контроллера I2C приоритет 24 IVPH:B8h (8 байт команды перехода и 4 байта команды NOP). + +Для управления существует много регистров +\begin{table}[h!] + \centering + \begin{tabular}{|c|c|c|} + \hline +Адрес & Обозначение &Описание\\ + \hline +1A00h & ICOAR & Own Address Register (регистр собственных адресов)\\ + \hline +1A04h & ICIMR & Interrupt Mask Register (регистр маски прерываний )\\ + \hline +1A08h & ICSTR & Interrupt Status Register (регистр статуса прерываний )\\ + \hline +1A0Сh & ICCLKL& Clock Low-Time Divider Register (регистр делителя частоты )\\ + \hline +1A10h & ICCLKH& Clock High-Time Divider Register (регистр делителя частоты )\\ + \hline +1A14h & ICCNT & Data Count (счетчик данных)\\ + \hline +1A18h & ICDRR & Data Receive Register (регистр принятых данных )\\ + \hline +1A1Ch & ICSAR & Slave Address Register (регистр подчиненного адреса )\\ + \hline +1A20h & ICDXR & Data Transmit Register (регистр передаваемых данных )\\ + \hline +1A24h & ICMDR & Mode Register(регистр режима )\\ + \hline +1A28h & ICIVR & Interrupt Vector Register (регистр вектора прерываний )\\ + \hline +1A2Ch & ICEMDR& Extended Mode Register (регистр расширенного режима )\\ + \hline +1A30h & ICPSC & Prescaler Register (регистр прескалера )\\ + \hline +1A34h & ICPID1& Peripheral Identification Register 1 (регистр идентификации 1)\\ + \hline +1A38h & CPID2 & Peripheral Identification Register 2 (регистр идентификации 2)\\ + \hline + \end{tabular} + \caption{Регистры $I^2C$} + \label{table:regs-i2c} +\end{table} + +(13-14) Регистры адреса и масок +(13-15) Регистр статуса +(13-16) Регистры приема-передачи +(13-17) Регистр режима +(13-19) Другие регистры +(13-20) Регистры идентификации, Аппаратурный сброс (используется вместе с тактовым питанием, то есть нужно дополнительно управлять Запись нуля не имеет эффекта, запись единицы запускает сброс, чтение единицы сигнализирует о состоянии сброса, чтение нуля сигнализирует об окончание сброса) + +\subsection{Межмикросхемный звуковой интерфейс $I^2S$ (14)} +(02) +I2S – Integrated Inter-chip Sound (интегрированный межмикросхемный звук) +SPDIF – Sony-Philips Digital Interface +AES/EBU – Audio Engineering Society/European Broadcasting Union + +аналоговые преобразуются при помощи АЦП. есть цифровые коаксиальные и оптические интерфейсы. Отдельно существует цифровой $I^2S$. Полученные цифровые данные могут быть переданы другим потребителям или выведены на внешние разъёмы. + +(03) Устройства по $I^2S$ подключаются похожим на SPI образом, но есть два тактовых сигнала (битовой и словной синхронизации). Словная синхронизация позволяет синхронизировать каналы стерео. + +(04) в составе микропроцессора имеется 4 $I^2S$. значит мы можем передавать 8 звуковых каналов звука в двух направлениях. Процессор имеет доступ к регистрам контроллеров и соответствующим контроллерам прерываний. + +(05) при подключении всегда выделяется ведущий и ведомые. ведущий выдаёт сигналы словной и битовой синхронизации. Можно организовать как передачу данных от ведущего ведомому, так и наоборот. Также можно организовать двусторонний обмен данными или два подчинённых могут быть соединены мастером. Работает как SPI, при передаче такта передаётся один бит данных. словная синхронизация меняет значения канала (низкий уровень для левого канала и высокий уровень для правого). + +(06) как и для $I^2C$ есть несколько форматов передачи данных. Так в формате DSP словная синхронизация передаётся импульсами и между импульсами передаётся и правый и левый канал, что позволяет передавать сразу 32-разрядные слова. + +(07) контроллер устроен как $I^2C$. Для приёма и передачи данных существуют независимые сигналы, приходящие на синхронизатор. Если принимаем - мы ведомое устройство. Для формирования тактирования есть тактовый генератор, задающий не только такты, но и коэффициент пересчёта. Делители можно задавать. Тактовый генератор формирует события контроллера. Данные через сдвиговый регистр и буфер попадают на схему расширения поля знака для передачи данных в формате с фиксированной запятой. Для отдачи данных есть аналогичная (ответная) схема сужения знака, и как только сдвиговый регистр освободится, данные передаются в усилители (передатчик). + +(08) Тактовое питание +\[ f_{I2S\_CLK} = \frac{f_{SYSCLK}}{2^{CLKDIV+1}}\] + +\[ f_{I2S\_FS} = \frac{f_{I2S\_CLK}}{2^{FSDIV+1}}\] + +Чтобы начать работать нужно разрешить тактирование. Всегда делим тактовую частоту процессора, других источников не будет. + +(09)Регистры расположены в адресном пространстве ввода-вывода. Базовые адреса: I2S0 – 2800h; I2S1 – 2900h; I2S2 – 2A00h; I2S3 – 2B00h. + +\begin{table}[H] + \centering + \begin{tabular}{|r|c|c|} + \hline +Адрес & Обозначение & Описание \\ +2800h & I2SSCTRL & Serializer Control Register (регистр управления) \\ +2804h & I2SSRATE & Sample Rate Generator Register (регистр скорости выборки) \\ +2808h & I2STXLT0 & Transmit Left Data 0 Register (регистр передачи левый 0) \\ +280Сh & I2STXLT1 & Transmit Left Data 1 Register (регистр передачи левый 1) \\ +2810h & I2STXRT0 & Transmit Right Data 0 Register (регистр передачи правый 0) \\ +2814h & I2STXRT1 & Transmit Right Data 1 Register (регистр передачи правый 1) \\ +2818h & I2SINTFL & Interrupt Flag Register (регистр флагов прерываний) \\ +281Ch & I2SINTMASK & Interrupt Mask Register (регистр маски прерываний) \\ +2820h & I2SRXLT0 & Receive Left Data 0 Register (регистр приема левый 0) \\ +2824h & I2SRXLT1 & Receive Left Data 1 Register (регистр приема левый 1) \\ +2828h & I2SRXRT0 & Receive Right Data 0 Register (регистр приема правый 0) \\ + 282Ch & 2SRXRT1 & Receive Right Data 1 Register (регистр приема правый 1)\\ + \hline + \end{tabular} + \caption{Регистры $I^2S$ на примере 0-го контроллера} +\end{table} + +PRCR (1C05h) – Peripheral Reset Control Register (регистр управления сбросом периферийных устройств) +PG4\_RST: LCD, I2S2, I2S3, UART, SPI. +PG3\_RST: MMC/SD0, MMC/SD1, I2S0, I2S1. + +Запись нуля без эффекта, запись 1 запускает сброс, чтение 1 сигнализирует о состоянии сброса, чтение 0 – окончание сброса. + +(10) Поскольку устройства работают асинхронно, существует вектор прерываний. +\begin{table}[H] + \centering + \begin{tabular}{|r|c|c|c|} + \hline +Вектор& Прерывание& Приоритет& Адрес\\ +00 RESET& Сброса и инициализации &00 &IVPD:00h \\ +01 NMI& Внутреннее немаскируемое &01 &IVPD:08h \\ +02 INT0& Внешнее по входу INT0 &03 &IVPD:10h \\ +03 INT1& Внешнее по входу INT1 &05 &IVPD:18h \\ +04 TINT& Агрегированное таймера &06 &IVPD:20h \\ +05 PROG0& I2S0, MMC/SD0 передачи &07 &IVPD:28h \\ +07 PROG1& I2S0,MMC/SD0 приема &10 &IVPD:38h \\ +08 DMA& Прямого доступа к памяти &11 &IVPD:40h \\ +09 PROG2& I2S1,MMC/SD1 передачи &13 &IVPD:48h \\ +11 PROG3& I2S1,MMC/SD1 приема &15 &IVPD:58h \\ +13 SAR& Агрегированное АЦП &18 &IVPD:68h \\ +14 XTM2& I2S2 передачи &21 &IVPD:70h \\ +15 RCV2& I2S2 приема &22 &IVPD:78h \\ +16 XMT3& I2S3 передачи &04 &IVPH:80h \\ +17 RCV3& I2S3 приема &09 &IVPH:88h \\ +18 RTC& Часов реального времени &12 &IVPH:90h \\ +21 GPIO& Портов ввода-вывода& 20 &IVPH:A8h \\ +23 I2C& Контроллера I2C& 24 &IVPH:B8h \\ + \hline + \end{tabular} + \caption{Регистры $I^2S$ на примере 0-го контроллера} +\end{table} + +(11) Регистр управления + +I2SSCTRL (2800h) – I2Sx Serializer Control Register (регистр управления) + +\begin{itemize} +\item ENABLE – Enable (разрешение работы контроллера) +\item MONO – Mono (режим моно) +\item LOOPBACK – Loopback (режим обратной петли) +\item FSPOL – Frame-synchronization polarity (полярность кадровой синхронизации I2S\_FS: 0 – высокий уровень, 1 – низкий уровень). Без дополнительной информации мы не можем знать, перепутаны ли каналы. +\item CLKPOL – Сlock polarity (полярность битовой синхронизации I2S\_CLK: 0 – переход от 0 к 1, 1 –переход от 1 к 0) +\item DATADLY – Data delay (задержка данных: 0 – 1 бит, 1 – 2 бита) +\item PACK – Pack (упаковка данных: 0 – запрещена, 1 – разрешена) +\item SIGN\_EXT – Sign extension (расширение знака) +\item WDLNGTH – Word length(длина слова: 0 – 8 бит, 1 – 10 бит, 2 – 12 бит, 3 – 14 бит, 4 – 16 бит, 5 – 18 бит, 6 – 20 бит, 7 – 24 бита, 8 – 32 бита) +\item MODE – Mode (режим: 1 – ведущий, master; 0 – ведомый, slave) +\item FRMT – Format (формат: 0 – I2S, 1 – DSP) +\end{itemize} + +(12) Упаковка данных. При уменьшении разрядности чисел с фиксированной запятой всегда усекается младшая часть, то есть при работе контроллера всегда пишутся только существенные данные. + +(13) Регистры делителей и данных +I2SSRATE (2804h) – I2Sn Sample Rate Generator Register (регистр делителей) + +\begin{itemize} +\item [] I2STXLT0 (2808h) – I2Sx Transmit Left Data 0 Register (регистр передачи левый 0) +\item [] I2STXLT1 (280Сh) – I2Sx Transmit Left Data 1 Register (регистр передачи левый 1) +\item [] I2STXRT0 (2810h) – I2Sx Transmit Right Data 0 Register (регистр передачи правый 0) +\item [] I2STXRT1 (2814h) – I2Sx Transmit Right Data 1 Register (регистр передачи правый 1) +\item [] I2SRXLT0 (2820h) – I2Sx Receive Left Data 0 Register (регистр передачи левый 0) +\item [] I2SRXLT1 (2824h) – I2Sx Receive Left Data 1 Register (регистр передачи левый 1) +\item [] I2SRXRT0 (2828h) – I2Sx Receive Right Data 0 Register (регистр передачи правый 0) +\item [] I2SRXRT1 (282Ch) – I2Sx Receive Right Data 1 Register (регистр передачи правый1) +\end{itemize} + +\begin{itemize} +\item FSDIV – Frame-synchronization divider (делитель кадровой синхронизации: 0 – 8, 1 – 16, 2 – 32, 3 – 64, 4 – 128, 5 – 256) +\item CLKDIV – Clock divider (делитель битовой синхронизации: 0 – 2, 1 – 4, 2 – 8, 3 – 16, 4 – 32, 5 – 64, 6 – 128, 7 – 256) +\item DATA – Data (данные) +\end{itemize} + +(14) Регистры прерываний +I2SINTFL (2818h) – I2Sx Interrupt Flag Register (регистр флагов прерываний) +I2SINTMASK (281Сh) – I2Sx Interrupt Mask Register (регистр масок прерываний) + +\begin{itemize} +\item XMITSTFL – Stereo data transmit (флаг или маска прерывания по готовности стерео передатчика) +\item XMITMONFL – Mono data transmit (флаг или маска прерывания по готовности моно передатчика) +\item RCVSTFL – Stereo data receive (флаг или маска прерывания по готовности стерео приемника) +\item RCVMONFL – Mono data receive (флаг или маска прерывания по готовности моно приемника) +\item FERRFL – Frame-synchronization error (флаг или маска прерывания по ошибки кадровой синхронизации) +\item OUERRFL – Overrun or Underrun condition (флаг или маска прерывания по передержке или недодержке) +\end{itemize} + +(15) Инициализация контроллера +\begin{enumerate} +\item Сброс PRCR[PGx\_RST] и ожидание нуля. +\item Подача тактового питания PCGCR1[I2SxCG]=0. +\item Сброс канала прямого доступа*. +\item Запрет прерываний и очистка флагов I2Sx. +\item Инициализация канала прямого доступа*. +\item Конфигурирование внешнего устройства I2S. +\item Разрешение прерываний. +\item Конфигурирование контроллера I2S: + \begin{itemize} + \item трассировка сигналов I2S на внешние входы; + \item если I2S ведущее устройство, то задать тактовую частоту в I2SSRATE; + \item разрешить прерывания в I2SINTMASK; + \item сконфигурировать I2SSCTRL. + \end{itemize} +\item Обработка прерываний контроллера и канала + \begin{itemize} + \item Чтение I2SINTFL для сброса флагов прерываний. + \item Чтение или запись данных в регистры данных I2S, если не используется канал прямого доступа. + \item Возврат из прерывания. + \end{itemize} +\item Завершение ввода-вывода + \begin{itemize} + \item Запрет прерываний и очистка флагов I2Sx. + \item Останов канала прямого доступа*. + \item Снятие тактового питания PCGCR1[I2SxCG]=0. + \end{itemize} +\end{enumerate} + +(17) Функции $I^2S$ + +\begin{lstlisting}[language=C,style=CCodeStyle] + port_write(0x2A08, 0x5678); // I2STXLT0 + port_write(0x2A0C, 0x1234); // I2STXLT1 + port_write(0x2A10, 0x5678); // I2STXRT0 + port_write(0x2A14, 0x1234); // I2STXRT1 + + void i2s2_init(void) { + int tmp = 0x04 < < 2; // WORD 16 + tmp |= 0x0082; // Master, Pack + port_write(0x2A00, tmp); // 16 bit + tmp = port_read(0x2A00); // I2SSCTRL + tmp = 0x2 < < 3; // FS 32; + tmp |= 0x0005; // Clock = CPU / 4 + port_write(0x2A04, tmp); // I2SSRATE + _port_write: port_write(0x2A1C, 0x20);// I2SINTMASK + } +\end{lstlisting} + +\begin{lstlisting}[style=ASMStyle] + .text + .global _port_read + .global _port_write + + ; int port_read(int reg) + _port_read: + MOV T0,AR0 + MOV port(*AR0), T0 + ret + + ; void port_write(int reg, int data) + MOV T0,AR0 + MOV T1, port(*AR0) + ret +\end{lstlisting} + +(18) Определения $I^2S$ +(19) Инициализация +(20) Секция прерываний +(21) Обработчик прерываний $I^2S$ + + +\subsection{Аудиокодек (15)} +Кодек TLV320AIC3204 +\begin{itemize} +\item Питание внутреннее (внешнее): + \begin{itemize} + \item аналоговое 1,5–1,95 В (1,1–3,6 В); + \item цифровое 1,26–1,95 В (1,8–3,6 В); + \item тактовое 8–192 кГц (512 кГц–50MГц). + \end{itemize} +\item Входы-выходы: + \begin{itemize} + \item вход стерео и моно микрофона; + \item выход стереонаушников; + \item линейный стерео выход. + \end{itemize} +\item Функции: + \begin{itemize} + \item стерео АЦП, от 8 до 192 кГц; + \item стерео ЦАП , от 8 до 192 кГц; + \item программируемое смещение и усиление; + \item 6 простых и 3 дифференциальных входа. + \end{itemize} +\end{itemize} + +(5) +Питание кодека включается сигналом \code{LDO_SELECT}. +(6) +тактируется и ресетится микропроцессором. подключается к процессору по $I^2S$ для сигналов и $I^2C$ для управления. +(7) +Кодек подключается к интерфейсу $I^2S_2$. + +(8) Обработка сигналов +И вход и выход заканчиваются звуковым интерфейсом (всё оцифровывается). Почти на каждом этапе приёма или передачи звука есть цифровое регулирование. + +(9) +(10) +(11) + +(14) +(15) +(16) + +(17) Инициализация кодека +\begin{lstlisting}[language=C,style=CCodeStyle] +uint16 aic3204_start( uint16* tab, uint16 len) { + // Локальные данные + uint16 dat; + uint8 reg, cmd; + // Цикл по элементам таблицы + while( --len > 0 ) { + // Чтение текущего элемента + dat = *tab++; + // Распаковка текущего элемента + reg = dat >> 8, cmd = dat & 0xFF; + // Интерпретация данных + if( reg == 0xFF ) + // Ожидание + ret &= C5515_wait( cmd*10 ); + else + // Запись в регистр кодека + ret &= AIC3204_set( reg, cmd); + } + return ret; +} +\end{lstlisting} + +(18) +(19) +(20) +Чтение-запись отсчетов +\begin{lstlisting}[language=C,style=CCodeStyle] +uint16 AIC3204_read( int16* left_input, int16* right_input) { + int16 dummy; + // Ожидание готовности приемника + while(!(I2S2.INTFL & INTFL_RCVR)); // Чтение отсчета левого канала + *left_input = I2S2.RXLT0; + dummy = I2S2.RXLT1; + // Чтение отсчета правого канала + *right_input = I2S2.RXRT0; + dummy = I2S2.RXRT1; +} + +void AIC3204_write( int16 left_output, int16 right_output) { + // Ожидание готовности передатчика + while(!(I2S2.INTFL & INTFL_XMITR)); // Запись отсчета в левый канал + I2S2.TXLT0 = left_output; + I2S2.TXLT1 = 0; + // Запись отсчета в правый канал + I2S2.TXRT0 = right_output; I2S2.TXRT1 = 0; +} +\end{lstlisting} + +\section{Стандартная библиотека (16)} +\begin{itemize} +\item \textbf{CSL} - Chip Support Library (библиотека поддержки) [P01] содержит функции + \begin{itemize} + \item синхронизации (\code{csl_ppl.h}), + \item питания (\code{csl_pwr.h}), + \item канала прямого доступа к памяти (\code{csl_dma.h}), + \item прерывания (\code{csl_irq.h}), + \item аналого-цифрового преобразователя (\code{csl_adc.h}), + \item входов-выходов общего назначения (\code{csl_gpio.h}), + \item интерфейса $I^2C$ (\code{csl_i2c.h}), + \item ... + \end{itemize} +\item \textbf{DSPLIB} (\code{dsplib.h}, \code{55xdspx.lib}) [P02, D09] содержит функции + \begin{itemize} + \item свертки, + \item корреляции, + \item КИХ- и БИХ-фильтрации, + \item адаптивной фильтрации, + \item быстрого преобразования Фурье, + \item математические функции, + \item матричные функции, + \item вспомогательные функции. + \end{itemize} +\item \textbf{IMGLIB} (\code{imglib.h}, \code{55ximage.lib}) содежржит функции + \begin{itemize} + \item компрессии и декомпрессии, + \item анализа изображений, + \item фильтрации изображений, + \item преобразования форматов. + \end{itemize} +\end{itemize} + +\subsection{Библиотека обработки сигналов} +используется для цифровой обработки сигналов (см. \hRf{pic:SignalProcessing}). В общем, все преобразования повторяют \hRf{subsect:methods}. + +В библиотеке присутствуют функции для +\begin{itemize} +\item Быстрое преобразование Фурье (FFT) + (25) +\item Фильтрация нерекурсивная (FIR) представлена функциями + \begin{itemize} + \item FIR direct form +\begin{verbatim} +ushort fir (DATA *x, DATA *h, + DATA *r, DATA *dbuffer, + ushort nx, ushort nh) +\end{verbatim} + \item FIR direct form (DUAL−MAC) +\begin{verbatim} +ushort fir2 (DATA *x, DATA *h, + DATA *r, DATA *dbuffer, + ushort nx, ushort nh) +\end{verbatim} + \item Symmetric FIR direct form +\begin{verbatim} +ushort firs (DATA *x, DATA *h, + DATA *r, DATA *dbuffer, + ushort nx, ushort nh2) +\end{verbatim} + \item Complex FIR direct form +\begin{verbatim} +ushort cfir (DATA *x, DATA *h, + DATA *r, DATA *dbuffer, + ushort nx, ushort nh) +\end{verbatim} + \item Фильтр с передискретизацией Decimating FIR filter +\begin{verbatim} +ushort firdec (DATA *x, DATA *h, + DATA *r, DATA *dbuffer, + ushort nh, ushort nx, ushort D) +\end{verbatim} + \item Фильтр с передискретизацией Interpolating FIR filter +\begin{verbatim} +ushort firinterp (DATA *x, DATA *h, + DATA *r, DATA *dbuffer, + ushort nh, ushort nx, ushort I) +\end{verbatim} + \item КИХ Гильберта FIR Hilbert Transformer (преобразование Гильберта, нужно передавать коэффициенты, просчитанные заранее) +\begin{verbatim} +ushort hilb16 (DATA *x, DATA *h, + DATA *r, DATA *dbuffer, + ushort nx, ushort nh) +\end{verbatim} + \item Решётчатый КИХ фильтр Lattice forward FIR filter (решетчатый фильтр) +\begin{verbatim} +ushort firlat (DATA *x, DATA *g, + DATA *r, DATA *pbuffer, + int nx, int nh) +\end{verbatim} + \end{itemize} +\item Фильтрация рекурсивная (IIR) представлена функциями + \begin{itemize} + \item IIR cascade direct 4-biquad form 2 +\begin{verbatim} +ushort iircas4 (DATA *x, DATA *h, + DATA *r, DATA *dbuffer, + ushort nbiq, ushort nx) +\end{verbatim} + \item IIR cascade direct 5-biquad form 2 +\begin{verbatim} +ushort iircas5 (DATA *x, DATA *h, + DATA *r, DATA *dbuffer, + ushort nbiq, ushort nx) +\end{verbatim} +\item IIR cascade direct 5-biquad form 1 +\begin{verbatim} +ushort iircas51 (DATA *x, DATA *h, + DATA *r, DATA *dbuffer, + ushort nbiq, ushort nx) +\end{verbatim} +\item Double-precision IIR filter +\begin{verbatim} +ushort iir32 (DATA *x, LDATA *h, + DATA *r, LDATA *dbuffer, + ushort nbiq, ushort nr) +\end{verbatim} +\item Решётчатый БИХ фильтр Lattice inverse IIR filter +\begin{verbatim} +ushort iirlat (DATA *x, DATA *h, + DATA *r, DATA *pbuffer, + int nx, int nh) +\end{verbatim} + \end{itemize} +\item Фильтрация адаптивная (DLMS) + \begin{itemize} + \item LMS FIR (delayed version) +\begin{verbatim} +ushort dlms (DATA *x, DATA *h, + DATA *r, DATA *des, + DATA *dbuffer, DATA step, + ushort nh, ushort nx) +\end{verbatim} +\item Adaptive delayed LMS filter (fast implemented) (LMS – Least Mean Square, минимальная среднеквадратическая ошибка) +\begin{verbatim} +ushort dlmsfast (DATA *x, DATA *h, + DATA *r, DATA *des, + DATA *dbuffer, DATA step, + ushort nh, ushort nx) +\end{verbatim} + \end{itemize} +\item Свертка (convolution) + \begin{itemize} + \item Convolution +\begin{verbatim} +ushort convol (DATA *x, DATA *h, + DATA *r, ushort nr, ushort nh) +\end{verbatim} +\item Convolution (DUAL−MAC) +\begin{verbatim} +ushort convol1 (DATA *x, DATA *h, + DATA *r, ushort nr, ushort nh) +\end{verbatim} +\item Convolution (DUAL−MAC) +\begin{verbatim} +ushort convol2 (DATA *x, DATA *h, + DATA *r, ushort nr, ushort nh) +\end{verbatim} + \end{itemize} +\item Корреляция (CORR) + \begin{itemize} + \item Autocorrelation +\begin{verbatim} +ushort acorr (DATA *x, DATA *r, + ushort nx, ushort nr, type) +\end{verbatim} +\item Correlation +\begin{verbatim} +ushort corr (DATA *x, DATA *y, + DATA *r, ushort nx, + ushort ny, type) +\end{verbatim} + \end{itemize} +\item Тригонометрические функции (SINE, ...) + (28) +\item Векторные функции (SQRT, SUB, DIV, ...) + (29-31) +\item Матричные функции (MUL, TRANS, ...) + (32) +\item Вспомогательные функции (RAND, ...) + (27) +\end{itemize} + +\begin{table}[h!] + \centering + \begin{tabular}{||p{80mm}|p{80mm}||} + \hline + БИХ & КИХ \\ [0.5ex] + \hline\hline + Более эффективны & Менее эффективны \\ + Есть аналоговый эквивалент & Нет аналогового эквивалента \\ + Могут быть нестабильными & Всегда стабильные \\ + Нелинейная фазовая характеристика & Линейная фазовая характеристика \\ + Больше «звон» при наличии ложных сигналов & Меньше звон при наличии ложных сигналов \\ + Доступны средства САПР & Доступны средства САПР \\ + Децимация не влияет на эффективность & Децимация увеличивает эффективность \\ + \hline + \end{tabular} + \caption{Сравнение фильтров} +\end{table} + +\subsection{Биквадратный фильтр} +(12) + +\subsection{Решётчатый фильтр} +(13) Исторически были первые (сверху один элемент - это бих, снизу один элемент - это ких). аналог фильтра с обратной связью +\begin{itemize} +\item КИХ + \[ K(z) = \frac{1}{G(z)}\] +\item БИХ + \[ K(z) = H(z)\] +\end{itemize} +\subsection{Фильтр Гильберта} +Частный случай КИХ - фильтр Гильберта (14) +(на рисунке графике внизу формулы $h(t) = W(t) \frac{1 - \cos(\pi t)}{\pi t})$, окно Хемминга $W(t) = 1 - A + \frac{A\cos(2\pi t)}{(N - 1)}$) + +\subsection{Адаптивный фильтр} +(19) + +\subsection{Свёртка} +(21) +Циклическая свертка: +\begin{itemize} +\item [] $x[N + H - 1]$ – входной вектор 1; +\item [] $h[H]$ – входной вектор 2; +\item [] $y[N]$ – выходной вектор. +\end{itemize} +Вычисляется без использования буфера задержки: +\begin{itemize} +\item [] $h[i] = 0$ при $i < 0$ и $i >= H$; +\item [] $x[j] = 0$ при $j < 0$ и $j >= N + H - 1$. +\end{itemize} + +\subsection{Корреляция} +(22) + +\subsection{Согласованный фильтр} +(15) + +\subsection{Спектральная обработка} +(24) + +\subsection{Бит-реверсивная перестановка} +(26) выполняется перед БПФ + +\section{Операционная система} +DSP/BIOS (Digital Signal Processing Base Instrumentation Operation System) – операционная система реального времени, предоставляющая следующие сервисы: +\begin{itemize} +\item мультизадачный планировщик задач; +\item аппаратурная абстракция устройств ввода-вывода данных; +\item независимый от устройств обмен потоками данных в реальном времени; – анализа поведения приложений и обмен данными с ними; +\item статическая конфигурация устройств ввода-вывода и приоритетов задач. +\end{itemize} +Создаёт псевдопараллельное исполнение задач системы. Программные модули DSP/BIOS: +\begin{itemize} +\item редактор конфигурирования; +\item модуль анализа реального времени; – модуль аппаратурной абстракции; +\item модуль ввода-вывода; +\item модуль управления потоками; – модуль синхронизации потоков. +\end{itemize} + +\appendix +\setcounter{secnumdepth}{0} +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Alph{subsection}} + +\subsection{Обозначения и сокращения} +\printnomenclature[23mm] + +\newpage +\printbibliography[heading=bibintoc, title={Список литературы}] + +\end{document} \ No newline at end of file diff --git a/02-dip-hw-01-report.tex b/02-dip-hw-01-report.tex new file mode 100644 index 0000000..92abd0c --- /dev/null +++ b/02-dip-hw-01-report.tex @@ -0,0 +1,566 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +\makeReportTitle{домашней}{№ 1}{Создание оригинального алгоритма регенерации характерных признаков}{Цифровая обработка изображений}{}{Большаков В.Э.} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Задание} +\begin{enumerate} +\item На языке Python 3.х подключить библиотеку opencv; +\item Дать пошаговое описание работы метода Лукаса-Канаде(ЛК); +\item Подготовить видеопоток с медленно движущимся объектом по горизонтали; +\item Запрограммировать отслеживание объекта с использованием ЛК метода (использовать функцию \code{cv2.calcOpticalFlowPyrLK()}); +\item Сделать перевод статьи Tracking of Moving Objects With Regeneration of Object Feature Points; +\item Подготовить второй видеопоток на основе для создания условий потери характерных точек ЛК при движении объекта; +\item Разработать и запрограммировать оригинальный алгоритм регенерации характерных признаков ЛК (по аналогии со статьей). +\item Провести эксперимент по регенерации характерных признаков ЛК с визуализацией результатов. +\item Провести эксперимент по отслеживанию объектов с визуализацией результатов (в том числе визуализацией применения характерных признаков на изображении). Сравнить надежность отслеживания с регенерацией и без нее. +\end{enumerate} +\section{Теоретическая часть} +Для обнаружения объектов на видео используется несколько методов: Ши-Томаси (поиск опорных точек) и Лукаса-Канаде (слежение за опорными точками в оптическом потоке). +\subsection{Метод поиска опорных точек Ши-Томаси} +Основная идея заключается в том, что углы могут быть обнаружены путем поиска значительных изменений во всех направлениях. Сначала рассматривается небольшое окно на изображении, затем сканируем всё изображение в поисках углов. Смещение окна в любом направлении приведет к значительному изменению внешнего вида, если это конкретное окно окажется над углом. То есть если мы замечаем, что есть область, в которой происходят значительные изменения, независимо от того, в каком направлении производится сканирование, то есть высокая вероятность, что в этом месте находится угол. Метод Ши-Томаси основан на методе детектирования углов Харриса (подробнее в подразделе \hrf{appendix:harris}) заключается в поиске соседних областей со значительным изменением интенсивности расматриваемого параметра (например, яркости). Метод производит оценку изображения и выставляет коэффициенты изменения областям. Выставление корректного порога оценки является ключевым фактором в правильном определении. Метод Ши-Томаси принципиально отличается только формулой оценки (подробнее в подразделе \hrf{appendix:shi-tomasi}) выбирающей не разницу произведения и суммы $\lambda_1$ и $\lambda_2$, а минимум из этих двух значений. +\subsection{Метод Лукаса-Канаде} +Оптический поток - это изображение видимого движения объектов, получаемое в результате перемещения объекта относительно наблюдателя. Выборочный поток - поток, который учитывает сдвиг отдельных заданных точек (например, некоторых характерных точек, предварительно найденных одним из алгоритмов детектирования таких точек). Алгоритм Лукаса-Канаде использует выборочный поток на первом кадре и после оценивает их расположение на последующем кадре. Алгоритм использует следующие данные: + +\begin{itemize} +\item Два кадра, следующие друг за другом (кадры полученные видео); +\item Массив начального набора характеристических точек; +\item Массив результирующих точек; +\item Массив который показывает статус поиска каждой точки; +\item Массив погрешностей для каждой операции поиска; +\item Размер окна по которому производится гауссово усреднение; +\item Дополнительные флаги, которые можно использовать для установки начального приближения потока или выбрать метод оценки погрешности, а также пороговое значение градиента. +\end{itemize} + +Важное допущения, для использования метода Лукаса-Канаде: +\begin{itemize} +\item Значения пикселей переходят из одного кадра в следующий кадр без изменений. Таким образом, мы делаем допущение, что пиксели, относящиеся к одному и тому же объекту, могут сместиться в какую-либо сторону, но их значение останется неизменным; +\item В алгоритме используется только производная первого порядка для аппроксимации функции движения выборочного потока +\end{itemize} + +\subsection{Регенерация точек} +Мы можем попытаться регенерировать точки после препятствия, потому что предполагаем что точки продолжат движение с вероятностью, которую можно найти, как максимум функции правдоподобия. То есть, из всего пространства возможных элементарных перемещений точек мы выбираем те, при которых функция правдоподобия достигает своего максимума. Функция правдоподобия зависит от значений положения опорных точек до препятствия и после (можно сказать, что это априорное положение опорной точки и апостериорное). Так как явный вид такой функции неизвестен, мы предполагаем что функция плотности вероятности является нормальной случайной величиной и, по этой причине, с вероятностью $\pm34.13\%$ опорная точка продолжит движение со среднеквадратичным отклонением скорости, численно равным средней скорости всех опорных точек до препятствия +\section{Практическая часть} +Входящими в алгоритм данными является видеофайл (поток из видеокадров) содержащий статический фон (камера не двигается), некоторое препятствие (неподвижный объект, находящийся между камерой и отслеживаемым объектом) и достаточно медленно перемещающийся объект. Результат работы алгоритма - это наложенные поверх видео отметки о характерных точках движущегося объекта. С точки зрения реализации, работа по распознаванию характерных точек в видеокадрах разделена на четыре основные части: +\begin{enumerate} +\item преобразование изображения в градации серого производится стандартной функцией библиотеки \code{OpenCV}. + \begin{lstlisting}[language=Python,style=PyCodeStyle] + # ... + prevGrayscale = cv2.cvtColor(prevFrame, cv2.COLOR_BGR2GRAY) + # ... + frameGrayscale = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) + # ... + \end{lstlisting} + В результате работы функции алгоритмы будут далее использовать изображения как, например, на рис. \hrf{pic:first}. +\begin{figure}[H] + \centering + \includegraphics[width=14cm]{01-dip-hw-first.png} + \caption{Первый кадр изображения} + \label{pic:first} +\end{figure} + +\item поиск характерных точек методом Ши-Томаси, + \begin{lstlisting}[language=Python,style=PyCodeStyle] + # ... + p0 = cv2.goodFeaturesToTrack(prevGrayscale, mask=mask_rect, **shiTomasiParameters) + # ... + \end{lstlisting} + Характерные точки ищутся внутри выделенной области (рис. \hrf{pic:bounding-box}). Внутрь функции передаются параметры, представленные в листинге \hrf{src:shi-tomasi-param}. + \begin{lstlisting}[language=Python,style=PyCodeStyle,label={src:shi-tomasi-param}] + # ... + shiTomasiParameters = dict(maxCorners=1000, + qualityLevel=0.3, + minDistance=5) + # ... + \end{lstlisting} + где + \begin{itemize} + \item [] \code{maxCorners} - количество углов (точек), которые мы хотим найти; + \item [] \code{qualityLevel} - значение порога, ниже которого углы будут отклонены; + \item [] \code{minDistance} - расстояние, на котором будут отброшены все менее качественные углы. + \end{itemize} +\begin{figure}[H] + \centering + \includegraphics[width=14cm]{01-dip-hw-manual.png} + \caption{Определение окна объекта} + \label{pic:bounding-box} +\end{figure} + +\item отслеживание характерных точек методом Лукаса–Канаде (рис. \hrf{pic:tracking}) - производится встроенной функцией из библиотеки OpenCV, также на монохромном изображении. Функция принимает на вход предыдущий и текущий кадр, а также параметры, представленные в листинге + + \begin{lstlisting}[language=Python,style=PyCodeStyle,label={src:lucas-kanade-param}] +lucasKanadeParameters = dict(winSize=(10, 10), + maxLevel=2, + criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)) +# ... +p1, st, err = cv2.calcOpticalFlowPyrLK(prevGrayscale, frameGrayscale, p0, None, **lucasKanadeParameters) + \end{lstlisting} + где + \begin{itemize} + \item [] \code{winSize} - размеры окна поиска; + \item [] \code{maxLevel} - количество уровней пирамиды поиска; + \item [] \code{criteria} - критерии окончания поиска итеративным алгоритмом. + \end{itemize} + + и для вызова функции + \begin{itemize} + \item [] \code{prevGrayscale} - предыдущий кадр в градациях серого; + \item [] \code{frameGrayscale} - текущий кадр в градациях серого; + \item [] \code{p0} - набор из найденных на предыдущем кадре точек; + \item [] \code{p1} - набор из найденных (отслеженных) на текущем кадре точек; + \item [] \code{st} - вектор статуса точек (1 точка отслежена и подтверждена, 0 точка потеряна). + \end{itemize} + +\begin{figure}[H] + \centering + \includegraphics[width=14cm]{01-dip-hw-frame-before.png} + \caption{Отслеживание характерных точек} + \label{pic:tracking} +\end{figure} +\item попытка регенерации потерянных из-за наличия препятствия характерных точек по методу Лычкова-Алфимцева-Сакулина. По условию задачи объект двигается горизонтально, его скорость невелика, как и любой иной объект он имеет свойство сохранять своё движение и за препятствием (когда опорные точки явно пропадают из вида), тогда мы можем предположить, что точки продолжат двигаться с некоторой скоростью, которую они имели до попадания объекта за препятствие, так называемая средняя скорость в физике. Применяя это понятие производим суммирование по всем точкам объекта и вычисляем среднюю скорость до попадания за препятствие, делим на количество таких точек, получим среднюю скорость, далее, когда объект окажется за препятствием - добавляем к тем точкам которые прекратили своё движение в горизонтальном направлении (упёрлись в препятствие) эту среднюю скорость, как добавочную, и считаем что они продолжают движение с этой скоростью. Далее как только объект вновь покажется после препятствия, метод Лукаса-Канаде снова найдёт опорные точки в потоке и продолжит следовать за ними (рис \hrf{pic:regeneration}). То есть, делаем экстраполяцию (прогноз) движения опорных точек. Код, осуществляющий такое вычисление представлен в листинге \hrf{src:regeneration}. + + \begin{figure}[H] + \includegraphics[width=14cm]{01-dip-hw-frame-after.png} + \caption{Регенерация характерных точек} + \label{pic:regeneration} + \end{figure} + + \begin{lstlisting}[language=Python,style=PyCodeStyle,label={src:regeneration}] +goodPoints = 0 +badPoints = 0 +badPointArray = [] + +k = 0.1 +meanXVelocity = 0.0 +xVelocity = 0.0 +for i in range(len(pointsInFrame)): + if abs(pointsInFrame[i][0] - pointsInPrevFrame[i][0]) <= k: + badPointArray.append(i) + badPoints += 1 + else: + goodPoints += 1 + xVelocity += abs(pointsInPrevFrame[i][0] - pointsInFrame[i][0]) +if goodPoints != 0: + meanXVelocity = xVelocity / goodPoints +for i in badPointArray: + pointsInFrame[i][0] += meanXVelocity + \end{lstlisting} + +\end{enumerate} + +\section{Заключение и выводы} +В результате выполнения работы были изучены базовые методы цифровой обработки изображений и отслеживания объектов в видеопотоке. Объект был зафиксирован и отслеживался на протяжении всего пути, несмотря на препятствие. При проходе объекта за препятствием без применения регенерации все точки были потеряны, в то время как регенерация позволила сохранить большую их часть. Для увеличения числа сохранённых точек возможно описать более надёжный алгоритм регенерации с учётом направления движения характерной точки и добавления некоторой дельты скоростей (на случай изменения скорости движения объекта, пока он находится вне зоны видимости). +\newpage +\appendix +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Asbuk{subsection}} + +\subsection{Полный листинг программы} +\begin{lstlisting}[language=Python,style=PyCodeStyle] +import numpy as np +import cv2 +from matplotlib import pyplot as plt + + +def mainScript(videoName): + cap = cv2.VideoCapture(videoName) + shiTomasiParameters = dict(maxCorners=1000, + qualityLevel=0.3, + minDistance=7) + + lucasKanadeParameters = dict(winSize=(10, 10), + maxLevel=2, + criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)) + + plt.figure(figsize=(10, 10)) + ret, prevFrame = cap.read() + plt.imshow(prevFrame) + plt.show() + + prevGrayscale = cv2.cvtColor(prevFrame, cv2.COLOR_BGR2GRAY) + mask_rect = [[0] * int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))] * int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + mask_rect = np.asarray(mask_rect) + mask_rect = mask_rect.astype(np.uint8) + x0 = 0 + y0 = 450 + dx = 130 + dy = 130 + mask_rect[y0:y0 + dy, x0:x0 + dx] = 255 + p0 = cv2.goodFeaturesToTrack(prevGrayscale, mask=mask_rect, **shiTomasiParameters) + p0_cor = np.int0(p0) + + plt.figure(figsize=(10, 10)) + cv2.rectangle(prevFrame, (x0, y0), (x0 + dx, y0 + dy), 255, 2) + for i in p0_cor: + x, y = i.ravel() + cv2.circle(prevFrame, (x, y), 1, 255, -1) + plt.imshow(prevFrame) + plt.show() + + mask = np.zeros_like(prevFrame) + color = np.random.randint(0, 255, (100, 3)) + + while True: + ret, frame = cap.read() + if not ret: + break + frameGrayscale = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) + p1, st, err = cv2.calcOpticalFlowPyrLK(prevGrayscale, frameGrayscale, p0, None, **lucasKanadeParameters) + + # Select good points + pointsInFrame = p1[st == 1] + pointsInPrevFrame = p0[st == 1] + +# Regeneration + goodPoints = 0 + badPoints = 0 + badPointArray = [] + + k = 0.1 + meanXVelocity = 0.0 + xVelocity = 0.0 + for i in range(len(pointsInFrame)): + if abs(pointsInFrame[i][0] - pointsInPrevFrame[i][0]) <= k: + badPointArray.append(i) + badPoints += 1 + else: + goodPoints += 1 + xVelocity += abs(pointsInPrevFrame[i][0] - pointsInFrame[i][0]) + if goodPoints != 0: + meanXVelocity = xVelocity / goodPoints + for i in badPointArray: + pointsInFrame[i][0] += meanXVelocity +# End Regeneration + + # draw the tracks + for i, (new, old) in enumerate(zip(pointsInFrame, pointsInPrevFrame)): + a, b = new.ravel() + c, d = old.ravel() + mask = cv2.line(mask, (int(a), int(b)), (int(c), int(d)), color[i].tolist(), 2) + frame = cv2.circle(frame, (int(a), int(b)), 1, color[i].tolist(), -1) + img = cv2.add(frame, mask) + + cv2.imshow('frame', img) + k = cv2.waitKey(30) & 0xff + if k == 27: + break + + # Now update the previous frame and previous points + prevGrayscale = frameGrayscale.copy() + p0 = pointsInFrame.reshape(-1, 1, 2) + + cv2.destroyAllWindows() + cap.release() + + +if __name__ == '__main__': + mainScript('IMG_9680.MOV') +\end{lstlisting} + + +\subsection{Детектирование углов Харриса} \label{appendix:harris} +\href{https://docs.opencv.org/4.x/dc/d0d/tutorial_py_features_harris.html}{OpenCV: Документация} + +\begin{multicols}{2} + Углы — это области изображения с большим разбросом интенсивности во всех направлениях. Одна из первых попыток найти углы в цифровом изображении была предпринята Крисом Харрисом и Майком Стивенсом в их статье «Комбинированный детектор углов и краев» в 1988 году, поэтому теперь она называется детектором углов Харриса. Он описал эту идею в математической форме. В основном, он находит разницу в интенсивности для смещения $(u, v)$ во всех направлениях. Это выражается следующим образом: + + \begin{equation*} + \begin{gathered} +E(u,v)= \\ =\sum_{x,y} w(x,y) [I(x+u,y+v) − I(x,y)]^2 + \end{gathered} + \end{equation*} + + где $w(x,y)$ - это оконная функция, $I(x+u,y+v)$ - смещённая интенсивность, $I(x,y)$ - интенсивность. Оконная функция представляет собой либо прямоугольное окно, либо окно Гаусса, которое дает вес пикселям под ним. + +Мы должны максимизировать функцию $E(u,v)$ для обнаружения углов. Это означает, что мы должны максимизировать второй член. Применяя разложение в ряд Тейлора к приведенному выше уравнению и используя некоторые математические шаги, мы получаем окончательное уравнение вида: + \begin{equation*} +E(u,v)\approx [u,v] M \begin{bmatrix} u\\v \end{bmatrix} + \end{equation*} + где + \begin{equation*} + M = \sum_{x,y} w(x,y) \begin{bmatrix} + I_xI_x & I_xI_y\\ + I_xI_y & I_yI_y + \end{bmatrix} + \end{equation*} + +Здесь $I_x$ и $I_y$ — производные изображения в направлениях $x$ и $y$ соответственно. (Их можно найти с помощью функции \code{cv.Sobel()}). + +Затем идет основная часть. Предварительные действия создали оценочную функцию, то есть, фактически, уравнение, которое определяет, может ли окно содержать угол или нет. + \begin{equation*} +R = det(M) - k(trace(M))^2 + \end{equation*} +где + +\begin{itemize} +\item [] $det(M) = \lambda_1\lambda_2$ +\item [] $trace(М) = \lambda_1 + \lambda_2$ +\item [] $\lambda_1$ и $\lambda_2$ — собственные значения оператора M +\end{itemize} +Таким образом, величины этих собственных значений определяют, является ли область углом, краем или плоскостью. + +\begin{itemize} +\item Когда $|R|$ мал, что бывает при малых $\lambda_1$ и $\lambda_2$, область плоская. +\item При $R < 0$, что бывает при $\lambda_1 \gg \lambda_2$ или наоборот, область является краевой. +\item Когда $R$ велико, что происходит, когда $\lambda_1$ и $\lambda_2$ велики и $\lambda_1 \sim \lambda_2$, область представляет собой угол. +\end{itemize} + +Таким образом, результатом Harris Corner Detection является изображение в градациях серого с оценками. Указание корректных пороговых значений для таких оценок даёт углы изображения. +\end{multicols} + +\subsection{Детектирование углов Ши-Томаси} \label{appendix:shi-tomasi} +\href{https://docs.opencv.org/3.4/d4/d8c/tutorial_py_shi_tomasi.html}{OpenCV: Документация} +\begin{multicols}{2} +В 1994, J. Shi и C. Tomasi немного изменили метод Харриса, что было отражено в их работе «Good Features to Track» которая показыват лучшие результаты, чем детектор углов Харриса. Оценочная функция в детекторе углов Харриса дана как: + + \begin{equation*} +R = \lambda_1\lambda_2 - k(\lambda_1+\lambda_2)^2 + \end{equation*} + +Вместо этого, Ши-Томаси предложили: + \begin{equation*} +R = \min(\lambda_1, \lambda_2) + \end{equation*} + +Если значение больше порогового, область считается углом. +\end{multicols} + +\subsection{Метод вычисления Лукаса-Канаде} \label{appendix:lucas-kanade} +\href{http://cecas.clemson.edu/~stb/klt/lucas_bruce_d_1981_1.pdf}{Оригинальная статья} + +\href{https://en.wikipedia.org/wiki/Lucas–Kanade_method}{Wikipedia} +\begin{multicols}{2} +В компьютерном зрении метод Лукаса-Канаде является широко используемым дифференциальным методом для оценки оптического потока. Он предполагает, что поток практически постоянный в локальной окрестности рассматриваемого пикселя, и решает основные уравнения оптического потока для всех пикселей в этой окрестности по критерию наименьших квадратов. Комбинируя информацию от нескольких соседних пикселей, метод Лукаса-Канаде часто может разрешить присущую обработке оптического потока неоднозначность. Он также менее чувствителен к шуму изображения, чем точечные методы. С другой стороны, поскольку это чисто локальный метод, он не может предоставить информацию о потоках внутри однородных областей изображения. + +Метод Лукаса–Канаде предполагает, что смещение содержимого изображения между двумя близкими моментами (кадрами) мал\'{о} и примерно постоянно в окрестности рассматриваемой точки $p$. Таким образом, можно предположить, что уравнение оптического потока выполняется для всех пикселей в пределах окна с центром в точке $p$. А именно, локальный вектор потока изображения (скорости) $(V_x, V_y)$ должен удовлетворять +\begin{equation*} + \begin{gathered} +I_{x}(q_{1})V_{x}+I_{y}(q_{1})V_{y}=-I_{t}(q_{1})\\ +I_{x}(q_{2})V_{x}+I_{y}(q_{2})V_{y}=-I_{t}(q_{2})\\ +\vdots \\ +I_{x}(q_{n})V_{x}+I_{y}(q_{n})V_{y}=-I_{t}(q_{n})\\ + \end{gathered} +\end{equation*} +где + +$q_1, q_2, ..., q_n$ — это пиксели внутри окна, а +$I_{x}(q_{i}), I_{y}(q_{i}), I_{t}(q_{i})$ — частные производные изображения $I$ относительно положения $х, у$ и времени $t$, оценённые в точке $q_{i}$ и в настоящее время. + +Эти уравнения можно записать в матричной форме $A_v = b$, где +\begin{equation*} + \begin{gathered} + A= + \begin{bmatrix} + I_{x}(q_{1}) & I_{y}(q_{1}) \\ + I_{x}(q_{2}) & I_{y}(q_{2}) \\ + \vdots & \vdots \\ + I_{x}(q_{n}) & I_{y}(q_{n}) + \end{bmatrix} + v= + \begin{bmatrix} + V_x \\ V_y + \end{bmatrix} \\ + b = + \begin{bmatrix} + -I_{t}(q_{1}) \\ + -I_{t}(q_{2}) \\ + \vdots \\ + -I_{t}(q_{n}) + \end{bmatrix} + \end{gathered} +\end{equation*} + + +В этой системе больше уравнений, чем неизвестных, и поэтому она обычно переопределена, то есть, метод Лукаса–Канаде позволяет получить компромиссное решение по принципу наименьших квадратов. А именно, решает +$2 \times 2$ систему: +\begin{equation*} + \begin{gathered} +A^{T}Av=A^{T}b \text{или}\\ +v = (A^{T}A)^{-1}A^{T}b + \end{gathered} +\end{equation*} + +где +$A^{T}$ - транспонированная матрица $A$. То есть он вычисляет +\begin{equation*} + \begin{gathered} + \begin{bmatrix} + V_x \\ V_y + \end{bmatrix} = + \begin{bmatrix} + \sum_i^nI_x(q_i)^2 & \sum_i^n I_x(q_i)I_y(q_i)\\ + \sum_i^nI_y(q_i)I_x(q_i) & \sum_i^n I_y(q_i)^2 + \end{bmatrix}^{-1}\\ + \begin{bmatrix} + \sum_i^n I_x(q_i)I_t(q_i)\\ + \sum_i^n I_y(q_i)I_t(q_i) + \end{bmatrix} + \end{gathered} +\end{equation*} + +где центральная матрица в уравнении является обратной матрицей. Матрицу $A^TA$ часто называют структурным тензором изображения в точке $p$. + +Приведенное выше решение методом наименьших квадратов придает одинаковую важность всем $n$ пикселям $q_{i}$ в окне. На практике обычно лучше придавать больший вес пикселям, расположенным ближе к центральному пикселю $p$. Для этого используется взвешенная версия уравнения наименьших квадратов, +\[А^{Т}WАv = А^{Т}Wb\] + +или же +\[v = (A ^ {T} WA) ^ {- 1} A^{T} Wb\] + +где $W$ — диагональная матрица $n\times n$, содержащая веса $W_{ii}=w_{i}$, которые должны быть присвоены уравнению пикселя $q_{i}$. То есть вычисляет +\begin{equation*} + \begin{gathered} + \begin{bmatrix} + V_x \\ V_y + \end{bmatrix} = \\ + \begin{bmatrix} + \sum_iw_iI_x(q_i)^2 & \sum_i w_iI_x(q_i)I_y(q_i)\\ + \sum_iw_iI_x(q_i)I_y(q_i) & \sum_i w_iI_y(q_i)^2 + \end{bmatrix}^{-1}\\ + \begin{bmatrix} + \sum_i w_iI_x(q_i)I_t(q_i)\\ + \sum_i w_iI_y(q_i)I_t(q_i) + \end{bmatrix} + \end{gathered} +\end{equation*} + + +Вес $w_{i}$ обычно устанавливается как функция Гаусса от расстояния между $q_{i}$ и $p$. + +\paragraph{Условия использования и методы} +Чтобы уравнение $A^{T}Av=A^{T}b$ было разрешимо, $A^{T}A$ должно быть обратимым, или собственные значения $A^{T}A$ должны удовлетворять $\lambda _{1} \geq \lambda _{2} > 0$. Чтобы избежать проблем с шумом, обычно требуется, чтобы $\lambda_{2}$ не было слишком маленьким. Кроме того, если $\lambda_{1}/\lambda_{2}$ слишком велико, это означает, что точка $p$ находится на ребре, и этот метод страдает от проблемы с апертурой. Таким образом, для правильной работы этого метода необходимо, чтобы $\lambda_{1} и \lambda_{2}$ были достаточно большими и имели одинаковую магнитуду. Это условие также относится к обнаружению углов. Это наблюдение показывает, что можно легко определить, какой пиксель подходит для работы метода Лукаса-Канаде, проверив одно изображение. + +Одним из основных предположений для этого метода является то, что движение небольшое (например, менее 1 пикселя между двумя изображениями). Если движение велико, один из методов состоит в том, чтобы сначала уменьшить разрешение изображений, а затем применить метод Лукаса-Канаде. Чтобы добиться отслеживания движения с помощью этого метода, его можно итеративно применять к вектору потока и пересчитывать до тех пор, пока не будет достигнут некоторый порог, близкий к нулю, после чего можно предположить, что окна изображения очень близки по подобию (движутся достаточно медленно). Делая это для каждого последовательного окна отслеживания, точка может отслеживаться на нескольких изображениях, пока она либо не будет скрыта, либо не выйдет за пределы кадра. +\end{multicols} + +\subsection{Отслеживание движущихся объектов с регенерацией характерных точек объекта} \label{appendix:alfimtsev-lychkov} +\begin{multicols}{2} +\textbf{Аннотация. Эта статья посвящена отслеживанию движущихся объектов в видео, основанному на технике разреженного оптического потока. Текущие оптические методы отслеживания потока страдают от потери характерных точек. Мы расширили существующий метод отслеживания разреженного оптического потока с помощью новой функции автоматического восстановления характерных точек, использующей принцип биологической регенерации. Кроме того, мы улучшили метод отслеживания для работы с преобразованиями вращения и масштабирования объекта. Мы применили улучшенный метод отслеживания к реальному видео и заметили приемлемую производительность отслеживания. Наш эксперимент показал, что предложенный метод слежения с восстановлением характерных точек обеспечивает более высокую точность отслеживания, чем оригинальный метод отслеживания без восстановления характерных точек когда движущийся объект частично закрыт препятствием. +Ключевые слова - отслеживание движущихся объектов, видеопоток, перекрытие объекта, обнаружение характерных точек, биологическая регенерация.} + +\paragraph{1. Введение} +Автоматическое отслеживание движущихся объектов на видео — важная задача, возникающая в таких областях, как безопасность, оборона, робототехника и др. Она заключается в вычислении положения движущегося объекта в последовательности видеокадров по заданному его положению в первом видеокадре последовательности. Автоматическое отслеживание движущихся объектов — сложная задача для видео с окклюзией (перекрытием) объектов и плохим освещением. + +\paragraph{2. Обзор литературы} +Можно выделить пять основных подходов к отслеживанию движущихся объектов: отслеживание блобов, отслеживание на основе контуров, отслеживание оптического потока, отслеживание на основе моделей и отслеживание нейронной сети. Отслеживание блоба использует методы вычитания фона и не подходит для видео, записанных движущейся камерой. Отслеживание нейронной сети требует больших обучающих наборов данных, которые можно найти только для определенных категорий объектов и только для обычных видео. Трудно подготовить большие обучающие наборы данных для видеороликов, производимых инфракрасными камерами или электронными оптическими преобразователями приборов ночного видения. Отслеживание на основе контуров, отслеживание на основе 3D-моделей и отслеживание плотного оптического потока требуют больших вычислительных мощностей, поэтому эти методы не подходят для приложений реального времени. В этой работе мы улучшаем существующий метод отслеживания разреженного оптического потока, основанный на оптическом потоке Лукаса-Канаде, который устраняет необходимость обучения и подходит для приложений в реальном времени. + +\paragraph{3. Постановка задачи} +Отслеживание разреженного оптического потока заключается в обнаружении характерных точек в видеокадре и последующем отслеживании обнаруженных характерных точек в серии видеокадров. Из-за несовершенства алгоритмов отслеживания некоторые характерные точки могут быть потеряны. Первоначально в контуре движущегося объекта можно обнаружить несколько характерных точек. Значительная часть пятна изображения вокруг такой характерной точки приходится на фон. Во время отслеживания, эта характерная точка может покинуть область объекта и войти в область фона, что вносит неопределенность в отслеживание движущегося объекта. Кроме того, непрозрачные препятствия могут скрывать некоторые части движущегося объекта и затруднять его правильное отслеживание. Для повышения точности слежения предлагается метод автоматического восстановления потерянных характерных точек путем обнаружения новых характерных точек в пределах области объекта. Основная идея метода восстановления основана на использовании принципов биологической регенерации. + +\paragraph{4. Восстановление характерных точек, основанное на биологической регенерации} +Регенерация – это особая способность биологического организма восстанавливать утраченные части своего тела. Рассмотрим три известных принципа биологической регенерации: эпиморфоз, моральфаллакс и эндоморфоз. Эпиморфоз заключается в редукции тканей тела, прилежащих к повреждённой поверхности, разрастании клеток и их последующей дифференцировке. Моральфалакс во многом похож на эпиморфоз, за ​​исключением того, что остальные клетки организма подлежат перестройке. Эндоморфоз заключается в восстановлении поврежденной массы органа за счет деления и гипертрофии клеток. + +Вышеупомянутые принципы регенерации могут быть адаптированы для восстановления потерянных характерных точек в задаче отслеживания объектов следующим образом. Эпиморфозы сохраняют исходные геометрические параметры движущихся объектов. Основным критерием для присвоения характерной точки движущемуся объекту является расстояние от этой характерной точки до ближайшего центра объекта. Основная идея моральфаллакса во многом похожа на эпиморфоз, за ​​исключением того, что осуществляется дальнейшая оптимизация, чтобы уменьшить количество плохо отслеживаемых характерных точек. Эндоморфоз учитывает количество характерных точек, которые в настоящее время отслеживаются в ограничивающей рамке объекта. + +В данной работе мы предлагаем использовать эпиморфоз в качестве базового принципа восстановления характерных точек. Пользователь задает порог количества отслеживаемых характерных точек в качестве входного параметра метода. Характерные точки изображения отслеживаются в каждом видеокадре с использованием разреженного оптического потока Лукаса-Канаде, а ограничивающие рамки объектов вычисляются с помощью метода отслеживания движущихся объектов, представленного в следующем разделе. Когда количество характерных точек в ограничивающей рамке объекта уменьшится ниже заданного пользователем порога, новые характерные точки будут обнаружены следующим образом. Сначала мы применяем детектор характерных точек Ши-Томаси для обнаружения новых характерных точек в ограничивающей рамке объекта. Во-вторых, мы отбрасываем характерные точки, расположенные на расстоянии менее 5 пикселей от исходных характерных точек объекта, которые в настоящее время отслеживаются. Наконец, мы выбираем необходимое количество характерных точек, которые находятся ближе всего к центру ограничивающей рамки объекта в текущем видеокадре. + +\paragraph{5. Метод отслеживания объекта в видео} +Главная проблема отслеживания характерных точек на основе разреженного оптического потока состоит в миграции отдельных характерных точек из области изображения движущегося объекта в область фонового изображения, что вносит ошибки в результаты отслеживания. Чтобы добиться надежного отслеживания движущихся объектов, нам необходимо различать и отбрасывать потерянные характерные точки. Метод слежения за движущимися объектами на основе сети относительного движения позволяет сопоставлять наблюдаемые положения объектов в текущем видеокадре с траекториями объектов в последовательности видеокадров по их относительным смещениям. Для составления оптимального совпадения используется принцип максимального правдоподобия. Оригинальный метод слежения предполагает, что отдельный объект представлен одной характерной точкой в ​​видеокадре, имеет дело только с поступательным движением и не учитывает вращение и масштабирование изображения объекта в кадре во время его движения. В этой работе мы предлагаем модификацию исходного метода отслеживания для работы с вращением и масштабированием объекта. + +Входящие данные метода включают набор кадров $Z_t = \{z_t^k\}$ полученный с использованием техники оптического потока, где $t$ это индекс видеокадра, $k$ - индекс характерной точки, $z_t^k = [z_{ut}^k, z_{vt}^k]$ - вектор обзора с координатами $z_{ut}^k$ и $z_{vt}^k$. +Текущее состояние отслеживаемых движущихся объектов представлено набором состояний $X_t = \{(x_t^i, h_t^i)\}$, где $t$ - индекс видеокадра, $i$ - индекс движущегося объекта ($i = 0$ означает фон), $x_t^i = [x_{ut}^i, x_{vt}^i]$ - вектор центров $i$-ых объектов внутри $t$-ого видеокадра, $h_t^i = [h_{ut}^i, h_{vt}^i]$ представляет размер границ распознанного $i$-го объекта. +Для расчёта положения центра объекта и относительного положения различных характерных точек мы составляем относительную модель движения $R_t = \{ (m_j^i, n_j^i), \pi_i \}$, где $(m_j^i,n_j^i), j = 1 : 2N$ это список индексов соответствующих пар характерных точек для $i$-го объекта, $\pi_i$ обозначает индексы основной соответствующей пары характерных точек $(m_{πi}^i, n_{πi}^i)$ которая используется для отслеживания $i$-го объекта на $t$-ом видеокадре. Для начального видеокадра $t = 0$ список индексов объединяется с использованием случайной выборки $2N$ пар характерных точек из общего набора обнаруженных характерных точек. +Затем мы сопоставляем характерные точки с движущимися объектами и находим основные опорные характерные точки объектов по принципу максимального правдоподобия: + +\begin{equation} + \begin{gathered} + p(Z_t|X_t,R_{t-1}) = \\ = \max\limits_{A, \pi}\prod_{i,k} p(z_t^k|x_t^i,R_{t-1}^\pi)^{a^{i,k}} + \end{gathered} + \label{eq:likehood} +\end{equation} + +где $R_{t-1}$ это модель относительного движения для предыдущего видеокадра, $R_{t-1}^\pi$ это модель относительного движения с измененными индексами пар основных опорных точек всех объектов, $A = \{a^{i,k}\}$ и $a^{i,k} \in \{0, 1\}$ представляют совпадающие соответствия точек признаков объектам, $p(z_t^k|x_t^i,R_{t-1}^\pi)$ функция частичного совпадения. + +Чтобы упростить проблему оптимизации возможно применить функцию логарифма к правой части (\hrf{eq:likehood}): +\begin{equation} + \begin{gathered} + p(Z_t|X_t,R_{t-1}) \sim \\ \sim \max\limits_{A, \pi}\prod_{i,k} a^{i,k} \ln p(z_t^k|x_t^i,R_{t-1}^\pi) + \end{gathered} + \label{eq:likehood-ln} +\end{equation} + +Модель относительного движения настраивается следующим образом. Решение задачи оптимизации (\hrf{eq:likehood-ln}) дает оптимальные значения элементов матрицы $A$. Можно выбрать пару лучших опорных точек модели $R_{t–1}$ при условии глобального оптимума (\hrf{eq:likehood-ln}) и $(N – 1)$ лучших опорных точек при условии локального максимума правдоподобия для $i$-го объекта: + +\begin{equation} + \begin{gathered} + \pi_{i\max} = \\ = \arg \max\limits_{A, \pi}\prod_{i,k} a^{i,k} \ln p(z_t^k|x_t^i,R_{t-1}^\pi) + \end{gathered} + \label{eq:likehood-ln-max} +\end{equation} + +Остальные $N$ пар выбираются методом случайной выборки из набора характерных точек $i$-го объекта в $t$-м видеокадре. Функция частичного правдоподобия представляется в виде + +\begin{equation} + p(z_t^k|x_t^i,R_{t-1}^\pi) = G(z_\tau^k, y_\tau^k) + \label{eq:likehood-partial} +\end{equation} + +где $G$ - это двумерный Гауссиан + +\begin{equation} + \begin{gathered} + G(v, v_0) = \\ = \exp \left\{ -\frac{1}{2}(v-v_0)^T C(v-v_0) \right\} + \end{gathered} + \label{eq:gaussian} +\end{equation} + +с ковариационной матрицей + +\begin{equation} + C=\begin{bmatrix} + \sigma_u^2 & \sigma_u\sigma_v\\ + \sigma_u\sigma_v & \sigma_u^2 + \end{bmatrix} + \label{eq:covariance-matrix} +\end{equation} + +и стандартными отклонениями для различных координат + +\begin{equation} + 3\sigma_u = \frac{1}{2}h_{u\tau}^i, 3\sigma_v = \frac{1}{2}h_{v\tau}^i + \label{eq:coord-deviations} +\end{equation} + +которые зависят от размера $i$-го объекта и времени $\tau$ обнаружения $k$-й характерной точки. + +$y_\tau^k = [y_{u\tau}^k, y_{v\tau}^k]^T$ в (\hrf{eq:likehood-partial}) - это прогнозируемое положение $k$-й характерной точки в $\tau$-м видеокадре, предполагая, что $k$-я характерная точка назначена $i$-му объекту, а модель относительного движения $i$-й характерной точки объекта представляет собой модель аффинного преобразования. + +Матрица аффинного преобразования $M_{ti} \in R^{2\times3}$ для $i$-го движущегося объекта определяется использованием следующей системой уравнений + +\begin{equation} + \begin{cases} + [z_{u\tau}^{p1} z_{v\tau}^{p1}]^Τ = M_{ti} \cdot [z_{u\tau}^{p1} z_{v\tau}^{p1} 1]^Τ\\ + [z_{u\tau}^{p2} z_{v\tau}^{p2}]^Τ = M_{ti} \cdot [z_{u\tau}^{p2} z_{v\tau}^{p2} 1]^Τ,\\ + [z_{u\tau}^{p3} z_{v\tau}^{p3}]^Τ = M_{ti} \cdot [z_{u\tau}^{p3} z_{v\tau}^{p3} 1]^Τ + \end{cases} + \label{eq:affine-matrix} +\end{equation} +где $p1, p2, p3$ это индексы характерных точек, присвоенных $i$-му движущемуся объекту. + +Предсказанное положение $k$-й характерной точки в $\tau$-м видеокадре вычисляется с использованием матрицы аффинного преобразования $M_{ti}$. +\begin{equation} + y_{k\tau} = M_{ti} \cdot [z_{u\tau}^{k} z_{v\tau}^{k} 1]^Τ + \label{eq:affine-equation} +\end{equation} +Характерная точка, переместившаяся из области движущегося объекта в фоновую область, уйдет далеко от движущегося объекта. Её функция частичного правдоподобия (\hrf{eq:likehood-partial}) принимает б\'{о}льшие значения, если характерная точка отнесена к фону, и меньшие значения, если характерная точка отнесена к движущемуся объекту. Таким образом, оптимальное решение для (\hrf{eq:likehood-ln}) дает нам разумное соответствие точек признаков движущимся объектам или фону. + +\paragraph{6. Устройство эксперимента и результаты} +Мы записали оригинальное видео с частотой кадров 25 кадров в секунду, продолжительностью 50 секунд и разрешением 720$\times$576 пикселей, которое представляет дорожное движение на дороге. Мы использовали предложенный метод отслеживания объектов для извлечения опорных траекторий для 14 движущихся автомобилей из исходного видео. Начальные точки траектории задавались вручную. Для имитации перекрытия движущихся объектов препятствием мы нанесли на все видеокадры 4 вертикальные серые полосы (каждая полоса шириной 12 пикселей), получив модифицированное видео. Мы применили предложенный метод отслеживания объектов к модифицированному видео, таким образом, получив результирующие траектории для 14 движущихся автомобилей в модифицированном видео для двух случаев. В первом случае восстановление характерных точек не производилось, а во втором случае восстановление характерных точек осуществлялось по предложенному способу регенерации. Координатам начальной точки траектории присваивались те же значения, что и для соответствующих опорных траекторий. Затем мы сопоставили полученные траектории с эталонными траекториями и рассчитали две метрики производительности: процент успешно отслеженных объектов и отклонение слежения. Движущийся объект считался успешно отслеженным, если расстояние его положения на результирующей траектории от его положения на опорной траектории не превышает заданного максимального порога расстояния для каждого видеокадра. Порог максимального расстояния задавался вручную в процентах от размера ограничивающей рамки объекта. Процент успешно отслеженных объектов рассчитывался как количество успешно отслеженных объектов, делённый на общее количество опорных траекторий. Отклонение слежения вычислялось как среднее стандартное отклонение полученных траекторий от эталонных траекторий среди всех успешно отслеженных объектов. Количество отслеживаемых характерных точек объекта было установлено вручную равным 10. Результаты эксперимента представлены в таблице в оригинале статьи. Когда пороговое значение максимального расстояния устанавливалось равным 0,5 размера ограничивающей рамки объекта, отслеживание с восстановлением потерянных характерных точек обеспечивало меньшее отклонение отслеживания, чем отслеживание без восстановления потерянных характерных точек. Когда порог максимального расстояния устанавливался на 0,75 размера ограничивающей рамки объекта, отслеживание с восстановлением потерянных характерных точек обеспечивало более высокий процент успешно отслеженных объектов, чем отслеживание без восстановления потерянных характерных точек. + +\paragraph{7. Выводы} +В данной работе мы расширили существующий метод отслеживания движущихся объектов в видеороликах функцией автоматического восстановления потерянных характерных точек, основанной на принципе биологической регенерации. Эксперимент, проведенный на реальном видео, показал, что автоматическое восстановление потерянных характерных точек позволяет повысить точность слежения в случае перекрытия движущегося объекта неподвижным препятствием. Использование аффинной модели движения позволяет иметь дело с поворотными и масштабными преобразованиями движущегося объекта при отслеживании. +\end{multicols} +\end{document} + diff --git a/02-dip-lab-01-report.tex b/02-dip-lab-01-report.tex new file mode 100644 index 0000000..a06a00f --- /dev/null +++ b/02-dip-lab-01-report.tex @@ -0,0 +1,494 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../bmstu-preamble} +\input{../fancy-listings-preamble} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% ... работе, номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{1}{Распознавание объекта по форме}{Цифровая обработка изображений}{}{Большаков В.Э.} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель} +Основной целью лабораторной работы является изучение методов распознания объекта по форме с помощью библиотеки цифровой обработки изображений scikit-image языка Python. + +\section{Задание} +Требуется запрограммировать работу программы распознавания фрукта в зависимости от формы объекта из обучающей выборки. В таблице \hrf{table:indi-task} представлено индивидуальное задание на лабораторную работу. + +\begin{table}[ht] + \centering + \begin{tabular}{|l|c|c|c|} + \hline + № варианта & Фрукт1 & Фрукт2 & Оператор \\ [0.5ex] + \hline + 11 & Corn & Quince & Кэнни \\ [1ex] + \hline + \end{tabular} + \caption{Индивидуальное задание на разработку} + \label{table:indi-task} +\end{table} + +\section{Выполнение} +В качестве исходного материала были получены обучающая и тестовая выборки изображений двух овощей/фруктов в соответствии с вариантом. Примеры изображений приведены на рис. \hrf{pic:train-samples}. + +\begin{figure}[ht] + \centering + \begin{subfigure}[b]{0.45\textwidth} + \centering + \includegraphics[width=0.8\textwidth]{c_100.jpg} + \caption{Corn} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.45\textwidth} + \centering + \includegraphics[width=0.8\textwidth]{q_100.jpg} + \caption{Quince} + \end{subfigure} + \caption{Изображения для тренировки алгоритма} + \label{pic:train-samples} +\end{figure} + +Для работы были использованы следующие инструменты: +\begin{itemize} +\item JetBrains PyCharm CE; +\item Python 3.9; +\item scikit-image 0.19.2. +\end{itemize} + +\subsection{Теоретическая часть} +Выделение границ — термин в теории обработки изображения и компьютерного зрения, частично из области поиска объектов и выделения объектов, основывается на алгоритмах, которые выделяют точки цифрового изображения, в которых резко изменяется яркость или есть другие виды неоднородностей. Основным принципом большинства методов выделения контура является вычисление частных производных от функции яркости по координатам \cite{dip:enhancing-bitmaps}. Пример выделения границ представлен на рис \hrf{pic:canny-sample}. +\begin{figure}[ht] + \centering + \includegraphics[height=4cm]{01-canny-01.png} + \caption{Пример работы фильтра Кэнни (Canny)} + \label{pic:canny-sample} +\end{figure} + +Фильтр (алгоритм) Кэнни представляет собой многоступенчатый детектор границ. Он использует фильтр, основанный на производной Гаусса, чтобы вычислить интенсивность градиентов. Гауссиан уменьшает влияние шума, присутствующего в изображении. Затем потенциальные края прореживаются до однопиксельных кривых путем удаления немаксимальных пикселей величины градиента\footnote{non-maximum pixels of the gradient magnitude}. Наконец, краевые пиксели сохраняются или удаляются с использованием порогового значения гистерезиса\footnote{Для гистерезиса характерно явление «насыщения», а также неодинаковость траекторий между крайними состояниями} для величины градиента. + +Фильтр Кэнни имеет три регулируемых параметра: ширину гауссовой кривой (чем шумнее изображение, тем больше ширина), а также нижний и верхний пороги для гистерезисной пороговой обработки. + +Для получения итоговых измерений каждой из фигур возможно получить тензор однородного тела единичной массы, имеющего форму каждой из них и получить тензоры, описывающие основные оси (X и Y) представленного на изображении тела относительно его центра массы. + +Тензор инерции - это матричная величина, описывающая меру инертности тела, при вращательном движении, подобно тому, как масса тела является мерой его инертности при поступательном движении. Вычислим тензор однородного тела единичной массы, чтобы найти только его габариты. Изображение является плоским, поэтому у тензора будет две основные оси, а не три. Возможно представить тензор объекта в виде матрицы +\[ \widehat{J}\bar{w} = + \begin{pmatrix} + J_{xx} & J_{xy} \\ + J_{yx} & J_{yy} \\ + \end{pmatrix} + \begin{pmatrix} + W_{x} \\ + W_{y} \\ + \end{pmatrix}. +\] + +Приведя данную матрицу к диагональному виду получим +\[ + \begin{pmatrix} + J_{x} & 0 \\ + 0 & J_{y} \\ + \end{pmatrix}, +\] +где $J_{x}$ и $J_{y}$ - это моменты инерции главных осей фигур на изображениях. То есть такие измерения, которые можно будет сравнить и понять, к какому классу относится та или иная фигура (кукуруза или груша). Компоненты тензора инерции вычисляются по формуле +\begin{equation*} + J_{xx} = \sum_m y^2 \Delta m = \sum_n y^2\frac{1}{n}. +\end{equation*} +Аналогично, $J_{yy} = \sum_n x^2\frac{1}{n}$, а $J_{xy} = J_{yx} = -\sum_n xy\frac{1}{n}$. + +\subsection{Разработка программы} +Библиотека skimage предоставляет лаконичный интерфейс загрузки изображений (строка \hrf{line:img-read}) в программу, поэтому пример, представленный на официальной странице библиотеки, повторён почти полностью и представлен в приложении \hrf{appendix:file-loading}. Также в приложении запрограммирован перевод цифрового изображения в полутоновой формат, с использованием стандартной функции, на строке \hrf{line:img-to-greyscale}. + +Для написания программы тренировки и проверки наборов изображений были написаны общие функции преобразования изображений (листинг \hrf{code:tensor}), загрузки каждого файла с изображением из папки (листинг \hrf{code:folder}) и частные функции запуска тренировки и тестирования. + +\begin{lstlisting}[language=Python,style=PyCodeStyle, caption={Функции получения тензора и нахождения собственных значений}, label={code:tensor}] + def solve_matrix(A): + L = [] + D = (A[0][0] + A[1][1]) * (A[0][0] + A[1][1]) - 4 * (A[0][0] * A[1][1] - A[1][0] * A[0][1]) + L.append(((A[0][0] + A[1][1]) + sqrt(D)) / 2) + L.append(((A[0][0] + A[1][1]) - sqrt(D)) / 2) + return L + + def tensor(image): # вычисление тензора инерции по формулам + sum_x = None + sum_y = None + n = 0 + # находим среднюю точку в каждой строке изображения + for y, itemy in enumerate(image): # находим строки + for x, itemx in enumerate(itemy): # берём столбцы + sum_x = 0 + sum_y = 0 + if itemx == 1: # если пиксель белый + sum_x += x + sum_y += y + n += 1 + x_c = sum_x / n # вычисляем среднее арифметическое + y_c = sum_y / n + Jxx = 0 + Jyy = 0 + Jxy = 0 + # также попиксельно рассматриваем изображение + for y, itemy in enumerate(image): + for x, itemx in enumerate(itemy): + if itemx == 1: # если пиксель белый + Jxx += ((y - y_c) * (y - y_c))/n # находим тензор по формуле + Jyy += ((x - x_c) * (x - x_c))/n + Jxy -= ((x - x_c) * (y - y_c))/n + return [[Jxx, Jxy], [Jxy, Jyy]] + \end{lstlisting} + +\begin{lstlisting}[language=Python,style=PyCodeStyle, caption={Работа с изображениями в папке}, label={code:folder}] + def get_list_image(path): + list_image = [] + for d, dirs, files in os.walk(path): # Достаем все каталоги по пути + for f in files: # Достаем все файлы + if re.search(".jpg", f): # Сортировка по типу + path = os.path.join(d, f) # Получаем путь до изображения + picture = io.imread(path) # Загружаем изображение в формате narray + picture_gray = rgb2gray(picture) # Переводим изображений в полутон + picture_canny = feature.canny(picture_gray, sigma=3, mode='constant', cval=1) + picture_chull = convex_hull_image(picture_canny) # заливка контуров изображения + picture_chull = picture_chull.astype(np.uint8) + list_image.append((picture_chull, f)) # Добавляем полученное изображение в список + return list_image +\end{lstlisting} + +Внутри функции загрузки изображения также сразу применяются функции получения границ фильтром Кэнни и заливки полученного изображения. В соответствии с вариантом (№11) был запрограммирован оператор фильтрации Кэнни со значением $\sigma = 3$, где сигма - это порог чувствительности распознавания границ. После работы оператора выделения границ фигура была залита и вычислен тензор инерции получившегося тела. Тренировка (листинг \hrf{code:training}) производилась на наборе изображений и результаты тренировки программы были записаны в словарь, содержащий значения минимума и максимума разности между главными осями тензоров инерции. +\begin{lstlisting}[language=Python,style=PyCodeStyle, caption={Код тренировки программы}, label={code:training}] +def training(training_path, fruit): + fruit_path = os.path.join(training_path, fruit) + some_prop_arr = [] + list_image = get_list_image(fruit_path) + for image in list_image: + own_numbers = solve_matrix(tensor(image[0])) + some_prop_arr.append(abs(own_numbers[0] - own_numbers[1])) + return [min(some_prop_arr), max(some_prop_arr)] +\end{lstlisting} + +В результате обучения были получены данные, представленные на рис. \hrf{fig:train-results}. + +\begin{figure}[H] + \centering +\begin{tikzpicture} + \begin{axis}[ + xmin=0, xmax=530, ymin=0, ymax=690, + width=140mm,height=110mm, + xlabel=Изображение, + ylabel=Разность моментов инерции главных осей тела,] + \addplot [blue] coordinates { + (0, 627.4607824733928) (1, 629.2695974371966) (2, 629.9554209593027) (3, 630.268029411357) (4, 630.6295207372107) (5, 625.8339628526348) (6, 625.8964369035497) (7, 626.5979015434887) (8, 625.2306613383677) (9, 626.3775276856277) (10, 625.5107854804395) (11, 626.0106043125209) (12, 626.2790447001885) (13, 624.6416933628533) (14, 624.7076264930304) (15, 628.9294293909321) (16, 632.31798020164) (17, 628.1644353897714) (18, 629.8765461117398) (19, 626.2943583644901) (20, 628.0866902299505) (21, 629.8275781255102) (22, 628.3092960981805) (23, 630.1023612272243) (24, 628.5292523585598) (25, 626.5508191041822) (26, 622.8590799056508) (27, 629.9440538380633) (28, 632.3036707519555) (29, 624.3833706404721) (30, 627.4726707741063) (31, 629.6878364997913) (32, 630.5185348477605) (33, 630.5124812282145) (34, 636.2054380967727) (35, 634.7046427336187) (36, 633.8497417207475) (37, 636.5278834340088) (38, 633.5647680943287) (39, 635.8154523751514) (40, 636.3225349655222) (41, 626.3773602069499) (42, 640.4644159348825) (43, 640.2429954451036) (44, 642.2688682295008) (45, 636.2357221747043) (46, 634.3971664974526) (47, 641.9238940534283) (48, 641.3886134400684) (49, 643.0213260492852) (50, 641.2751718926081) (51, 639.0920937675796) (52, 624.8137537147923) (53, 632.4407802739498) (54, 634.2504737332504) (55, 635.123316950992) (56, 632.5400024530343) (57, 631.024464097855) (58, 633.272977201304) (59, 635.8882466624875) (60, 630.6793826213832) (61, 624.9122374754847) (62, 634.3047639782453) (63, 631.941137136622) (64, 632.3867375860023) (65, 627.5326898417975) (66, 625.4646494959436) (67, 623.658538055161) (68, 625.0179763139789) (69, 624.590576865256) (70, 621.6883973855956) (71, 626.6429715100707) (72, 623.9650414779394) (73, 625.3945458330404) (74, 627.9641569696935) (75, 625.1165070677858) (76, 624.7243922218458) (77, 621.8411823174158) (78, 624.8167888979496) (79, 625.8303922721636) (80, 626.9775572684015) (81, 626.9667198752054) (82, 626.4799542502055) (83, 612.0555075531094) (84, 624.4035774020192) (85, 628.2825448647161) (86, 627.5007077260182) (87, 629.9434339330244) (88, 627.4373225862212) (89, 627.3721458119073) (90, 628.031602776535) (91, 622.6824154884432) (92, 627.0096845957587) (93, 626.5661917834273) (94, 624.7495703774318) (95, 623.0111874385307) (96, 622.2817386665105) (97, 626.1873004845656) (98, 621.6711068487709) (99, 624.4232253048453) (100, 621.7135775336171) (101, 623.0069773773184) (102, 634.5139645875552) (103, 622.4447909411745) (104, 620.7712794231238) (105, 616.5278675541269) (106, 619.3745091102379) (107, 618.5704355056066) (108, 622.0954703789457) (109, 616.0835351534836) (110, 631.7721435271798) (111, 620.7251419468425) (112, 619.42788225753) (113, 616.7683377335743) (114, 617.5203098468523) (115, 624.1094773315817) (116, 615.2902027826132) (117, 609.2277619472329) (118, 618.8286002133661) (119, 621.2064945034929) (120, 626.5853861369799) (121, 621.9851478186949) (122, 625.8678173982206) (123, 631.4421405634038) (124, 630.7048751744294) (125, 631.163498676287) (126, 634.2707686327126) (127, 634.7839280940477) (128, 636.411718598489) (129, 629.8499907076861) (130, 637.530004560821) (131, 635.2424498643154) (132, 635.9948941618518) (133, 635.166180070554) (134, 634.5650851594451) (135, 636.2836647928797) (136, 634.8374148898588) (137, 636.9667104276721) (138, 637.7991427851275) (139, 626.4054897146805) (140, 634.5752477931796) (141, 636.8651866208634) (142, 637.0527448158831) (143, 628.764830749955) (144, 635.9138563520996) (145, 635.008770779174) (146, 631.6951826947329) (147, 632.5796661507305) (148, 632.4555711376579) (149, 630.6666000338996) (150, 636.2885095939138) (151, 597.3948260380142) (152, 598.5143479462397) (153, 595.2680800798375) (154, 603.0608167306659) (155, 608.898241939918) (156, 612.5974351209122) (157, 613.8606035925711) (158, 611.8131953676086) (159, 604.8415705274656) (160, 617.2142476072188) (161, 641.9704936188414) (162, 618.5909062827875) (163, 626.1712220279785) (164, 627.399386735337) (165, 630.5624572919661) (166, 631.5745439169859) (167, 639.9364042057691) (168, 634.485957895716) (169, 623.2626045944662) (170, 637.6534910791877) (171, 634.2933046959574) (172, 636.2465943828796) (173, 635.452293298622) (174, 628.7511310958678) (175, 624.0120638597828) (176, 626.3055523868802) (177, 624.49389929354) (178, 621.5026304161049) (179, 617.0870806858915) (180, 618.457415296378) (181, 618.5259340035659) (182, 608.4772033751697) (183, 643.1810004470299) (184, 603.9924173797259) (185, 585.6563239960317) (186, 585.0769199784231) (187, 586.9812846571747) (188, 590.024524605058) (189, 587.2973319053553) (190, 583.0325396001358) (191, 580.7499809452531) (192, 571.559975188427) (193, 570.0395885704654) (194, 640.157795770819) (195, 561.9186027065509) (196, 559.7236388452618) (197, 547.0547306220482) (198, 542.4005435763659) (199, 529.9106917294939) (200, 522.4616690336475) (201, 511.9077111745944) (202, 494.4214062166664) (203, 493.61731873245776) (204, 485.51103163020855) (205, 637.2016341822862) (206, 475.73662305230937) (207, 461.439991878835) (208, 437.7754509419734) (209, 639.3220989882541) (210, 632.0749403837528) (211, 512.6804354222788) (212, 527.7238900255832) (213, 534.5811371411078) (214, 538.8322981570952) (215, 634.1111943421761) (216, 548.0698872780063) (217, 544.1128105689722) (218, 561.0386251766396) (219, 570.1552058004363) (220, 566.5030456476592) (221, 580.182986907236) (222, 583.9978017750077) (223, 591.8035685530765) (224, 592.7060892453073) (225, 597.2220425692058) (226, 632.6602395129546) (227, 605.2647930969538) (228, 611.9381754525969) (229, 614.34292268576) (230, 617.5202914538409) (231, 618.2020427294984) (232, 626.9836143479155) (233, 630.3933185086603) (234, 621.1885046154008) (235, 636.8374868394667) (236, 638.8558939703888) (237, 628.4765235939697) (238, 637.5785155357084) (239, 626.0345752821752) (240, 622.5879212896031) (241, 621.7137781760473) (242, 615.7406861977315) (243, 618.2280938348612) (244, 606.6096983071818) (245, 598.5541703912621) (246, 597.7249449821309) (247, 590.6959530909917) (248, 587.3573765968556) (249, 635.4657671628529) (250, 586.193957029066) (251, 590.0908305552421) (252, 575.8120957365651) (253, 576.5003073881305) (254, 565.2861505490141) (255, 552.6706651327496) (256, 541.2223737020754) (257, 535.6160598486538) (258, 525.4946802760599) (259, 515.581145480055) (260, 643.0105187007996) (261, 497.25537027871167) (262, 488.8513004413888) (263, 478.022895669593) (264, 460.4984619003674) (265, 457.51184898828706) (266, 444.5354065220363) (267, 423.7820627651653) (268, 405.2643194308406) (269, 397.01082694684885) (270, 373.4926946842768) (271, 641.2861114712177) (272, 358.60201343108946) (273, 346.02779819908665) (274, 642.4291067261158) (275, 640.2424511487134) (276, 400.18964412344576) (277, 642.6086466984073) (278, 419.9138815920667) (279, 422.0567626362232) (280, 437.78566856899795) (281, 454.576029699148) (282, 464.94669222386534) (283, 478.3045136419138) (284, 487.53884427329643) (285, 504.637011458207) (286, 516.9376907954536) (287, 518.3894792796923) (288, 643.6888600160144) (289, 514.3449433807123) (290, 536.0656517659384) (291, 541.5504485639697) (292, 549.7547214457085) (293, 553.4141530235056) (294, 556.1351612164551) (295, 571.4997316768056) (296, 579.6846808947121) (297, 582.1842752254795) (298, 582.8480966137013) (299, 643.721007225698) (300, 627.0406991556345) (301, 622.8591739632984) (302, 620.6810307020979) (303, 628.1153923749655) (304, 629.4119146188755) (305, 629.129517400063) (306, 622.5581708750906) (307, 622.2256630677279) (308, 627.4680948145965) (309, 626.9173174162881) (310, 615.2046481991315) (311, 627.7789346785082) (312, 603.8866383503553) (313, 613.7894324488761) (314, 610.4285161304105) (315, 603.8832090986191) (316, 596.5322330276151) (317, 596.6291186481819) (318, 599.7555471780283) (319, 572.5763808773252) (320, 595.7553092620246) (321, 580.1758409264353) (322, 638.8467022064561) (323, 582.0103310023524) (324, 571.5922795804458) (325, 559.4502821386523) (326, 556.491334727631) (327, 560.9151199052551) (328, 553.6342784910386) (329, 541.9322177176982) (330, 536.0035786705271) (331, 529.1019741538394) (332, 521.2933767239965) (333, 638.4548712989115) (334, 514.0897632854546) (335, 485.8084314794869) (336, 484.46519274293445) (337, 473.8930170081343) (338, 470.8295468592221) (339, 446.88841945501684) (340, 439.8468642587586) (341, 404.2233404726147) (342, 392.05163751854957) (343, 373.10937534032115) (344, 642.5110867732162) (345, 639.5825725535549) (346, 639.192965649815) (347, 452.118927611899) (348, 463.05197653128096) (349, 638.6843535148632) (350, 477.4294939956906) (351, 487.93423913668903) (352, 496.04817819584224) (353, 506.15754666364467) (354, 518.7792258399606) (355, 518.8665317862898) (356, 535.282131787723) (357, 541.7527273080743) (358, 547.984701825902) (359, 557.6099648727584) (360, 628.2260241843555) (361, 564.7709502462928) (362, 562.5588425165715) (363, 557.8649559049734) (364, 578.8330902418381) (365, 588.9837341619195) (366, 587.3145214701094) (367, 591.9682181128353) (368, 596.53573279445) (369, 608.8474189205781) (370, 615.8434331903156) (371, 630.5877983957648) (372, 621.2154460427611) (373, 622.6636774148099) (374, 622.0745105419475) (375, 629.2654134379753) (376, 624.5496661434001) (377, 629.6163602724322) (378, 632.903191392033) (379, 640.0862908814538) (380, 642.2045697621015) (381, 643.0629589268897) (382, 624.4389040485589) (383, 626.9583545972339) (384, 627.7325960397607) (385, 622.3997236654503) (386, 619.0535500856281) (387, 617.837241140109) (388, 609.2786869285155) (389, 601.4726808481298) (390, 593.4120573797065) (391, 590.0359961740958) (392, 580.1860061708537) (393, 577.3798508451907) (394, 633.1876433006378) (395, 571.8084188551079) (396, 560.7291142288007) (397, 557.5823554376336) (398, 543.1164021301197) (399, 540.9239512255283) (400, 529.8681787375417) (401, 512.6774565720968) (402, 499.76290828067783) (403, 494.66809179453566) (404, 477.3270237814802) (405, 640.4623254878671) (406, 475.3433459168415) (407, 466.59128710462113) (408, 453.9484222173975) (409, 444.5751755517319) (410, 433.11000492632314) (411, 412.48870470840416) (412, 396.24795993252354) (413, 639.3735050291962) (414, 638.0118121371829) (415, 470.4072741863663) (416, 638.6669998698048) (417, 489.4952361254184) (418, 513.0240973470584) (419, 524.1418134920236) (420, 532.3444796209269) (421, 544.0384258695485) (422, 549.563509043936) (423, 560.8700428817081) (424, 569.8170419956485) (425, 577.3659695265553) (426, 590.3717978540308) (427, 647.416671344422) (428, 595.8612889400252) (429, 599.869758386815) (430, 605.3717134212383) (431, 608.6107807793396) (432, 610.3938171734853) (433, 621.3868902466922) (434, 622.6380412061594) (435, 625.7604248168075) (436, 630.1551651218304) (437, 632.4883511575035) (438, 643.4902377076482) (439, 636.30415580366) (440, 627.5709914139036) (441, 636.367193549462) (442, 635.0645928782321) (443, 629.459215714978) (444, 643.2353742108684) (445, 644.0311399352214) (446, 644.9316567025953) (447, 647.3473689448616) (448, 635.4855484450435) (449, 628.7353523981556) + }; + \addplot [red] coordinates { + (0, 173.51242311267396) (1, 226.56468376945395) (2, 227.2128790606232) (3, 228.80979958275339) (4, 229.00661476467667) (5, 227.7773552530195) (6, 227.1400372238188) (7, 227.7280628790279) (8, 223.38898073349634) (9, 221.50976541647174) (10, 219.264282572698) (11, 217.6438689308548) (12, 212.43262157854406) (13, 209.06321520889782) (14, 203.06777034194198) (15, 203.06102278721391) (16, 199.9207834366171) (17, 198.58630343161053) (18, 196.68354258971243) (19, 195.4182799948153) (20, 189.27510661404494) (21, 187.22908617944375) (22, 185.19119949876904) (23, 183.92035332026586) (24, 183.42132197776613) (25, 183.48806596832918) (26, 180.61143390944244) (27, 177.58458247604062) (28, 175.9406922344877) (29, 174.54001651342872) (30, 171.99889125873892) (31, 170.60644472409058) (32, 169.05174623765078) (33, 168.57232084674234) (34, 168.96992205783295) (35, 167.570810757333) (36, 166.94265776448782) (37, 165.7726082271745) (38, 167.7328001560154) (39, 169.11527251133663) (40, 169.43277923657683) (41, 172.5509148371089) (42, 172.72150791802056) (43, 174.491136729493) (44, 175.7288507493529) (45, 177.5005171769717) (46, 178.45187359467695) (47, 179.80358263123276) (48, 179.76981579366452) (49, 180.52707676683917) (50, 180.35004115061412) (51, 179.85468675267794) (52, 179.14599346043087) (53, 179.2473979927782) (54, 181.0362629602473) (55, 180.72325111901546) (56, 181.25624714830474) (57, 178.69220676301507) (58, 179.31661022035428) (59, 182.9305532216797) (60, 183.16762399923965) (61, 181.92984593877253) (62, 184.30568549033842) (63, 181.58199597905536) (64, 182.50323477665705) (65, 186.490902542115) (66, 183.87109298489122) (67, 185.39111331070058) (68, 185.0394833185585) (69, 185.32262163112273) (70, 191.89228328673357) (71, 192.28682234935837) (72, 192.7635948338334) (73, 188.906153664788) (74, 189.68758016499714) (75, 193.32600166696312) (76, 191.75814655909556) (77, 168.8224626879811) (78, 193.43085019793517) (79, 193.4148643403953) (80, 188.78053845023123) (81, 186.41910456041018) (82, 185.71667531135836) (83, 184.18057353191267) (84, 181.53451689079907) (85, 181.1804028143206) (86, 181.4093489171994) (87, 179.9772603674271) (88, 181.10610587236306) (89, 180.83252149031176) (90, 180.5774610953183) (91, 179.3240984762383) (92, 181.04893497236577) (93, 179.8866102083585) (94, 184.67420233617054) (95, 184.25114524528476) (96, 185.15654325472195) (97, 181.3425673025256) (98, 181.30397824653) (99, 185.06774820786546) (100, 186.56305829495886) (101, 181.76567436124833) (102, 181.70587136221707) (103, 182.34958157699026) (104, 187.16223833604317) (105, 187.65818898138446) (106, 187.51769132613276) (107, 188.6309994241701) (108, 191.53486936415038) (109, 196.36822131498957) (110, 197.53616842969512) (111, 197.04912421890504) (112, 198.6181838772997) (113, 200.1446845708881) (114, 204.07152562906816) (115, 205.34928604590505) (116, 205.7700842909901) (117, 211.5522665173625) (118, 212.79692872591545) (119, 213.58136969802467) (120, 215.93233954765992) (121, 216.68927322340545) (122, 218.0631256899958) (123, 215.71905386835624) (124, 219.80168889572906) (125, 218.1396527048646) (126, 219.8947847989645) (127, 219.97287730928338) (128, 222.4371715941873) (129, 225.98003024871372) (130, 225.25253611192005) (131, 228.08159374052184) (132, 230.22535678466647) (133, 233.2388071258331) (134, 234.85040711621946) (135, 235.42534657605165) (136, 234.5844627230942) (137, 233.55302273146293) (138, 237.73451317838652) (139, 236.8956794358843) (140, 238.22978340672262) (141, 237.82942741115653) (142, 236.73053200217646) (143, 231.38345624955298) (144, 226.83189132907256) (145, 225.85711833727532) (146, 222.576656609363) (147, 224.46227260015849) (148, 220.7940680131219) (149, 220.2853720058726) (150, 212.96115990445008) (151, 210.74787827412808) (152, 208.32784239690045) (153, 203.4766905094806) (154, 197.60157593891785) (155, 195.84074470736437) (156, 194.81961077029064) (157, 190.59796851158694) (158, 187.22333820443083) (159, 186.67245218894072) (160, 186.04712473861196) (161, 183.54978523756904) (162, 178.1907457824583) (163, 178.22027896362403) (164, 174.78773600886228) (165, 175.69397707091775) (166, 176.36639376297023) (167, 174.59461199466188) (168, 174.2023038431608) (169, 170.4208250203023) (170, 174.18251808774806) (171, 173.18683480337302) (172, 171.8167865195046) (173, 171.98219291799364) (174, 169.783619045254) (175, 173.53658987194996) (176, 207.39471365511173) (177, 206.8059538996062) (178, 207.32041570750062) (179, 204.97760645596003) (180, 207.85899837894846) (181, 210.40779911119853) (182, 215.84588559702138) (183, 215.8493209665806) (184, 216.76441359573704) (185, 172.50468842729015) (186, 217.44122237203294) (187, 218.8085502180504) (188, 218.42502142111653) (189, 218.57176963301845) (190, 215.95424123665015) (191, 219.76076198029386) (192, 218.98779144615764) (193, 218.7735177816121) (194, 216.19080795586592) (195, 214.95042651429299) (196, 216.51399114086826) (197, 217.2979443840777) (198, 216.80054805899317) (199, 216.68808420508321) (200, 216.4219142485706) (201, 214.81550647658173) (202, 216.61555003007288) (203, 220.0142547382079) (204, 213.5609101402968) (205, 215.24065768489436) (206, 213.6294224394751) (207, 218.2416296874763) (208, 213.80807692364397) (209, 210.44481015762761) (210, 213.14361169575113) (211, 218.1981396462745) (212, 217.04730861145663) (213, 214.46042838323615) (214, 215.22174229518617) (215, 214.9395261178704) (216, 218.2294593313377) (217, 216.78657683634748) (218, 218.02470869384757) (219, 219.74503197565878) (220, 219.21416545876383) (221, 218.69333255962692) (222, 225.21645750897278) (223, 223.77664260204892) (224, 220.51453591506447) (225, 222.18343489280534) (226, 219.41257864249388) (227, 221.59269546775744) (228, 219.76986987093636) (229, 221.47443582876622) (230, 217.84428209473305) (231, 219.68318667305607) (232, 219.53084490509679) (233, 220.7920407007648) (234, 223.69435882619013) (235, 224.52255842215004) (236, 222.91866182451417) (237, 227.30705171328754) (238, 228.5845536660638) (239, 231.7820360941687) (240, 227.24248998652507) (241, 229.28800907160695) (242, 227.88472943048487) (243, 228.57160419234992) (244, 226.14953410081688) (245, 45.21686677693879) (246, 3.849341186247102) (247, 2.788195025603045) (248, 10.922015721502703) (249, 15.48547445453596) (250, 16.513722887339554) (251, 22.245131544948435) (252, 25.437798024370522) (253, 28.69050134108784) (254, 34.689125271268495) (255, 27.52751508564029) (256, 88.7307373224051) (257, 28.26943552117109) (258, 34.86846829903175) (259, 16.50502157678443) (260, 12.599953951031921) (261, 11.798477904606443) (262, 10.100317606514636) (263, 18.22358457505925) (264, 18.58187367031337) (265, 17.67044955544111) (266, 17.337961399969345) (267, 92.87845761080547) (268, 11.747251069624781) (269, 9.018662183587821) (270, 5.818996833525034) (271, 6.027053047834215) (272, 20.334078976459978) (273, 27.62645491337571) (274, 37.537428330274906) (275, 41.28299068584329) (276, 50.03633642507475) (277, 61.399254342960376) (278, 95.04006086115464) (279, 67.10226453042196) (280, 81.00392212919951) (281, 85.90451089233261) (282, 39.19021532411034) (283, 44.253721386520965) (284, 107.74461470423313) (285, 119.19346060313273) (286, 126.4536732747224) (287, 67.44818895332429) (288, 77.82862589789045) (289, 107.13976553553539) (290, 86.84214260460584) (291, 151.66065335424855) (292, 95.96903808444966) (293, 163.38209555493881) (294, 114.45894848172884) (295, 117.80951033909326) (296, 128.7500414820335) (297, 163.00714744942456) (298, 169.58631571144127) (299, 163.92525002673284) (300, 110.86763376611043) (301, 159.51509782750782) (302, 165.37164705964864) (303, 165.2370194642798) (304, 179.928697907934) (305, 177.34690700350973) (306, 179.66834184122467) (307, 111.39107114155848) (308, 114.6751782964227) (309, 117.84614427248812) (310, 186.11833064335997) (311, 184.3053685231066) (312, 181.6078063752339) (313, 178.8044278795963) (314, 175.30347089269208) (315, 118.7566816148344) (316, 171.10485701967423) (317, 166.7700891401953) (318, 163.08752642589025) (319, 159.8802737422102) (320, 155.20214683066) (321, 151.7312663510645) (322, 148.0199729680616) (323, 147.6443932786865) (324, 137.36881555460917) (325, 136.16738184654514) (326, 122.69873289102111) (327, 50.13800679898122) (328, 130.85624422547875) (329, 122.54840557548164) (330, 110.07601157232057) (331, 104.89566813978354) (332, 91.65891096271207) (333, 90.96013536137093) (334, 84.1592213358008) (335, 75.28863639953624) (336, 69.77230729309485) (337, 64.43910093564864) (338, 128.6730029921037) (339, 58.20657535973305) (340, 52.3799630079418) (341, 48.03046732260145) (342, 46.913695233585486) (343, 41.05238213251437) (344, 36.987871811862306) (345, 36.61932159780986) (346, 25.020674034420153) (347, 21.96249164878941) (348, 22.54203862790655) (349, 133.41770594236277) (350, 18.21556847826878) (351, 20.44351707497367) (352, 20.57074049034395) (353, 21.820533815122417) (354, 23.662918355029888) (355, 27.90815393453113) (356, 29.414040939076585) (357, 31.49706758426919) (358, 32.7512384709089) (359, 34.24885024886407) (360, 137.10059051802932) (361, 38.87311798658834) (362, 41.00095306395019) (363, 38.92436470720054) (364, 40.40306459177032) (365, 37.59139778399481) (366, 31.210302807694006) (367, 32.06220196658978) (368, 39.740914851405705) (369, 37.217126300871996) (370, 38.66726397873026) (371, 141.18121385588097) (372, 38.406514414790536) (373, 40.99166835393089) (374, 34.99099606136883) (375, 39.71814153077844) (376, 40.60378920825087) (377, 41.74748177256629) (378, 41.64641302310838) (379, 35.525180118718936) (380, 25.87036832195031) (381, 23.260011256606276) (382, 144.5429549606436) (383, 22.532419156970718) (384, 18.821750801274447) (385, 19.164947113794597) (386, 17.906909198502944) (387, 16.220808476330376) (388, 13.328840729594504) (389, 12.554650105596238) (390, 11.528234590745342) (391, 7.778741840092607) (392, 5.879687867412031) (393, 146.11581958118109) (394, 4.904709065598581) (395, 11.60462684654749) (396, 13.32487167217505) (397, 15.057286834276738) (398, 13.97186215300303) (399, 16.33443148071865) (400, 16.949906838907737) (401, 18.08566997388266) (402, 22.003202015830993) (403, 23.044318188244915) (404, 150.4881861786755) (405, 27.34548076113333) (406, 33.500760337953125) (407, 29.145010811509337) (408, 32.20272838836695) (409, 33.409414087146615) (410, 29.533488089024786) (411, 29.527906846596352) (412, 34.75420574595091) (413, 39.71346748530914) (414, 37.13230085887926) (415, 154.9981001899842) (416, 43.61581621518462) (417, 48.04281492857194) (418, 49.00096514017605) (419, 51.34693496162549) (420, 51.48930768277614) (421, 53.752676390057104) (422, 59.463842432564434) (423, 64.72954263008819) (424, 66.6940564656793) (425, 71.74602296333387) (426, 155.23106773398757) (427, 75.48221458965327) (428, 81.06372526767564) (429, 88.01327945385225) (430, 92.88823308391056) (431, 94.26113648783075) (432, 102.05828009288689) (433, 107.33420270111668) (434, 111.89276599175969) (435, 114.44770473211071) (436, 121.30183965929336) (437, 158.2736530988709) (438, 50.17599478849411) (439, 122.52017784486588) (440, 126.4252555027029) (441, 134.36202243602452) (442, 132.37976874871168) (443, 141.29349058712796) (444, 141.89600155722428) (445, 147.95350048067417) (446, 151.51589728364434) (447, 154.3082528185098) (448, 53.77492255663492) (449, 60.11790067863444) (450, 64.53550722400973) (451, 174.56710798705535) (452, 167.96628045348479) (453, 160.98147192725008) (454, 159.85459498669775) (455, 157.7151062418131) (456, 68.03200906298548) (457, 155.16768130832105) (458, 152.71902588726698) (459, 147.89996876045257) (460, 148.309288526481) (461, 147.273962717433) (462, 146.01616970319947) (463, 141.44948438357574) (464, 139.01432940349196) (465, 137.75138042902637) (466, 136.99697417058428) (467, 70.51734947260934) (468, 134.57453681671996) (469, 133.37619669314745) (470, 127.56093678612456) (471, 124.57224675907855) (472, 121.53799833413859) (473, 118.17165286431367) (474, 112.1386885434722) (475, 114.54505691884287) (476, 106.15517393069695) (477, 96.78946535818386) (478, 75.55087213892966) (479, 78.71827067532286) (480, 74.98085035533381) (481, 67.1694842139591) (482, 50.00129336452915) (483, 44.634853683289066) (484, 37.59261270638103) (485, 27.003479736465124) (486, 25.473225717575588) (487, 21.12061232491874) (488, 14.73430918601457) (489, 84.7077870069902) + }; + \end{axis} +\end{tikzpicture} + \caption{Данные тренировки} + \label{fig:train-results} +\end{figure} + +\begin{figure}[H] + \centering +\begin{tikzpicture} + \begin{axis}[ + xmin=0, xmax=170, ymin=0, ymax=690, + width=140mm,height=110mm, + xlabel=Изображение, + ylabel=Разность моментов инерции главных осей тела,] + \addplot [blue, only marks] coordinates { + (0, 173.29764182010757) (1, 172.6389865077026) (2, 173.149352035025) (3, 170.03767210208844) (4, 174.94166790227098) (5, 178.9239885772716) (6, 178.30395376707702) (7, 178.7542860541896) (8, 179.91099808492322) (9, 180.59798146508496) (10, 180.5012626982387) (11, 184.87771903147103) (12, 179.07031756694306) (13, 181.53630773096444) (14, 184.41087015555996) (15, 182.9962549413138) (16, 183.9495773915944) (17, 183.63330975240683) (18, 186.1461796983633) (19, 180.651263928851) (20, 180.74957122449678) (21, 183.90010227329986) (22, 182.5549496487668) (23, 183.10330011133885) (24, 182.64618865766988) (25, 180.85013541771013) (26, 181.2670499174219) (27, 180.72609703165637) (28, 180.75293296190875) (29, 180.15323226079659) (30, 182.76669619393556) (31, 182.85348420399578) (32, 181.35249930838427) (33, 183.8049567748934) (34, 184.09189377612688) (35, 185.7283997349616) (36, 188.33369524814105) (37, 190.4952359597906) (38, 191.82551356428513) (39, 192.89921640555383) (40, 192.8210404698495) (41, 193.68686749053018) (42, 196.0864301316655) (43, 172.31125120179695) (44, 169.04931376644566) (45, 169.86514484518756) (46, 198.3700133498171) (47, 174.17877154682304) (48, 173.3844128259703) (49, 173.54590410832157) (50, 171.47524504342744) (51, 172.83319776922235) (52, 174.68315817974127) (53, 180.26177125596837) (54, 180.25433818207784) (55, 182.00770456617806) (56, 181.66843852471885) (57, 201.5413394316525) (58, 181.84970369175772) (59, 182.40091882524848) (60, 183.99821335577622) (61, 187.00110172159293) (62, 191.21229408486556) (63, 191.00878749191747) (64, 191.14138702139707) (65, 190.99291975623208) (66, 190.64309832943383) (67, 193.70519931080344) (68, 205.80956225992531) (69, 195.640486613529) (70, 198.7398962957193) (71, 203.61106667796116) (72, 204.24560080814257) (73, 205.01459978514265) (74, 204.9053758209588) (75, 206.65084637672874) (76, 218.4782631176463) (77, 170.7641597237909) (78, 169.23124635127192) (79, 169.08727584723107) (80, 174.8284346579918) (81, 173.80038908954003) (82, 172.9261443634212) (83, 176.6490344663075) (84, 183.4001998705088) (85, 185.20335067893757) (86, 197.1646169444748) (87, 199.08743325457067) (88, 202.21628921532556) (89, 210.6626116192133) (90, 211.8693191263049) (91, 214.34520467075805) (92, 220.9442932752288) (93, 225.22607026426766) (94, 226.10329757553927) (95, 225.47626463754432) (96, 224.10929074576484) (97, 228.35920265487516) (98, 226.4320784640609) (99, 224.05243699323995) (100, 222.3875457513655) (101, 216.8160288775743) (102, 210.9622953460107) (103, 203.03837539385785) (104, 209.64679821274837) (105, 202.94174593478562) (106, 198.6230459854212) (107, 193.3418402530417) (108, 197.6684571727463) (109, 191.03703787050745) (110, 196.27624651128707) (111, 186.0867507236499) (112, 157.86589946075264) (113, 171.73828545411084) (114, 163.92596896255668) (115, 170.71655891582395) (116, 170.5372251421989) (117, 175.92897305871202) (118, 178.58896093850467) (119, 185.69540338002588) (120, 186.23217573930492) (121, 186.44025429282635) (122, 186.66501327829252) (123, 186.6503995964335) (124, 173.8510594801719) (125, 190.07254019970878) (126, 189.06032060957455) (127, 193.1345087547479) (128, 191.56622264297044) (129, 191.8477911115283) (130, 194.0415200343075) (131, 196.01261668301726) (132, 191.68644168600417) (133, 176.50473671074428) (134, 180.53010852647208) (135, 184.05798546459073) (136, 186.53864341386662) (137, 186.2807485476228) (138, 188.75026329680804) (139, 188.01659159726773) (140, 187.24367349121098) (141, 191.58116671245733) (142, 192.01637825118542) (143, 189.73962873249565) (144, 193.57828256986772) (145, 192.9997668146757) (146, 195.9931824868134) (147, 191.066264073414) (148, 190.62920965433977) (149, 189.3061256052108) (150, 187.7076993203002) (151, 190.48967645851826) (152, 188.05225502574154) (153, 184.7015855333878) (154, 181.72580337621395) (155, 182.0073361769107) (156, 183.36080785274362) (157, 180.4239253409844) (158, 184.89952087917436) (159, 183.26371266127666) (160, 176.6950436565437) (161, 177.2941686542481) (162, 175.51560457518218) (163, 173.19055397920988) (164, 167.54028792510553) (165, 163.63023854982993) + }; + \addplot [red, only marks] coordinates { + (0, 632.8931699822933) (1, 629.7038316620205) (2, 625.5013602550243) (3, 637.9479118254721) (4, 635.784476882296) (5, 629.0900104139605) (6, 628.307820854963) (7, 626.0424996951442) (8, 631.6984517078465) (9, 630.6725267963852) (10, 630.6086224641941) (11, 624.1401063364196) (12, 623.686716719738) (13, 621.6113845119769) (14, 620.3068927688273) (15, 622.8482459106467) (16, 624.5830594422794) (17, 620.8978857895659) (18, 623.0057912390344) (19, 610.5611643344187) (20, 622.6607347837121) (21, 623.4048567112111) (22, 622.7979515091522) (23, 624.1046390149496) (24, 625.5979617243534) (25, 626.3452201961579) (26, 633.9202721111658) (27, 623.727719628704) (28, 623.7376087997175) (29, 620.8573777418496) (30, 620.8051690722007) (31, 620.934345370192) (32, 619.463807403215) (33, 620.0400587181165) (34, 621.7440979178523) (35, 619.3000997892827) (36, 618.7151210878569) (37, 615.415529253858) (38, 616.8641613947239) (39, 614.5406877169245) (40, 614.5212611665879) (41, 621.8106168796833) (42, 621.493603326729) (43, 620.0563202016983) (44, 620.6157091834348) (45, 625.0921743024971) (46, 630.6061184845965) (47, 634.5309767186541) (48, 636.1592791984662) (49, 619.5119695461385) (50, 432.7849376830029) (51, 414.85554093268877) (52, 402.5637803166401) (53, 395.6289079093242) (54, 367.0696582980438) (55, 367.96165478471363) (56, 353.9202625616549) (57, 315.44691280758894) (58, 243.29723235968913) (59, 216.1450637919022) (60, 211.2433337504151) (61, 214.77336051935356) (62, 192.89889085747876) (63, 227.57301738713363) (64, 255.60402289057862) (65, 293.7496240153587) (66, 373.1518621965313) (67, 402.5317275945274) (68, 421.3552941983651) (69, 447.33389207735854) (70, 460.64473696411574) (71, 477.90778403433114) (72, 492.9190960492312) (73, 329.42504606184184) (74, 276.37916603230826) (75, 257.0969230704086) (76, 237.9359923032116) (77, 217.63441613840206) (78, 189.57337744276134) (79, 144.82041846199866) (80, 124.06275663469887) (81, 94.86463055078798) (82, 57.0416111903769) (83, 43.68987693744498) (84, 38.589038001010294) (85, 30.962040401506783) (86, 24.46658420394192) (87, 26.721696591810087) (88, 48.540961521352074) (89, 88.4142216054247) (90, 125.40487924607874) (91, 197.28731453402224) (92, 229.8385257062983) (93, 256.97479000271545) (94, 284.3930572959491) (95, 307.16974825755193) (96, 325.05736443395375) (97, 352.03079765591633) (98, 369.1596572138391) (99, 387.60246662779787) (100, 357.380302995957) (101, 334.6630211198651) (102, 315.8144106212038) (103, 296.01304475342783) (104, 263.72056321834066) (105, 203.37843524117216) (106, 172.9659998363727) (107, 140.56728754758478) (108, 106.28972147131753) (109, 51.686933273975455) (110, 41.28449832694878) (111, 40.76620110041972) (112, 42.95481060875386) (113, 37.83427370347977) (114, 43.826271894231695) (115, 36.612635480213385) (116, 74.78745646327366) (117, 107.71892696334089) (118, 135.51135524360188) (119, 209.06019221722045) (120, 241.38331606375345) (121, 275.8713738407264) (122, 300.96102573203007) (123, 316.7352734702408) (124, 367.1689648282829) (125, 391.8209961394373) (126, 404.58824831771585) (127, 421.63351876129116) (128, 359.1309905971775) (129, 338.4575964215583) (130, 314.38356570027923) (131, 290.94087787016895) (132, 234.82476349332978) (133, 202.51480955923716) (134, 178.18015015344713) (135, 156.32753515825402) (136, 138.26972918427714) (137, 133.8558506359691) (138, 127.99689973687447) (139, 168.08725547216403) (140, 206.86455063620224) (141, 242.82078906480683) (142, 269.97425464635177) (143, 300.2739783372019) (144, 350.5724224528708) (145, 366.6897691365413) (146, 393.1298418583999) (147, 404.94304648961565) (148, 432.24598337735745) (149, 448.2804663651735) + }; + \addplot [black] coordinates { + (0,346.02779819908665) (170,346.02779819908665) + }; + \addplot [black] coordinates { + (0,647.416671344422) (170,647.416671344422) + }; + % ошибки 2 рода + \addplot [green, only marks] coordinates{ + (0, -1) (1, -1) (2, -1) (3, -1) (4, -1) (5, -1) (6, -1) (7, -1) (8, -1) (9, -1) (10, -1) (11, -1) (12, -1) (13, -1) (14, -1) (15, -1) (16, -1) (17, -1) (18, -1) (19, -1) (20, -1) (21, -1) (22, -1) (23, -1) (24, -1) (25, -1) (26, -1) (27, -1) (28, -1) (29, -1) (30, -1) (31, -1) (32, -1) (33, -1) (34, -1) (35, -1) (36, -1) (37, -1) (38, -1) (39, -1) (40, -1) (41, -1) (42, -1) (43, -1) (44, -1) (45, -1) (46, -1) (47, -1) (48, -1) (49, -1) (50, -1) (51, -1) (52, -1) (53, -1) (54, -1) (55, -1) (56, -1) (57, 315.44691280758894) (58, 243.29723235968913) (59, 216.1450637919022) (60, 211.2433337504151) (61, 214.77336051935356) (62, 192.89889085747876) (63, 227.57301738713363) (64, 255.60402289057862) (65, 293.7496240153587) (66, -1) (67, -1) (68, -1) (69, -1) (70, -1) (71, -1) (72, -1) (73, 329.42504606184184) (74, 276.37916603230826) (75, 257.0969230704086) (76, 237.9359923032116) (77, 217.63441613840206) (78, 189.57337744276134) (79, 144.82041846199866) (80, 124.06275663469887) (81, 94.86463055078798) (82, 57.0416111903769) (83, 43.68987693744498) (84, 38.589038001010294) (85, 30.962040401506783) (86, 24.46658420394192) (87, 26.721696591810087) (88, 48.540961521352074) (89, 88.4142216054247) (90, 125.40487924607874) (91, 197.28731453402224) (92, 229.8385257062983) (93, 256.97479000271545) (94, 284.3930572959491) (95, 307.16974825755193) (96, 325.05736443395375) (97, -1) (98, -1) (99, -1) (100, -1) (101, 334.6630211198651) (102, 315.8144106212038) (103, 296.01304475342783) (104, 263.72056321834066) (105, 203.37843524117216) (106, 172.9659998363727) (107, 140.56728754758478) (108, 106.28972147131753) (109, 51.686933273975455) (110, 41.28449832694878) (111, 40.76620110041972) (112, 42.95481060875386) (113, 37.83427370347977) (114, 43.826271894231695) (115, 36.612635480213385) (116, 74.78745646327366) (117, 107.71892696334089) (118, 135.51135524360188) (119, 209.06019221722045) (120, 241.38331606375345) (121, 275.8713738407264) (122, 300.96102573203007) (123, 316.7352734702408) (124, -1) (125, -1) (126, -1) (127, -1) (128, -1) (129, 338.4575964215583) (130, 314.38356570027923) (131, 290.94087787016895) (132, 234.82476349332978) (133, 202.51480955923716) (134, 178.18015015344713) (135, 156.32753515825402) (136, 138.26972918427714) (137, 133.8558506359691) (138, 127.99689973687447) (139, 168.08725547216403) (140, 206.86455063620224) (141, 242.82078906480683) (142, 269.97425464635177) (143, 300.2739783372019) (144, -1) (145, -1) (146, -1) (147, -1) (148, -1) (149, -1) + }; + \end{axis} +\end{tikzpicture} + \caption{Данные тестирования для предельных значений кукурузы} + \label{fig:test-results-corn} +\end{figure} + +\begin{figure}[H] + \centering +\begin{tikzpicture} + \begin{axis}[ + xmin=0, xmax=170, ymin=0, ymax=690, + width=140mm,height=110mm, + xlabel=Изображение, + ylabel=Разность моментов инерции главных осей тела,] + \addplot [blue, only marks] coordinates { + (0, 173.29764182010757) (1, 172.6389865077026) (2, 173.149352035025) (3, 170.03767210208844) (4, 174.94166790227098) (5, 178.9239885772716) (6, 178.30395376707702) (7, 178.7542860541896) (8, 179.91099808492322) (9, 180.59798146508496) (10, 180.5012626982387) (11, 184.87771903147103) (12, 179.07031756694306) (13, 181.53630773096444) (14, 184.41087015555996) (15, 182.9962549413138) (16, 183.9495773915944) (17, 183.63330975240683) (18, 186.1461796983633) (19, 180.651263928851) (20, 180.74957122449678) (21, 183.90010227329986) (22, 182.5549496487668) (23, 183.10330011133885) (24, 182.64618865766988) (25, 180.85013541771013) (26, 181.2670499174219) (27, 180.72609703165637) (28, 180.75293296190875) (29, 180.15323226079659) (30, 182.76669619393556) (31, 182.85348420399578) (32, 181.35249930838427) (33, 183.8049567748934) (34, 184.09189377612688) (35, 185.7283997349616) (36, 188.33369524814105) (37, 190.4952359597906) (38, 191.82551356428513) (39, 192.89921640555383) (40, 192.8210404698495) (41, 193.68686749053018) (42, 196.0864301316655) (43, 172.31125120179695) (44, 169.04931376644566) (45, 169.86514484518756) (46, 198.3700133498171) (47, 174.17877154682304) (48, 173.3844128259703) (49, 173.54590410832157) (50, 171.47524504342744) (51, 172.83319776922235) (52, 174.68315817974127) (53, 180.26177125596837) (54, 180.25433818207784) (55, 182.00770456617806) (56, 181.66843852471885) (57, 201.5413394316525) (58, 181.84970369175772) (59, 182.40091882524848) (60, 183.99821335577622) (61, 187.00110172159293) (62, 191.21229408486556) (63, 191.00878749191747) (64, 191.14138702139707) (65, 190.99291975623208) (66, 190.64309832943383) (67, 193.70519931080344) (68, 205.80956225992531) (69, 195.640486613529) (70, 198.7398962957193) (71, 203.61106667796116) (72, 204.24560080814257) (73, 205.01459978514265) (74, 204.9053758209588) (75, 206.65084637672874) (76, 218.4782631176463) (77, 170.7641597237909) (78, 169.23124635127192) (79, 169.08727584723107) (80, 174.8284346579918) (81, 173.80038908954003) (82, 172.9261443634212) (83, 176.6490344663075) (84, 183.4001998705088) (85, 185.20335067893757) (86, 197.1646169444748) (87, 199.08743325457067) (88, 202.21628921532556) (89, 210.6626116192133) (90, 211.8693191263049) (91, 214.34520467075805) (92, 220.9442932752288) (93, 225.22607026426766) (94, 226.10329757553927) (95, 225.47626463754432) (96, 224.10929074576484) (97, 228.35920265487516) (98, 226.4320784640609) (99, 224.05243699323995) (100, 222.3875457513655) (101, 216.8160288775743) (102, 210.9622953460107) (103, 203.03837539385785) (104, 209.64679821274837) (105, 202.94174593478562) (106, 198.6230459854212) (107, 193.3418402530417) (108, 197.6684571727463) (109, 191.03703787050745) (110, 196.27624651128707) (111, 186.0867507236499) (112, 157.86589946075264) (113, 171.73828545411084) (114, 163.92596896255668) (115, 170.71655891582395) (116, 170.5372251421989) (117, 175.92897305871202) (118, 178.58896093850467) (119, 185.69540338002588) (120, 186.23217573930492) (121, 186.44025429282635) (122, 186.66501327829252) (123, 186.6503995964335) (124, 173.8510594801719) (125, 190.07254019970878) (126, 189.06032060957455) (127, 193.1345087547479) (128, 191.56622264297044) (129, 191.8477911115283) (130, 194.0415200343075) (131, 196.01261668301726) (132, 191.68644168600417) (133, 176.50473671074428) (134, 180.53010852647208) (135, 184.05798546459073) (136, 186.53864341386662) (137, 186.2807485476228) (138, 188.75026329680804) (139, 188.01659159726773) (140, 187.24367349121098) (141, 191.58116671245733) (142, 192.01637825118542) (143, 189.73962873249565) (144, 193.57828256986772) (145, 192.9997668146757) (146, 195.9931824868134) (147, 191.066264073414) (148, 190.62920965433977) (149, 189.3061256052108) (150, 187.7076993203002) (151, 190.48967645851826) (152, 188.05225502574154) (153, 184.7015855333878) (154, 181.72580337621395) (155, 182.0073361769107) (156, 183.36080785274362) (157, 180.4239253409844) (158, 184.89952087917436) (159, 183.26371266127666) (160, 176.6950436565437) (161, 177.2941686542481) (162, 175.51560457518218) (163, 173.19055397920988) (164, 167.54028792510553) (165, 163.63023854982993) + }; + \addplot [red, only marks] coordinates { + (0, 632.8931699822933) (1, 629.7038316620205) (2, 625.5013602550243) (3, 637.9479118254721) (4, 635.784476882296) (5, 629.0900104139605) (6, 628.307820854963) (7, 626.0424996951442) (8, 631.6984517078465) (9, 630.6725267963852) (10, 630.6086224641941) (11, 624.1401063364196) (12, 623.686716719738) (13, 621.6113845119769) (14, 620.3068927688273) (15, 622.8482459106467) (16, 624.5830594422794) (17, 620.8978857895659) (18, 623.0057912390344) (19, 610.5611643344187) (20, 622.6607347837121) (21, 623.4048567112111) (22, 622.7979515091522) (23, 624.1046390149496) (24, 625.5979617243534) (25, 626.3452201961579) (26, 633.9202721111658) (27, 623.727719628704) (28, 623.7376087997175) (29, 620.8573777418496) (30, 620.8051690722007) (31, 620.934345370192) (32, 619.463807403215) (33, 620.0400587181165) (34, 621.7440979178523) (35, 619.3000997892827) (36, 618.7151210878569) (37, 615.415529253858) (38, 616.8641613947239) (39, 614.5406877169245) (40, 614.5212611665879) (41, 621.8106168796833) (42, 621.493603326729) (43, 620.0563202016983) (44, 620.6157091834348) (45, 625.0921743024971) (46, 630.6061184845965) (47, 634.5309767186541) (48, 636.1592791984662) (49, 619.5119695461385) (50, 432.7849376830029) (51, 414.85554093268877) (52, 402.5637803166401) (53, 395.6289079093242) (54, 367.0696582980438) (55, 367.96165478471363) (56, 353.9202625616549) (57, 315.44691280758894) (58, 243.29723235968913) (59, 216.1450637919022) (60, 211.2433337504151) (61, 214.77336051935356) (62, 192.89889085747876) (63, 227.57301738713363) (64, 255.60402289057862) (65, 293.7496240153587) (66, 373.1518621965313) (67, 402.5317275945274) (68, 421.3552941983651) (69, 447.33389207735854) (70, 460.64473696411574) (71, 477.90778403433114) (72, 492.9190960492312) (73, 329.42504606184184) (74, 276.37916603230826) (75, 257.0969230704086) (76, 237.9359923032116) (77, 217.63441613840206) (78, 189.57337744276134) (79, 144.82041846199866) (80, 124.06275663469887) (81, 94.86463055078798) (82, 57.0416111903769) (83, 43.68987693744498) (84, 38.589038001010294) (85, 30.962040401506783) (86, 24.46658420394192) (87, 26.721696591810087) (88, 48.540961521352074) (89, 88.4142216054247) (90, 125.40487924607874) (91, 197.28731453402224) (92, 229.8385257062983) (93, 256.97479000271545) (94, 284.3930572959491) (95, 307.16974825755193) (96, 325.05736443395375) (97, 352.03079765591633) (98, 369.1596572138391) (99, 387.60246662779787) (100, 357.380302995957) (101, 334.6630211198651) (102, 315.8144106212038) (103, 296.01304475342783) (104, 263.72056321834066) (105, 203.37843524117216) (106, 172.9659998363727) (107, 140.56728754758478) (108, 106.28972147131753) (109, 51.686933273975455) (110, 41.28449832694878) (111, 40.76620110041972) (112, 42.95481060875386) (113, 37.83427370347977) (114, 43.826271894231695) (115, 36.612635480213385) (116, 74.78745646327366) (117, 107.71892696334089) (118, 135.51135524360188) (119, 209.06019221722045) (120, 241.38331606375345) (121, 275.8713738407264) (122, 300.96102573203007) (123, 316.7352734702408) (124, 367.1689648282829) (125, 391.8209961394373) (126, 404.58824831771585) (127, 421.63351876129116) (128, 359.1309905971775) (129, 338.4575964215583) (130, 314.38356570027923) (131, 290.94087787016895) (132, 234.82476349332978) (133, 202.51480955923716) (134, 178.18015015344713) (135, 156.32753515825402) (136, 138.26972918427714) (137, 133.8558506359691) (138, 127.99689973687447) (139, 168.08725547216403) (140, 206.86455063620224) (141, 242.82078906480683) (142, 269.97425464635177) (143, 300.2739783372019) (144, 350.5724224528708) (145, 366.6897691365413) (146, 393.1298418583999) (147, 404.94304648961565) (148, 432.24598337735745) (149, 448.2804663651735) + }; + \addplot [black] coordinates { + (0,238.22978340672262) (170,238.22978340672262) + }; + \addplot [black] coordinates { + (0,2.788195025603045) (170,2.788195025603045) + }; + % ошибки 1 рода + \addplot [green, only marks] coordinates{ + (0, -1) (1, -1) (2, -1) (3, -1) (4, -1) (5, -1) (6, -1) (7, -1) (8, -1) (9, -1) (10, -1) (11, -1) (12, -1) (13, -1) (14, -1) (15, -1) (16, -1) (17, -1) (18, -1) (19, -1) (20, -1) (21, -1) (22, -1) (23, -1) (24, -1) (25, -1) (26, -1) (27, -1) (28, -1) (29, -1) (30, -1) (31, -1) (32, -1) (33, -1) (34, -1) (35, -1) (36, -1) (37, -1) (38, -1) (39, -1) (40, -1) (41, -1) (42, -1) (43, -1) (44, -1) (45, -1) (46, -1) (47, -1) (48, -1) (49, -1) (50, -1) (51, -1) (52, -1) (53, -1) (54, -1) (55, -1) (56, -1) (57, -1) (58, -1) (59, 216.1450637919022) (60, 211.2433337504151) (61, 214.77336051935356) (62, 192.89889085747876) (63, 227.57301738713363) (64, -1) (65, -1) (66, -1) (67, -1) (68, -1) (69, -1) (70, -1) (71, -1) (72, -1) (73, -1) (74, -1) (75, -1) (76, 237.9359923032116) (77, 217.63441613840206) (78, 189.57337744276134) (79, 144.82041846199866) (80, 124.06275663469887) (81, 94.86463055078798) (82, 57.0416111903769) (83, 43.68987693744498) (84, 38.589038001010294) (85, 30.962040401506783) (86, 24.46658420394192) (87, 26.721696591810087) (88, 48.540961521352074) (89, 88.4142216054247) (90, 125.40487924607874) (91, 197.28731453402224) (92, 229.8385257062983) (93, -1) (94, -1) (95, -1) (96, -1) (97, -1) (98, -1) (99, -1) (100, -1) (101, -1) (102, -1) (103, -1) (104, -1) (105, 203.37843524117216) (106, 172.9659998363727) (107, 140.56728754758478) (108, 106.28972147131753) (109, 51.686933273975455) (110, 41.28449832694878) (111, 40.76620110041972) (112, 42.95481060875386) (113, 37.83427370347977) (114, 43.826271894231695) (115, 36.612635480213385) (116, 74.78745646327366) (117, 107.71892696334089) (118, 135.51135524360188) (119, 209.06019221722045) (120, -1) (121, -1) (122, -1) (123, -1) (124, -1) (125, -1) (126, -1) (127, -1) (128, -1) (129, -1) (130, -1) (131, -1) (132, 234.82476349332978) (133, 202.51480955923716) (134, 178.18015015344713) (135, 156.32753515825402) (136, 138.26972918427714) (137, 133.8558506359691) (138, 127.99689973687447) (139, 168.08725547216403) (140, 206.86455063620224) (141, -1) (142, -1) (143, -1) (144, -1) (145, -1) (146, -1) (147, -1) (148, -1) (149, -1) + }; + \end{axis} +\end{tikzpicture} + \caption{Данные тестирования для предельных значений груши} + \label{fig:test-results-quince} +\end{figure} +Далее был организован и проведён эксперимент на тестовой выборке. +\begin{lstlisting}[language=Python,style=PyCodeStyle, caption={Код эксперимента на тестовой выборке}, label={code:testing}] +def testing(fruit_path, limits, inverse=False): + list_image = get_list_image(fruit_path) + true_array = [] + for image in list_image: + own_numbers = solve_matrix(tensor(image[0])) + delta = (abs(own_numbers[0] - own_numbers[1])) + if (limits[0] < delta < limits[1]) ^ inverse: + true_array.append(image[1]) + return true_array +\end{lstlisting} +и вычислены ошибки первого и второго рода. Ошибки первого рода - это когда программа приняла кукурузу за грушу. Ошибка второго рода - это когда программа не приняла кукурузу за кукурузу. В результате обработки тестовой выборки было выявлено: +\begin{table}[H] + \centering + \begin{tabular}{|c|c|c|} + \hline + & Первого рода (шт.) & Второго рода (шт.)\\ + \hline + Corn & 0 & 71 \\ + \hline + Quince & 25 & 0 \\ + \hline + \end{tabular} + \caption{Ошибки при обработке тестовой выборки} + \label{tab:testing-errors} +\end{table} + +Диаграмма работы программы имеет следующий вид: +\begin{center} +\begin{sequencediagram} + \newthread{m}{:Main} + \newinst[1]{tr}{:Training} + \newinst[1]{ts}{:Testing} + \newinst[1]{ip}{:Image processing} + \newinst[1]{sd}{:Stat dictionary} + + \begin{sdblock}{Training}{gathering stats} + \begin{call}{m}{invoke}{tr}{} + \begin{call}{tr}{invoke with train path}{ip}{tensor delta} + \begin{call}{ip}{tensor}{ip}{} \end{call} + \begin{call}{ip}{solve}{ip}{} \end{call} + \end{call} + \begin{call}{tr}{write deltas}{sd}{} \end{call} + \end{call} + \end{sdblock} + + \begin{sdblock}{Testing}{checking pics} + \begin{call}{m}{invoke}{ts}{} + \begin{call}{ts}{invoke test path}{ip}{tensor delta} + \begin{call}{ip}{tensor}{ip}{} \end{call} + \begin{call}{ip}{solve}{ip}{} \end{call} + \end{call} + \begin{call}{ts}{}{sd}{read deltas} \end{call} + \begin{call}{ts}{check deltas}{ts}{} \end{call} + \begin{call}{ts}{write errors}{sd}{} \end{call} + \end{call} + \end{sdblock} +\end{sequencediagram} +\end{center} + +Выполнение алгоритма преобразования было разделено на несколько шагов, показанных на рис. \hrf{pic:cstages} и \hrf{pic:qstages}. Каждое изображение было преобразовано в градации серого, далее был применён фильтр Кэнни и произведена заливка контура. + +\begin{figure} + \centering + \includegraphics{01-picture.png} + \includegraphics{01-picture_gray.png} + \includegraphics{01-picture_canny.png} + \includegraphics{01-picture_chull.png} + \caption{Изменения изображения кукурузы} + \label{pic:cstages} +\end{figure} + +\begin{figure} + \centering + \includegraphics{02-picture.png} + \includegraphics{02-picture_gray.png} + \includegraphics{02-picture_canny.png} + \includegraphics{02-picture_chull.png} + \caption{Изменения изображения груши} + \label{pic:qstages} +\end{figure} + +На рис. \hrf{fig:test-results-quince} и \hrf{fig:test-results-corn} зелёным отмечены изображения, которые продемонстрировали ошибки первого и второго рода, соответственно. + +\section{Заключение и выводы} +С использованием фильтра, определяющего границы и некоторых дополнительных расчётов с большой долей точности возможно определить, какое именно изображение было передано программе. Очевидно, что категоризировать изображение только по его форме почти невозможно, несмотря на то, что был выбран достаточно гибкий способ определения формы через вычисление тензора инерции, и это возможно доказать подобрав изображения близких по форме предметов. + +\nocite{dip:gonzales-dip} +\nocite{dip:math-an} +\nocite{dip:recognition-dip} + +\newpage +\printbibliography[heading=bibintoc, title={Список литературы}] + +\newpage +\appendix +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Alph{subsection}} + +\subsection{Исходный пример работы фильтра Кэнни.} +\label{appendix:file-loading} +\begin{lstlisting}[language=Python,style=PyCodeStyle] +# -*- coding: utf-8 -*- + import matplotlib.pyplot as plt + from skimage import feature + from skimage import io + from skimage.color import rgb2gray + + image = io.imread(....) # loading image <@\label{line:img-read}@> + im_gray = rgb2gray(image) # modifying to greyscale <@\label{line:img-to-greyscale}@> + + # Compute the Canny filter for two values of sigma (from example + edges1 = feature.canny(im_gray) + edges2 = feature.canny(im_gray, sigma=3) + + # display results + fig, ax = plt.subplots(nrows=1, ncols=3, figsize=(8, 3)) + ax[0].imshow(image, cmap='gray') + ax[0].set_title('noisy image', fontsize=20) + ax[1].imshow(edges1, cmap='gray') + ax[1].set_title(r'Canny filter, $\sigma=1$', fontsize=20) + ax[2].imshow(edges2, cmap='gray') + ax[2].set_title(r'Canny filter, $\sigma=3$', fontsize=20) + + for a in ax: + a.axis('off') + + fig.tight_layout() + plt.show() +\end{lstlisting} + +\newpage +\subsection{Математическое обоснование работы функции вычисления тензора инерции} +Тензор инерции величина связывающая момент импульса тела с его угловой скоростью \(\bar{L} = \widehat{J}\bar{w}\). Для тела состоящего из N точек величина момента n-й точки вычисляется по формуле \(\bar{L}_n = \bar{r} \times \bar{p}\). Тогда момент импульса тела можно представить как: +\[\bar{L} = \sum_{n=1}^{N} \bar{r} \times \bar{p}.\] + +Импульс тела массой m равен \(\bar{p} = m\bar{v}\), тогда выражая скорость через угловую скорость (\(\bar{v} = [\bar{w} \times \bar{r}]\)), получаем выражение для момента инерции тела: +\[\bar{L} = \sum_{n=1}^{N} \bar{r} \times m_n [\bar{w} \times \bar{r}].\] + +Так как масса - это скалярная величина получаем: +\[\bar{L} = \sum_{n=1}^{N} m_n[\bar{r} \times [\bar{w} \times \bar{r}]]\] + +Применив формулу Лагранжа для двойного векторного произведения +\[[\bar{r} \times [\bar{w} \times \bar{r}]] = \bar{w} (\bar{r}, \bar{r}) - \bar{r}(\bar{w},\bar{r})\] + +Так как для ортонормированного базиса \((\bar{w} , \bar{r}) = w_x x + w_y y + w_z z\) получаем: +\[ \bar{L} = \sum_{n=1}^N m_n[\bar{r} \times [\bar{w} \times \bar{r}]] = \sum_{n=1}^N m_n (\bar{w} r^2 - \bar{r}(w_x x + w_y y + w_z z)).\] + +Пусть векторы базиса i,j,k: +\begin{equation*} + \begin{gathered} + \sum_{n=1}^N m_n ((\bar{i}w_x r^2 + \bar{j}w_y r^2 + \bar{k}w_z r^2) - (\bar{i}x + \bar{j}y + \bar{k}z)(w_x x + w_y y + w_z z)) = \\ += \sum_{n=1}^N m_n ((\bar{i}w_x (x^2 + y^2 + z^2) + \bar{j}w_y (x^2 + y^2 + z^2) + \bar{k}w_z (x^2 + y^2 + z^2)) -\\ +- (\bar{i}w_x x^2 + \bar{j}w_y y^2 + \bar{k}w_z z^2 + \bar{i}w_y x y + \bar{i}w_z x z + \bar{j}w_x y x + \bar{j}w_z y z + \bar{k}w_x z x + \bar{k}w_y z y )) + \end{gathered} +\end{equation*} + +Сокращая члены выражения получаем: +\begin{equation*} + \begin{gathered} + \sum_{n=1}^N m_n ((\bar{i}w_x (y^2 + z^2) + \bar{j}w_y (x^2 +z^2) + \bar{k}w_z (x^2 + y^2)) -\\ + -(\bar{i}w_y x y + \bar{i}w_z x z + \bar{j}w_x y x + \bar{j}w_z y z + \bar{k}w_x z x +\bar{k}w_y z y )) \\ + \end{gathered} +\end{equation*} + +Так как масса тела находится в одной плоскости, выражение примет вид: +\[\bar{L} = \sum_{n=1}^{N} m_n ((\bar{i}{w}_x (y^2) + \bar{j}{w}_y (x^2) - (\bar{i}{w}_y x y + \bar{j}{w}_x y x))\] + +Запишем L в виде вектора: +\[ + \bar{L} = + \begin{pmatrix} + \sum_{n=1}^{N} m_n(w_{x}y^2 - w_{y}x y) \\ + \sum_{n=1}^{N} m_n(w_{y}x^2 - w_{x}y x) \\ + \end{pmatrix} + \bar{w} = + \begin{pmatrix} + w_{x} \\ + w_{y} \\ + \end{pmatrix} +\] + +то есть, \(\bar{L} = \widehat{J}\bar{w}\). Представляя \(\widehat{J}\) в виде: +\[ +\widehat{J} = \begin{pmatrix} + J_{xx} & J_{xy} \\ + J_{yx} & J_{yy} \\ + \end{pmatrix} +\] + +Получаем: +\[ + \begin{pmatrix} + \sum_{n=1}^{N} m_n(w_{x}y^2 - w_{y}x y) \\ + \sum_{n=1}^{N} m_n(w_{y}x^2 - w_{x}y x) \\ + \end{pmatrix}= + \begin{pmatrix} + J_{xx} & J_{xy} \\ + J_{yx} & J_{yy} \\ + \end{pmatrix} + \begin{pmatrix} + w_{x} \\ + w_{y} \\ + \end{pmatrix} +\] +\[ + \begin{pmatrix} + \sum_{n=1}^{N} m_n(w_{x}y^2 - w_{y}x y) \\ + \sum_{n=1}^{N} m_n(w_{y}x^2 - w_{x}y x) \\ + \end{pmatrix}= + \begin{pmatrix} + J_{xx} w_{x} + J_{xy} w_{y}\\ + J_{yx} w_{x} + J_{yy} w_{y} \\ + \end{pmatrix} +\] +\[ + \begin{pmatrix} + \sum_{n=1}^{N} m_n(w_{x}y^2) - \sum_{n=1}^{N} m_n(w_{y}x y) \\ + \sum_{n=1}^{N} m_n(w_{y}x^2) - \sum_{n=1}^{N} m_n(w_{x}y x) \\ + \end{pmatrix}= + \begin{pmatrix} + J_{xx} w_{x} + J_{xy} w_{y}\\ + J_{yx} w_{x} + J_{yy} w_{y} \\ + \end{pmatrix} +\] + +Тогда компоненты \(\widehat{J}\) можно представить в виде: +\begin{equation*} +\begin{gathered} + J_{xx} = \sum_{n=1}^{N} m_n(y^2)\\ + J_{xy} = -\sum_{n=1}^{N} m_n(xy)\\ + J_{yx} = -\sum_{n=1}^{N} m_n(yx)\\ + J_{yy} = \sum_{n=1}^{N} m_n(x^2)\\ +\end{gathered} +\end{equation*} + +\end{document} + diff --git a/02-dip-lab-02-report.tex b/02-dip-lab-02-report.tex new file mode 100644 index 0000000..eda2742 --- /dev/null +++ b/02-dip-lab-02-report.tex @@ -0,0 +1,510 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../bmstu-preamble} +\input{../fancy-listings-preamble} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% ... работе, номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{2}{Распознавание объекта по цвету}{Цифровая обработка изображений}{}{Большаков В.Э.} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\sloppy +\section{Цель} +Основной целью лабораторной работы является изучение методов распознания объекта по цвету с помощью библиотеки цифровой обработки изображений scikit-image, а также разработка программы распознавания блюд на подносе. +\section{Задание} +\begin{itemize} +\item Подготовить выборку 10 цветных цифровых изображений блюд бауманской столовой (по аналогии с примером). +\item В среде Spyder (сборка Anaconda) на языке Python (3.5 и старше) создать проект и подключить библиотеку scikit-image. +\item Из л.р. 1 взять модуль загрузки цветного цифрового изображения и модуль обработки пикселей. +\item Запрограммировать формулу перевода цветного цифрового изображения в цветовое пространство в соответствии с вариантом (В1: RGB, В2: HSV, В3: CMYK, В4: YUV, В5: Hough Circle+HSV, В6: Hough Circle +HSL) +\item Создать классификацию блюд из цифровых изображений. +\item Для каждого блюда определить цветовые характеристики. Задать распределение значений каждого цвета. +\item Провести эксперимент по распознаванию блюд с визуализацией результатов. +\end{itemize} + +Вариант (по номеру в списке группы) 9, то есть цветовое пространство CMYK. Для распознавания разрешается использовать только цвет. +\section{Теоретическая часть} +\subsection{Цветовое пространство CMYK} +Система CMYK создана и используется для типографической печати. Аббревиатура \textbf{CMYK} означает названия основных красок, использующихся для четырехцветной печати: голубой (Сyan), пурпурный (Мagenta) и жёлтый (Yellow). Буквой К обозначают черную краску (BlacK), позволяющую добиться насыщенного черного цвета при печати. Используется последняя, а не первая буква слова, чтобы не путать CMYK Black и RGB Blue. На рисунке \hrf{pic:cmyk-rgb} показана цветовая палитра CMYK вместе с RGB. +\begin{figure}[H] + \centering + \includegraphics[width=12cm]{02-dip-lab02-cmyk-rgb.png} \caption{Цветовые пространства CMYK и RGB} + \label{pic:cmyk-rgb} +\end{figure} + +\subsection{Особенность формирования цвета} +Каждое из чисел, определяющее цвет в CMYK, представляет собой процент краски данного цвета, составляющей цветовую комбинацию. Например, для получения тёмно-оранжевого цвета следует смешать 30\% голубой краски, 45\% пурпурной краски, 80\% жёлтой краски и 5\% чёрной. Это можно обозначить следующим образом: CMYK(30/45/80/5). + +\subsection{Перевод из RGB в CMYK} +Для того, чтобы перевести пиксель RGB в пиксель CMYK можно применить формулу, описанную на языке Java и представленную в таблице \hrf{code:rgb-cmyk}. +\begin{lstlisting}[language=Java, style=JCodeStyle, caption={Формула перевода из RGB в CMYK}, label={code:rgb-cmyk}] + int black = Math.min(Math.min(255 - red, 255 - green), 255 - blue); + if (black!=255) { + int cyan = (255-red-black)/(255-black); + int magenta = (255-green-black)/(255-black); + int yellow = (255-blue-black)/(255-black); + return new int[] {cyan,magenta,yellow,black}; + } else { + int cyan = 255 - red; + int magenta = 255 - green; + int yellow = 255 - blue; + return new int[] {cyan,magenta,yellow,black}; + } +\end{lstlisting} +Пример полученного изображения с использованием преобразования пикселей представлен на рисунке \hrf{pic:trans}. При преобразовании таким методом исходного изображения (\hrf{pic:trans-rgb}) будет получено изображение не естественных цветов (\hrf{pic:trans-cmyk}). + +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.4\textwidth} + \centering + \includegraphics[width=\textwidth]{02-dip-lab02-trans-rgb.png} + \caption{Исходное изображение в пространстве RGB} + \label{pic:trans-rgb} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.4\textwidth} + \centering + \includegraphics[width=\textwidth]{02-dip-lab02-trans-cmyk.png} + \caption{Преобразованное изображение CMYK} + \label{pic:trans-cmyk} + \end{subfigure} + \caption{Пример попиксельного перевода изображения} + \label{pic:trans} +\end{figure} + +Данные результаты не являются правильными. Для более точного преобразования следует использовать ICC профили, описывающие как должен отображаться цвет на мониторе и бумаге. + +\subsection{Цветовое профилирование} +Для достоверного управления цветом необходимы ICC-совместимые профили всех цветовоспроизводящих устройств. Например, без точного профиля сканера хорошо отсканированное изображение может отображаться в другой программе неправильно из-за различий между алгоритмами отображения, используемыми сканером и программой. Недостоверность цветопередачи может привести к внесению в хорошее изображение ненужных и, возможно, вредных "улучшений". При наличии точного профиля программа, импортирующая изображение, способна скорректировать разницу с устройством и воспроизвести достоверные цвета отсканированного изображения. + +Профили документов описывают конкретное цветовое пространство, используемое в документе. Путем назначения профиля, или пометки документа профилем, приложение определяет фактические цвета документа. Например, запись R = 127, G = 12, B = 107 — это просто набор чисел, которые разные устройства будут отображать по-разному. Однако при пометке цветовым пространством Adobe RGB эти числа определяют фактический цвет или длину световой волны. На рисунке \hrf{pic:icc-profile} представлена назначение профилей ICC. +\begin{figure}[H] + \centering + \includegraphics[width=5cm]{02-dip-lab02-icc-profile.png} + \caption{Пример использования профилей ICC} + \label{pic:icc-profile} +\end{figure} + +При использовании профилей преобразованные изображения получаются более правдоподобными. На рисунке \hrf{pic:icc-trans} представлено такое преобразование, \hrf{pic:icc-trans-rgb} пространство RGB, \hrf{pic:icc-trans-cmyk} пространство CMYK. +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.4\textwidth} + \centering + \includegraphics[width=\textwidth]{02-dip-lab02-trans-rgb.png} + \caption{Исходное изображение в пространстве RGB} + \label{pic:icc-trans-rgb} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.4\textwidth} + \centering + \includegraphics[width=\textwidth]{02-dip-lab02-trans-rgb.png} + \caption{Преобразованное изображение CMYK} + \label{pic:icc-trans-cmyk} + \end{subfigure} + \caption{Пример преобразования с использованием профилей} + \label{pic:icc-trans} +\end{figure} + +\section{Практическая часть} +\subsection{Состав исполняемых файлов} +Программа по распознаванию изображений состоит из двух скриптов: +\begin{itemize} +\item основного скрипта для выполнения программы \code{main.py}; +\item скрипта для обработки изображений \code{colorFoodView.py}. +\end{itemize} + +Основной скрипт для тренировки принимает 2 аргумента для запуска: +\begin{itemize} +\item \code{-c}, файл конфигурации программы в формате json; +\item \code{-f}, файл описывающий блюда и их цвета. +\end{itemize} + +Например, скрипт для запуска тренировки может выглядеть следующим образом: +\begin{lstlisting}[style=CCodeStyle] +main.py -c "./configs.json" -f "./foods.json" +\end{lstlisting} + +\subsection{Конфигурационные файлы} +Для корректной работы программы, ей необходимо передать два файла в формате json: +\begin{enumerate} +\item файл конфигурации (далее \code{config.json}); +\item файл описания блюд (далее \code{food.json}). +\end{enumerate} + +Параметры файла \code{config.json} представлены в таблице \hrf{table:config-json}, а пример заполненного файла в листинге \hrf{code:conf-json}. +\begin{table}[H] + \centering + \begin{tabular}{|l|p{100mm}|} + \hline + Наименование параметра & Описание \\ \hline + \code{RGB_profile} & Путь до профиля ICC RGB описывающего цветовое пространство исходного изображения \\ \hline + \code{CMYK_profile} & Путь до профиля ICC CMYK в чье цветовое пространство должно быть переведено изображение \\ \hline + \code{Path_to_food} & Путь до папки с изображениями \\ \hline + \code{Delta_for_color} & Процент погрешности для пикселей \\ \hline + \code{Color_swap} & Цвет в формате CMYK в который необходимо преобразовать найденные пиксели \\ \hline + \code{Mode} & Режим работы программы. Если режим работы Test, то в консоль будет выводиться количество найденных пикселей для искомого блюда\\ + \hline + \end{tabular} + \caption{Параметры конфигурации} + \label{table:config-json} +\end{table} + +\begin{lstlisting}[language=C,style=CCodeStyle, caption={Пример настроек параметров в программе}, label={code:conf-json}] + { + "RGB_profile": "./AdobeICCProfiles/RGB/AdobeRGB1998.icc", + "CMYK_profile": "./AdobeICCProfiles/CMYK/WebCoatedSWOP2006Grade5.icc", + "Path_to_food": "./WorkFood", + "Delta_for_color": 5, + "Color_swap": [100, 78, 0, 0], + "Mode": "Product" + } +\end{lstlisting} + +Параметры файла \code{food.json} представлены в таблице \hrf{table:food-json}, а пример заполненного файла в листинге \hrf{code:food-json}. Файл описывает список блюд, а именно параметры каждого из элементов списка. +\begin{table}[H] + \centering + \begin{tabular}{|l|p{100mm}|} + \hline + Наименование параметра & Описание \\ \hline + Name & Наименование блюда \\ \hline + CMYK & Пиксели которые описывают данное блюдо \\ \hline + Count & Минимальное количество пикселей, которое должно быть у изображения для того, чтобы можно было говорить о том, что на изображении присутствует искомое блюдо. Данное значение можно получить в тестовом режиме \\ + \hline + \end{tabular} + \caption{Параметры конфигурации} + \label{table:food-json} +\end{table} + +\begin{lstlisting}[language=C,style=CCodeStyle, caption={Пример настроек параметров в программе}, label={code:food-json}] +{ + "Foods": [ + { + "Name": "Банан в шоколаде", + "CMYK": [ + { "C": 23, "M": 29, "Y": 44, "K": 7 }, + { "C": 29, "M": 40, "Y": 57, "K": 11 }, + { "C": 34, "M": 61, "Y": 63, "K": 40 } + ], + "Count": 2000 + }, + { + "Name": "Сосиска", + "CMYK": [ + { "C": 27, "M": 65, "Y": 76, "K": 25 }, + { "C": 14, "M": 47, "Y": 67, "K": 3 }, + { "C": 24, "M": 65, "Y": 85, "K": 20 }, + { "C": 28, "M": 83, "Y": 99, "K": 30 } + ], + "Count": 9000 + }, + //... + ] +} +\end{lstlisting} + +\subsection{Описание алгоритма работы программы} +Алгоритм работы основной программы заключается в загрузке и настройки конфигурации и передаче их в скрипт обработки изображения. После выполнения поиска блюд и перед началом нового цикла работа можно скорректировать \code{json} файлы конфигурации и изменения будут применены без необходимости перезапуска программы. +В скрипте обработки изображения используется следующий алгоритм работы: +\begin{itemize} +\item преобразовать все изображения в цветовое пространство, описанное профилем CMYK; +\item для каждого изображения найти пиксели из выбранного блюда; +\item если пиксель найден, то его цвет меняется на цвет, заданный в настройках; +\item проверяется количество найденных пикселей, если их меньше порогового значения, то изображение отбрасывается; +\item изображения, прошедшие проверку, возвращаются в основную программу для дальнейшей работы. +\end{itemize} + +\subsection{Выборка для тестирования} +Для тестирования была подготовлена выборка из десяти подносов с едой. Каждая картинка была приведена к разрешению 400х300 пикселей. Изначальный размер изображений (более 4000х3000 пикселей) не позволяет добиться приемлемых результатов с использованием только цвета как характеристики для поиска изображений на фото. На рисунке \hrf{pic:food-src} представлена подготовленная для работы выборка. + +\begin{figure}[H] + \centering + \includegraphics[width=3cm]{01-dip-lab02-rgb1.jpg} + \includegraphics[width=3cm]{01-dip-lab02-rgb2.jpg} + \includegraphics[width=3cm]{01-dip-lab02-rgb3.jpg} + \includegraphics[width=3cm]{01-dip-lab02-rgb4.jpg} + \includegraphics[width=3cm]{01-dip-lab02-rgb5.jpg} + \includegraphics[width=3cm]{01-dip-lab02-rgb6.jpg} + \includegraphics[width=3cm]{01-dip-lab02-rgb7.jpg} + \includegraphics[width=3cm]{01-dip-lab02-rgb8.jpg} + \includegraphics[width=3cm]{01-dip-lab02-rgb9.jpg} + \includegraphics[width=3cm]{01-dip-lab02-rgb10.jpg} + \caption{Исходная выборка изображений} + \label{pic:food-src} +\end{figure} + +\subsection{Подготовка данных} +Для анализа изображений на предмет присутствия искомых пикселей они должны быть правильно заданы. Для этого используется скрипт \code{converter.py} преобразующий рабочее изображение в пространство CMYK. В дальнейшем с помощью дополнительного инструментария\footnote{онлайн пикер цвета https://www.ginifab.com/feeds/pms/color\_picker\_from\_image.php}, возможно узнать цвет пикселей в пространстве CMYK и внести в \code{food.json}. + +\section{Результат работы} +\subsection{Листинг} +Исходный код скриптов \code{main.py}, \code{colorFoodView.py} и \code{converter.py} представлены в приложениях \hrf{app:main}, \hrf{app:find} и \hrf{app:conv} соответственно. + +\subsection{Интерфейс и измерения} +Программа использует терминальный текстовый интерфейс для взаимодействия с пользователем. На основе содержания \code{food.json} строятся возможные варианты выбора в основном меню. Предусмотрен контроль ошибок ввода. В результате измерений программа вернет изображения где, по её мнению, присутствуют искомые продукты. Найденные пиксели будут закрашены в заданный в конфигурации цвет. Результат работы для поиска яичницы приведен на рисунке \hrf{pic:result}. + +\begin{figure}[H] + \centering + \includegraphics[width=12cm]{01-dip-lab02-result.png} + \caption{Результат работы программы} + \label{pic:result} +\end{figure} + +\subsection{Ошибки} +В ходе вычислений программа допускает некоторое количество ошибок. Чем качественнее изображение, тем больше шансов что искомый пиксель будет присутствовать на изображении в неожиданных местах. Рабочая выборка подверглась минимальной предварительной обработке и часто в искомую область попадают объекты, не связанные с продуктами, такие как стол или поднос. В таблице \hrf{table:errors} представлены ошибки первого и второго рода для измерений. +\begin{table}[H] + \centering + \begin{tabular}{||r|c|c||} + \hline + \multirow{2}{*}{Результаты} & \multicolumn{2}{c|}{Верная гипотеза} \\ + \cline{2-3} + & H0 & H1 \\ + \hline + H0 & 27 & 36 \\ + \hline + H1 & 0 & 524 \\ + \hline + \end{tabular} + \caption{Ошибка первого и второго рода} + \label{table:errors} +\end{table} +\begin{itemize} +\item [] Ошибка первого рода: $0\%$ +\item [] Ошибка второго рода: $36 / 524 * 200 = 7\%$ +\end{itemize} +Данные результаты легко объяснить. Коэффициенты для срабатывания определения блюда настроены таким образом, чтобы находить блюдо в наборе. И программа хорошо справляется с этой задачей. Ошибки второго рода могут возникнуть, когда цвет блюда очень общий для изображения и срабатывает в нем во многих местах. Таких ситуаций не много, однако они имеют место быть. Основная масса ошибок второго рода отсекаются настраиваемым коэффициентом для каждого блюда. + +\section{Заключение} +В ходе выполнения задания были изучены методы по обработке изображения и работы с цветом. Исходя из результатов тестирования можно сделать вывод, что использование только цвета для поиска объектов на картинке не является достаточным, а подготовке рабочей выборки нужно уделять большое внимание. Разный источник света и разные условия сьемки сильно изменяют цвета, которые можно использовать для идентификации объектов. + +\newpage +\appendix +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Asbuk{subsection}} + +\subsection{Основная программа} +\label{app:main} +\begin{lstlisting}[language=Python,style=PyCodeStyle] +import argparse + +# Парсим аргументы вызова скрипта +import codecs +import json +import sys + +from ColorFoodView import find_food + + +def create_parser(): + parser = argparse.ArgumentParser() + parser.add_argument('-c', '--configs') + parser.add_argument('-f', '--foods') + return parser + + +def menu(foods): + print("Допустимый выбор:") + print("0 : Выход") + i = 1 + for food in foods["Foods"]: + print(i, ":", food["Name"]) + i += 1 + print("Введите команду:") + i -= 1 + while 1: + try: + chose = int(input()) + if 0 > chose or chose > i: + print("Данной команды не существует. Выберите из предложенного набора и попробуйте еще раз.") + continue + return chose + except: + print("Необходимо ввести число соответсвующее вашему выбору. Попробуйте еще раз") + + +# поиск продуктов +def food_name(foods, chose): + return foods["Foods"][chose - 1] + + +namespace = create_parser().parse_args(sys.argv[1:]) + +while 1: + # получение конфигурационных данных + configs = json.loads(codecs.open(namespace.configs, 'r', encoding='utf-8').read()) + # получение данных для справочника продуктов + foods = json.loads(codecs.open(namespace.foods, 'r', encoding='utf-8').read()) + # меню выбора + chose = menu(foods) + if chose == 0: + break + # запрос на поиск продуктов + images_food = find_food(configs, food_name(foods, chose)) + for image in images_food: + image.show() + print("Нажмите любую кнопку чтобы продолжить.") + input() +\end{lstlisting} + +\subsection{Поиск объектов по цвету} +\label{app:find} +\begin{lstlisting}[language=Python,style=PyCodeStyle] +import os + +import re + +from PIL import Image +from PIL.ImageCms import profileToProfile + +color_swap = [0, 0, 0, 255] +delta_for_color = 0 +mode = "Product" + + +# Возвращает список изображений в цветовом пространтстве CMYK +def get_list_cmyk_image(path, rgb_profile, cmyk_profile): + list_image = [] + for d, dirs, files in os.walk(path): # Достаем все каталоги по пути + for f in files: # Достаем все файлы + if re.search(".jpg", f): # Сортировка по типу + path = os.path.join(d, f) # Получаем путь до изображения + im = Image.open(path) + picture_cmyk = profileToProfile(im, rgb_profile, cmyk_profile, outputMode='CMYK') + list_image.append(picture_cmyk) # Добавляем полученное изображение в список + return list_image + + +# переводит список процентов в соответствующее значение [0..255] +def percent_to_scale_list(percent): + list = [] + for p in percent: + list.append(percent_to_scale(p)) + return list + + +# преобразует процент в соответветсвующее значение [0..255] +def percent_to_scale(percent): + return int(percent / 100 * 255) + + +# получение минимум +# значение пикселя - процент погрешности +def get_min(param): + result = param - delta_for_color + if result < 0: + return 0 + else: + return result + + +# получение максимума +# значение пикселя + процент погрешности +def get_max(param): + result = param + delta_for_color + if result > 255: + return 255 + else: + return result + + +# проверка входит ли значение пикселя в заданные границы +def pixel_equal(pixel, mask_pixel): + min_c = get_min(pixel) + max_c = get_max(pixel) + return min_c <= mask_pixel <= max_c + + +# проверка пикселя на соответсвие искомого +def range_equal(pixel, mask_pixel): + c = pixel_equal(pixel[0], mask_pixel[0]) + m = pixel_equal(pixel[1], mask_pixel[1]) + y = pixel_equal(pixel[2], mask_pixel[2]) + k = pixel_equal(pixel[3], mask_pixel[3]) + + if c and m and y and k: + return 1 + else: + return 0 + + +# ищем пиксели из изображения и сравниваем с искомыми +# если поиск был успешен, то заменяем его на заданные в конфигурации цвет +def swap_pixel(image, mask_pixels, color_count): + count = 0 + for i in range(image.width): + for j in range(image.height): + pixel = image.getpixel((i, j)) + for mask_pixel in mask_pixels: + if range_equal(pixel, mask_pixel): + image.putpixel((i, j), tuple(color_swap)) + count += 1 + if mode == "Test": + print(count) + + if count > color_count: + return image + else: + return None + + +# Получение списка пикселей для дальшейшего их поиска в изображении +def get_mask_pixel(food_name): + list_tuple = [] + for pixel in food_name["CMYK"]: + c = percent_to_scale(pixel["C"]) + m = percent_to_scale(pixel["M"]) + y = percent_to_scale(pixel["Y"]) + k = percent_to_scale(pixel["K"]) + list_tuple.append(tuple([c, m, y, k])) + return list_tuple + + +# поиск блюд на изображении +def find_food_on_image(cmyk_image_list, food_name): + list_found_image = [] + for image in cmyk_image_list: + mask_pixel = get_mask_pixel(food_name) + image_swap_pixel = swap_pixel(image, mask_pixel, food_name["Count"]) + if image_swap_pixel is not None: + list_found_image.append(image_swap_pixel) + return list_found_image + + +# точка входа в скрипт, настройка параметров и вызов функций +def find_food(configs, food_name): + global delta_for_color, color_swap, mode + delta_for_color = percent_to_scale(configs["Delta_for_color"]) + color_swap = percent_to_scale_list(configs["Color_swap"]) + mode = configs["Mode"] + cmyk_image_list = get_list_cmyk_image(configs["Path_to_food"], configs["RGB_profile"], configs["CMYK_profile"]) + food_on_image_list = find_food_on_image(cmyk_image_list, food_name) + return food_on_image_list +\end{lstlisting} + +\subsection{Конвертер изображений} +\label{app:conv} +\begin{lstlisting}[language=Python,style=PyCodeStyle] +from PIL import Image +from PIL.ImageCms import profileToProfile + +RGB_profile = "./AdobeICCProfiles/RGB/AdobeRGB1998.icc" +CMYK_profile = "./AdobeICCProfiles/CMYK/WebCoatedSWOP2006Grade5.icc" + +for i in range(1, 11): + image_path = "./WorkFood/" + str(i) + ".jpg" + im = Image.open(image_path) + converted_image = profileToProfile(im, RGB_profile, CMYK_profile, outputMode='CMYK') + converted_image.save("./CMYK_Food/" + str(i) + ".jpg") +\end{lstlisting} + + +\end{document} + diff --git a/02-dip-lab-04-report.tex b/02-dip-lab-04-report.tex new file mode 100644 index 0000000..db1f132 --- /dev/null +++ b/02-dip-lab-04-report.tex @@ -0,0 +1,652 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../bmstu-preamble} +\input{../fancy-listings-preamble} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% ... работе, номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{4}{Разработка программы для классификации изображений с использованием свёрточной нейронной сети}{Цифровая обработка изображений}{}{Большаков В.Э.} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\sloppy +\section{Цель} +Основной целью лабораторной работы является изучение методов распознания объекта с использованием свёрточной нейронной сети (CNN) и определение лучшей архитектуры сети для такого распознавания. +\section{Задание} +\begin{itemize} +\item Подключить библиотеку scikit-learn, tensorflow или pytorch; +\item Дополнить наборы картинок по варианту. Минимум 20 картинок для каждого класса (при неудовлетворительной классификации добавить ещё). Картинки намеренно должны быть схожими; +\item Выбрать реализацию и обучить свёрточную нейронную сеть (CNN) для классификации в соответствии с вариантом; +\item Провести эксперимент по распознаванию изображений с визуализацией результатов; +\item Провести информационный поиск в Интернете. Попробовать несколько вариантов архитектур CNN. Выбрать лучшую архитектуру как минимум из двух. Построить график ошибок первого и второго рода по результатам распознавания; +\item Прислать программу и подготовленные изображения преподавателю; +\item Подготовить и прислать отчет. +\end{itemize} + +Вариант (по номеру в списке группы) 9, то есть «плантан и утёнок». +\section{Теоретическая часть} +\subsection{Свёрточная нейронная сеть} +Сверточная нейронная сеть основана на универсальных математических операциях с матрицами\cite[c. 665]{dsa:cormen}. В общем случае, это последовательное применение операции сложения и/или умножения подматрицы основной матрицы для получения значения свёртки (рис. \hrf{pic:convolution-idea}). Свёртка - это линейное преобразование. + +\begin{figure}[H] + \centering + \def\svgwidth{100mm} + \input{pics/02-dip-04-lab-cnn-idea.pdf_tex} + \caption{Схема преобразвоания матрицы 3х5 в свёртку 1х3} + \label{pic:convolution-idea} +\end{figure} + +Двумерная свертка — это операция для которой формируется ядро, представляющее из себя матрицу весов (weight matrix). Ядро проходит над двумерным изображением, поэлементно выполняя операцию умножения с той частью входных данных, над которой оно сейчас находится, и суммирует все полученные значения в одно, выходное. + +\begin{figure}[H] + \centering + \def\svgwidth{130mm} + \input{pics/02-dip-04-lab-cnn-weight.pdf_tex} + \caption{Добавление к свёртке весов} + \label{pic:convolution-weight} +\end{figure} + +Ядро повторяет эту процедуру с каждой локацией, над которой оно проходит, преобразуя двумерную матрицу в другую, всё ещё двумерную матрицу признаков. Признаки на выходе являются взвешенными суммами признаков на входе, расположенных примерно в том же месте, что и выходной пиксель на входном слое. Независимо от того, попадает ли входной признак в «примерно то же место», он определяется в зависимости от того, находится он в зоне ядра, создающего выходные данные, или нет. Это значит, что размер ядра сверточной нейронной сети определяет количество признаков, которые будут объединены для получения нового признака на выходе. + +Например, имея $5*5=25$ признаков на входе и $3*3=9$ признаков на выходе для стандартного слоя (standard fully connected layer) мы бы имели весовую матрицу $25*9=225$ параметров, а каждый выходной признак являлся бы взвешенной суммой всех признаков на входе. Свертка позволяет произвести такую операцию с всего 9-ю параметрами, ведь каждый признак на выходе получается анализом не каждого признака на входе, а только одного входного, находящегося в «примерно том же месте». + +Часто используемые техники: Padding и Striding. +\paragraph{Padding.} При проходе весовой матрицы по краю изображения, самые крайние пиксели, фактически, обрезаются, преобразуя матрицу признаков размером $5*5$ в матрицу $3*3$. Крайние пиксели никогда не оказываются в центре ядра, потому что тогда ядру не над чем будет проходить за краем. Padding добавляет к краям поддельные пиксели (обычно нулевые). + +\paragraph{Striding.} Часто бывает, что при работе со сверточным слоем, нужно получить выходные данные меньшего размера, чем входные. Идея stride заключается в том, чтобы пропустить некоторые области, над которыми проходит ядро. Шаг 1 означает, что берутся области «через пиксель», то есть, по факту, стандартная свертка. Шаг 2 означает, что берутся области через каждые два пикселя, пропуская все другие области в процессе и уменьшая их количество примерно в два раза, шаг 3 означает пропуск трёх пикселей, сокращая количество в 3 раза и т.д. + +\subsection{Архитектура нейронной сети и обучение} +\label{subsect:arch} +В работе не применяются поддельные пиксели ни в одной из архитектур. Пропускание шагов свёртки также не используется (области анализа следуют без разрывов). Для увеличения количества обучающих примеров была применена \textit{аугментация данных} (добавление шумов, деформация изображения, приближение в случайную точку изображения и произвольный поворот изображений). Пример аугментации приведён на рисунке \hrf{pic:augment}, а код, который деформирует изображения в листинге \hrf{lst:augment}. + +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.45\textwidth} + \centering + \includegraphics[width=\textwidth]{02-dip-04-lab-pic-src.png} + \caption{Исходное изображение} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.45\textwidth} + \centering + \includegraphics[width=\textwidth]{02-dip-04-lab-pic-aug.png} + \caption{Изменённое изображение} + \end{subfigure} + \caption{Аугментация изображений} + \label{pic:augment} +\end{figure} + +\begin{lstlisting}[language=Python,style=PyCodeStyle,label={lst:augment}] +data_augmentation = keras.Sequential( + [ + layers.RandomFlip("horizontal_and_vertical", + input_shape=(img_height, + img_width, + 3)), + layers.RandomRotation(0.3), + layers.RandomZoom(-0.3), + layers.Rescaling(0.3), + ] + ) +\end{lstlisting} + +В обучении всех архитектур, кроме одной, использовались пакеты по 8 изображений, а в единственном случае, 32. Пример изображений внутри пакета из 32 изображений приведён на рисунке \hrf{pic:pack-sample}. + +\begin{figure}[H] + \centering + \includegraphics[width=11cm]{02-dip-04-lab-pack-sample.png} + \caption{Пример пакета для обучения нейросети} + \label{pic:pack-sample} +\end{figure} + +В работе были применены разные архитектуры, обучавшиеся каждая по 1000 эпох. Каждая архитектура включает в себя специальные свёрточные слои и один примитивный слой (обычный персептрон). Структуры нейронных сетей приведены в таблице \hrf{table:arch-diff}. Построенные автоматизированно диаграммы нейронных сетей в приложении \hrf{appendix:architectures}. + +\begin{table}[h!] + \centering + \begin{tabular}{|p{15mm}|p{30mm}|p{40mm}|p{30mm}|p{15mm}|p{15mm}|} + \hline + Номер архитектуры & Метод обучения & Количество нейронов свёрточного слоя & Количество нейронов примитивного слоя & Размер пакета & Эпох \\ [0.5ex] + \hline + 1(\hrf{pic:arch-1}) & ADAM & 16/32/64 & 256 & 8 & 1000 \\ + 2(\hrf{pic:arch-1}) & SGD & 16/32/64 & 256 & 8 & 1000 \\ + 3(\hrf{pic:arch-1}) & ADAM & 16/32/64 & 256 & 32 & 1000 \\ + 4(\hrf{pic:arch-1}) & ADAM & 16/32/64 & 256 & 8 & 10000 \\ + 5(\hrf{pic:arch-5}) & ADAM & 16/32/64/128/64/32 & 256 & 8 & 1000 \\ + 6(\hrf{pic:arch-6}) & ADAM & 32/64/128 & 512 & 8 & 1000 \\ + \hline + \end{tabular} + \caption{Свойства архитектур нейронных сетей, применённых в работе} + \label{table:arch-diff} +\end{table} + +\textbf{SGD (Stochastic Gradient Descent)} - тренировка нейронной сети заключается в подборе параметров (весов модели) таким образом, чтобы минимизировать ошибку нейронной сети на тренировочном наборе. Если значение ошибки нейросети не минимальное, но и незначительно изменяется между эпохами обучения, то алгоритм метода принимает решение об изменении поправок к весам нейронов. + +\textbf{ADAM (ADAptive Moment estimation)} - это алгоритм оптимизации, который можно использовать вместо классической процедуры SGD для итеративного обновления весов сети на основе обучающих данных. SGD поддерживает единую скорость обучения (называемую альфа) для всех обновлений веса, и скорость обучения не изменяется во время тренировки. В то время как в методе Adam скорость обучения поддерживается для каждого веса сети (параметра) и отдельно адаптируется по мере развития обучения. Метод вычисляет индивидуальные адаптивные скорости обучения для различных параметров из оценок первого и второго моментов градиентов. + +Каждая архитектура содержит специальный слой, препятствующий переобучению сети. Такой слой в терминах TensorFlow называется DropOut. Это виртуальный слой, не строгое понятие, некоторая абстракция, между двумя смежными слоями, этому слою передается число от 0 до 1 - вероятность срабатывания. Дропаут представляет собой "выключение" нейрона из смежного слоя (рис. \hrf{pic:dropout}). + +\begin{figure}[H] + \centering + \def\svgwidth{100mm} + \input{pics/02-dip-04-lab-dropout.pdf_tex} + \caption{Принцип работы dropout} + \label{pic:dropout} +\end{figure} + +\section{Практическая часть} +Приложение состоит из набора пресетов свёрточных нейронных сетей, функций создания обучающей и валидационной выборки, терминального интерфейса пользователя и функции тестирования нейросети на наборе изображений из исходного задания. + +\subsection{Пользовательский интерфейс} +Пользовательский интерфейс предполагает выбор количества обучающих эпох и выбор одной из шести архитектур нейронной сети. +\begin{lstlisting}[language=Python,style=PyCodeStyle,caption={Запрос аргументов и настройка нейросети},label={src:learn}] +def create_parser(): + parser = argparse.ArgumentParser() + parser.add_argument('-e', '--epoch') + parser.add_argument('-b', '--batch') + parser.add_argument('-a', '--arch') + parser.add_argument('-m', '--method') + return parser + +namespace = create_parser().parse_args(sys.argv[1:]) + +if __name__ == '__main__': + #Создание и обучение сети + mainFunction(int(namespace.epoch), int(namespace.batch), int(namespace.arch), namespace.method) + +\end{lstlisting} + +\subsection{Архитектуры нейросетей} +В листинге \hrf{src:archpick} приведён пример создания архитектуры свёрточной нейросети и функция выбора архитектуры для дальнейшего применения в приложении. Полностью, функции создания всех архитектур приведены в приложении \hrf{appendix:main}. + +\begin{lstlisting}[language=Python,style=PyCodeStyle,caption={Создание архитектуры по умолчанию},label={src:archpick}] +def DefaultArchitecture(): + return Sequential([ + data_augmentation, + layers.Rescaling(1. / 255, input_shape=(img_height, img_width, 3)), + layers.Conv2D(32, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(64, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(128, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Flatten(), + layers.Dropout(0.2), + layers.Dense(256, activation='relu'), + layers.Dense(num_classes) + ]) + +architectureType = { + 1 : DefaultArchitecture, + 2 : DefaultArchitecture, + 3 : DefaultArchitecture, + 4 : DefaultArchitecture, + 5 : FiveArchitecture, + 6 : SixArchitecture +} + +def GetModelArchitecture(type): + num_classes = len(class_names) + return architectureType[type] +\end{lstlisting} + +\subsection{Обучение} +Для обучения была сформирована выборка из похожих изображений. Формирование более широкой выборки для обучения нейросетей подробно описано в подразделе «\hRf{subsect:arch}». Код, осуществляющий формирование обучающей и валидационной выборки представлен в листинге \hrf{src:learn}. + +\begin{lstlisting}[language=Python,style=PyCodeStyle,caption={Функция создания выборок и функция обучения},label={src:learn}] +def CreateTrainAndValidDataSet(batch_size): + train_ds = tf.keras.utils.image_dataset_from_directory( + data_dir, + validation_split=0.2, + subset="training", + seed=123, + image_size=(img_height, img_width), + batch_size=batch_size) + + val_ds = tf.keras.utils.image_dataset_from_directory( + data_dir, + validation_split=0.2, + subset="validation", + seed=123, + image_size=(img_height, img_width), + batch_size=batch_size) + return [train_ds, val_ds] + +def TrainNetwork(model, train_ds, val_ds, epochs): + return model.fit( + train_ds, + validation_data=val_ds, + epochs=epochs + ) +\end{lstlisting} + +\subsection{Выборка для тестирования} +Для тестирования была использована выборка из задания, показанная на рисунке \hrf{pic:testing-set}. Тестирование нейросети и демонстрация результатов производилось скриптом, представленным в листинге \hrf{src:testing}. Скрипт разбивает исходное изображение на 16 изображений объектов и последовательно классифицирует каждое с последующим выводом результатов на экран. Результаты работы скрипта для каждой из архитектур представлены в разделе \hrf{sec:results}. + +\begin{figure}[H] + \centering + \includegraphics[width=16cm]{01-dip-lab04-testing.jpg} + \caption{Исходная выборка из задания} + \label{pic:testing-set} +\end{figure} + +\begin{lstlisting}[language=Python,style=PyCodeStyle,caption={Разбиение тестовой выборки и классификация},label={src:testing}] +valid_image = PIL.Image.open('plantain_vs_duckling.jpg') +matrix_valid_image = np.array(valid_image) +plt.figure(figsize=(10, 10)) +dx = int(matrix_valid_image.shape[0] / 4) +dy = int(matrix_valid_image.shape[1] / 4) +count = 1 +for j in range(0, matrix_valid_image.shape[1] - dy, dy): + for i in range(0, matrix_valid_image.shape[0] - dx, dx): + ax = plt.subplot(4, 4, count) + plt.imshow(matrix_valid_image[j:j + dy,i:i + dx].astype("uint8")) + plt.axis("off") + count += 1 + +plt.figure(figsize=(10, 10)) +dx = int(matrix_valid_image.shape[0] / 4) +dy = int(matrix_valid_image.shape[1] / 4) +count = 1 +for j in range(0, matrix_valid_image.shape[1] - dy, dy): + for i in range(0, matrix_valid_image.shape[0] - dx, dx): + ax = plt.subplot(4, 4, count) + plt.imshow(matrix_valid_image[j:j + dy, i:i + dx].astype("uint8")) + img = (PIL.Image.fromarray(np.uint8(matrix_valid_image[j:j + dy, i:i + dx]))).resize((img_height, img_width)) + img_array = tf.keras.utils.img_to_array(img) + img_array = tf.expand_dims(img_array, 0) + predictions = model.predict(img_array) + score = tf.nn.softmax(predictions[0]) + plt.title(class_names[np.argmax(score)] + "\nТочность = " + str(int(100 * np.max(score))) + " %") + plt.axis("off") + count += 1 +plt.subplots_adjust(wspace=0.1, hspace=1) +plt.tight_layout() +plt.show() +\end{lstlisting} + +\section{Результат работы} +\label{sec:results} +Нейросети определили на изображениях объекты с некоторой вероятностью. Пример результата работы нейросети для первой архитектуры представлен в таблице \hrf{table:results} + +\begin{table}[H] + \centering + \begin{tabular}{|c|c|c|c|} + \hline + Номер & Изображено & Попадание & Точность \\ [0.5ex] + \hline + 1 & Плантан & да & 100 \\ + 2 & Утёнок & да & 99 \\ + 3 & Плантан & да & 100 \\ + 4 & Утёнок & да & 100 \\ + 5 & Плантан & да & 100 \\ + 6 & Плантан & нет & 88 \\ + 7 & Утёнок & да & 100 \\ + 8 & Плантан & да & 100 \\ + 9 & Утёнок & да & 100 \\ + 10 & Утёнок & да & 99 \\ + 11 & Плантан & да & 99 \\ + 12 & Плантан & нет & 99 \\ + 13 & Плантан & да & 100 \\ + 14 & Утёнок & да & 100 \\ + 15 & Плантан & нет & 100 \\ + 16 & Утёнок & да & 99 \\ + \hline + \end{tabular} + \caption{Результат работы нейросети №1} + \label{table:results} +\end{table} + +В результате классификации (после обучения и тестирования) были получены данные представленные на рисунке \hrf{pic:net-test}. Графики процессов обучения (наличие ошибок и точность классификации представлены в приложении \hrf{appendix:graphics}) + +\begin{figure}[H] + \centering + \includegraphics[width=12cm]{02-dip-04-lab-1network-valid.png} + \caption{Результаты классификации изображений нейронной сетью} + \label{pic:net-test} +\end{figure} + +\subsection{Ошибки} +В результате работы нейросетями были допущены ошибки первого и второго рода (ложноположительные и ложноотрицательные заключения). Ошибка первого рода ($\alpha$-ошибка) - это ситуация, когда отвергнута верная гипотеза, а ошибка второго рода ($\beta$-ошибка) - это ситуация, когда принята неверная гипотеза. Можно предположить, что неуверенность (ниже 98\%) сети в верном результате классификации - это ошибка первого рода, а некорректная классификация с любым уровнем точности - ошибка второго рода. Такие допущения введены из-за малого размера обучающих наборов. Сводная таблица \hrf{table:mistakes} содержит результаты классификации изображений, а результаты работы каждой сети представлены в приложении \hrf{appendix:result-pics}. + +\begin{table}[H] + \centering + \begin{tabular}{|c|c|c|} + \hline + Архитектура & $\alpha$-ошибки & $\beta$-ошибка \\ + \hline + 1 & 0/16 & 3/16 \\ + 2 & 2/16 & 1/16 \\ + 3 & 8/16 & 2/16 \\ + 4 & 1/16 & 1/16 \\ + 5 & 4/16 & 2/16 \\ + 6 & 1/16 & 2/16 \\ + \hline + \end{tabular} + \caption{Сводная таблица ошибок} + \label{table:mistakes} +\end{table} +\section{Заключение} +В ходе выполнения задания были изучены принципы работы CNN и их основные архитектуры. Исходя из результатов тестирования можно сделать вывод, что использование небольших датасетов для обучения является основной проблемой для распознавания изображений, то есть при достаточном расширении обучающей выборки или увеличении количества эпох нейросеть можно обучить для достаточно точного определения объекта на изображении. + +\newpage +\printbibliography[heading=bibintoc, title={Список литературы}, resetnumbers=1] + +\newpage +\appendix +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Asbuk{subsection}} + +\subsection{Полный текст программы} +\label{appendix:main} +\begin{lstlisting}[language=Python,style=PyCodeStyle] +import argparse +import codecs +import pathlib +import sys + +import PIL +import matplotlib.pyplot as plt +import numpy as np +import tensorflow as tf +from tensorflow import keras +from tensorflow.keras import layers +from tensorflow.keras.models import Sequential + +img_height = 180 +img_width = 180 +data_dir = pathlib.Path("dataset") + +data_augmentation = keras.Sequential( + [ + layers.RandomFlip("horizontal_and_vertical", + input_shape=(img_height, + img_width, + 3)), + layers.RandomRotation(0.1), + layers.RandomZoom(-0.1), + layers.Rescaling(0.1), + ] +) +def TrainNetwork(model, train_ds, val_ds, epochs): + return model.fit( + train_ds, + validation_data=val_ds, + epochs=epochs + ) + +def CreateTrainAndValidDataSet(batch_size): + train_ds = tf.keras.utils.image_dataset_from_directory( + data_dir, + validation_split=0.2, + subset="training", + seed=123, + image_size=(img_height, img_width), + batch_size=batch_size) + + val_ds = tf.keras.utils.image_dataset_from_directory( + data_dir, + validation_split=0.2, + subset="validation", + seed=123, + image_size=(img_height, img_width), + batch_size=batch_size) + global class_names + class_names = train_ds.class_names + return [train_ds, val_ds] + +def CompileMoment(model, optimaizer): + model.compile(optimizer=optimaizer, + loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), + metrics=['accuracy']) + +def GetModelArchitecture(type): + global num_classes + num_classes = len(class_names) + return architectureType[type]() + +def DefaultArchitecture(): + + return Sequential([ + data_augmentation, + layers.Rescaling(1. / 255, input_shape=(img_height, img_width, 3)), + layers.Conv2D(32, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(64, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(128, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Flatten(), + layers.Dropout(0.2), + layers.Dense(256, activation='relu'), + layers.Dense(num_classes) + ]) + +def FiveArchitecture(): + return Sequential([ + data_augmentation, + layers.Rescaling(1. / 255, input_shape=(img_height, img_width, 3)), + layers.Conv2D(64, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(128, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(256, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(128, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(64, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Flatten(), + layers.Dropout(0.2), + layers.Dense(256, activation='relu'), + layers.Dense(num_classes) + ]) + +def SixArchitecture(): + return Sequential([ + data_augmentation, + layers.Rescaling(1. / 255, input_shape=(img_height, img_width, 3)), + layers.Conv2D(128, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(256, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(512, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Flatten(), + layers.Dropout(0.2), + layers.Dense(512, activation='relu'), + layers.Dense(num_classes) + ]) + +architectureType = { + 1 : DefaultArchitecture, + 2 : DefaultArchitecture, + 3 : DefaultArchitecture, + 4 : DefaultArchitecture, + 5 : FiveArchitecture, + 6 : SixArchitecture +} + +def create_parser(): + parser = argparse.ArgumentParser() + parser.add_argument('-e', '--epoch') + parser.add_argument('-b', '--batch') + parser.add_argument('-a', '--arch') + parser.add_argument('-m', '--method') + return parser + +namespace = create_parser().parse_args(sys.argv[1:]) + +def mainFunction(epoch, batch_size, modelType, optimaizeMethod): + image_count = len(list(data_dir.glob('*/*.jpg'))) + print("Всего изображений = " + str(image_count)) + + #Передаем размер пакета + train_ds, val_ds = CreateTrainAndValidDataSet(batch_size) + + AUTOTUNE = tf.data.AUTOTUNE + + train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE) + val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE) + + #Модель из предкомпелированных + model = GetModelArchitecture(modelType) + + CompileMoment(model, optimaizeMethod) + + history = TrainNetwork(model, train_ds, val_ds, epoch) + + acc = history.history['accuracy'] + val_acc = history.history['val_accuracy'] + + loss = history.history['loss'] + val_loss = history.history['val_loss'] + + epochs_range = range(epoch) + + plt.figure(figsize=(8, 8)) + plt.subplot(1, 2, 1) + plt.plot(epochs_range, acc, label='Точность на тренировочной выборке') + plt.plot(epochs_range, val_acc, label='Точность на контрольной выборке') + plt.legend(loc='lower right') + plt.title('Точности на тренировочной и контрольной выборке') + + plt.subplot(1, 2, 2) + plt.plot(epochs_range, loss, label='Ошибка на тренировочной выборке') + plt.plot(epochs_range, val_loss, label='Ошибка на контрольной выборке') + plt.legend(loc='upper right') + plt.title('Ошибки на обучающей и контрольной выборках') + plt.show() + + valid_image = PIL.Image.open('plantain_vs_duckling.jpg') + + matrix_valid_image = np.array(valid_image) + plt.figure(figsize=(10, 10)) + dx = int(matrix_valid_image.shape[0] / 4) + dy = int(matrix_valid_image.shape[1] / 4) + count = 1 + for j in range(0, matrix_valid_image.shape[1] - dy, dy): + for i in range(0, matrix_valid_image.shape[0] - dx, dx): + ax = plt.subplot(4, 4, count) + plt.imshow(matrix_valid_image[j:j + dy, i:i + dx].astype("uint8")) + img = (PIL.Image.fromarray(np.uint8(matrix_valid_image[j:j + dy, i:i + dx]))).resize((img_height, img_width)) + img_array = tf.keras.utils.img_to_array(img) + img_array = tf.expand_dims(img_array, 0) + predictions = model.predict(img_array) + score = tf.nn.softmax(predictions[0]) + plt.title(class_names[np.argmax(score)] + "\nТочность = " + str(int(100 * np.max(score))) + " %") + plt.axis("off") + count += 1 + plt.subplots_adjust(wspace=0.1, hspace=1) + plt.tight_layout() + plt.show() + + +if __name__ == '__main__': + #Создание и обучение сети + mainFunction(int(namespace.epoch), int(namespace.batch), int(namespace.arch), namespace.method) +\end{lstlisting} + +\subsection{Архитектуры применённых нейросетей} +\label{appendix:architectures} + +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.3\textwidth} + \centering + \includegraphics[width=\textwidth]{02-dip-04-lab-1network-arch.png} + \caption{Нейросеть для 1, 2, 3 и 4 случая} + \label{pic:arch-1} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.3\textwidth} + \centering + \includegraphics[width=\textwidth]{02-dip-04-lab-5network-arch.png} + \caption{Нейросеть 5} + \label{pic:arch-5} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.3\textwidth} + \centering + \includegraphics[width=\textwidth]{02-dip-04-lab-6network-arch.png} + \caption{Нейросеть 6} + \label{pic:arch-6} + \end{subfigure} + \caption{Стандартная визуализация архитектур пакета TensorFlow} + \label{pic:architectures} +\end{figure} + +\subsection{Графики обучения нейросетей} +\label{appendix:graphics} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-1network.png} + \caption{Графики обучения сети №1} +\end{figure} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-2network.png} + \caption{Графики обучения сети №2} +\end{figure} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-3network.png} + \caption{Графики обучения сети №3} +\end{figure} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-4network.png} + \caption{Графики обучения сети №4} +\end{figure} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-5network.png} + \caption{Графики обучения сети №5} +\end{figure} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-6network.png} + \caption{Графики обучения сети №6} +\end{figure} + +\subsection{Результаты классификации изображений} +\label{appendix:result-pics} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-1network-valid.png} + \caption{Классификация сетью №1} +\end{figure} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-2network-valid.png} + \caption{Классификация сетью №2} +\end{figure} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-3network-valid.png} + \caption{Классификация сетью №3} +\end{figure} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-4network-valid.png} + \caption{Классификация сетью №4} +\end{figure} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-5network-valid.png} + \caption{Классификация сетью №5} +\end{figure} + +\begin{figure}[H] + \includegraphics[width=17cm]{02-dip-04-lab-6network-valid.png} + \caption{Классификация сетью №6} +\end{figure} + +\end{document} diff --git a/02-dspmd-01-hw-report.tex b/02-dspmd-01-hw-report.tex new file mode 100644 index 0000000..b5d9921 --- /dev/null +++ b/02-dspmd-01-hw-report.tex @@ -0,0 +1,263 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../bmstu-preamble} +\input{../fancy-listings-preamble} +\numerationTop + +\titlespacing*{\section}{\parindent}{1ex}{1em} + +\setlength{\parindent}{4pc} % exaggerated for the example + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader +\captionsetup[tabular]{labelsep=space, + justification=raggedright, singlelinecheck=off} + +\makeReportTitle{домашней}{1}{Команды микропроцессора}{Микропроцессорные устройства обработки сигналов}{}{проф. каф. ИУЗ, д.т.н. \\В.С. Выхованец} +\newpage +\thispagestyle{empty} +\tableofcontents +\addtocontents{toc}{\vspace{2ex}} % 6.2.3 В элементе «Содержание» номера подразделов приводят после абзацного отступа, равного двум знакам, относительно номеров разделов. +\newpage +\pagestyle{fancy} +\section{Задача} +Целью выполнения домашнего задания является изучение архитектуры и организации микропроцессора и выбор методов и средств реализации низкоуровневой функции, заданной в теме домашнего задания. + +\textbf{Темой домашнего задания} является умножение и сложение с насыщением и округлением: \code{long \_smacr(long src1, int src2, int src3)}. + +Выполнение задания разделено на следующие этапы: +\begin{enumerate}[label=\arabic*),ref=\arabic*] +\item ознакомление с методическим материалом, учебным пособием \cite[с. 6-68]{dsp:lectures} и технической документацией \cite{ti:dsp-mnemonics}, поиск и изучение команд микропроцессора, позволяющих эффективно реализовать заданную функцию; +\item описание найденных команд и их настройка для реализации разрабатываемой низкоуровневой функции; +\item описание методики разработки низкоуровневой функции. +\end{enumerate} + +\section{Выполнение} +Для выполнения домашнего задания необходимо: +\begin{itemize} +\item ознакомиться с рекомендованной литературой; +\item разработать и описать алгоритм решения задачи; +\item найти и изучить команды микропроцессора, необходимые для решения задачи; +\item подготовить тестовые данные для проверки реализации алгоритма; +\item оформить\cite{gost:texts} отчет\cite{gost:links} по домашнему заданию\cite{bmstu:dsp-methodics1}. +\end{itemize} +Основным результатом домашнего задания является методика разработки низкоуровневой функции для умножения и сложения с насыщением и округлением. + +\subsection{Описание алгоритма низкоуровневой функции} +В микропроцессоре используется арифметика с фиксированной запятой, поэтому умножение дробных и целых чисел производится по одному и тому же принципу, представленному в общем виде формулами +\begin{equation} + \begin{gathered} + X_{Q1.15} = -s_x + 2^{-15} \sum_{i=0}^{14} x_i \cdot 2^i, Y_{Q1.15} = -s_y + 2^{-15} \sum_{i=0}^{14} y_i \cdot 2^i, \\ + Z = 2^{-30} \big( -s_x + 2^{15} \sum_{i=0}^{14} x_i \cdot 2^i\big) \big( -s_y + 2^{15} \sum_{i=0}^{14} y_i \cdot 2^i \big), \\ + Z = 2^{-30}(X_{Z16} \cdot Y_{Z16}) = 2^{-30} Z_{Z32}, Z_{Q1.31} = 2 \cdot Z, \\ + Z_{Q1.31} = -s_Z + 2^{-31} \sum_{i=0}^{30} z_i \cdot 2^i, \\ + Z_{Q1.31} = Z_{Z32} < < 1, \\ + Z_{Q1.15} = Z_{Z32} > > 15, + \end{gathered} + \label{math:multiply} +\end{equation} +где $ X_{Q1.15} $ - первый операнд в формате Q1.15, $ Y_{Q1.15} $ - второй операнд в формате Q1.15, $ Z_{Q1.15} $ - результат вычислений в формате Q1.15, $-s_x$ - старший разряд первого операнда, обозначающий знак числа, $ x_i$ - каждый следующий разряд первого операнда, $-s_y$ - старший разряд второго операнда, обозначающий знак числа, $ y_i$ - каждый следующий разряд второго операнда. Таким образом для получения корректного результат умножения двух чисел в формате Q1.15 необходимо отсечь от полученного 32-разрядного результата младшие 15 разрядов, предварительно удалив самый старший разряд. + +Насыщение - это процесс для операций с фиксированной запятой, при котором происходит преобразование результата умножения на максимально возможное представимое число. При отрицательном результате происходит замена на самое маленькое представимое число (например, \code{0xFF80000000} – минимальное число в Q1.31), а при положительном - на самое большое доступное (например, \code{0x007FFFFFFF} – максимальное число в Q1.31). Пример насыщения в таблице \hrf{table:saturation} демонстрирует также разницу двоичных представлений чисел разной разрядности. +\begin{table}[H] + \captionsetup{labelsep=endash} + \centering + \caption{Пример насыщения} + \label{table:saturation} + \begin{tabular}{|lclcl|} + \hline + Q9.31 & & & & Q1.31 \\ [0.5ex] + 0xFE80\_0000\_09 & & & $\neq$ & 0x80\_0000\_09 \\ + 0x0180\_0000\_09 & & & $\neq$ & 0x80\_0000\_09 \\ + 0xFE80\_0000\_09 & $\approx$ & 0xFF80\_0000\_09 & = & 0x80\_0000\_00 \\ + 0x0180\_0000\_09 & $\approx$ & 0x007F\_FFFF\_FF & = & 0x7F\_FFFF\_FF \\ + \hline + \end{tabular} +\end{table} + + +\subsection{Прототип низкоуровневой функции} +Согласно документации \cite[с. 77 (3-33)]{ti:dsp-prog-guide}, прототип низкоуровневой функции и описание аргументов функции на языке Си имеют вид, представленный в таблице \hrf{table:prototype}. + +\begin{table}[H] + \captionsetup{labelsep=endash} + \centering + \caption{Прототип и описание действия функции} + \label{table:prototype} + \begin{tabular}{|p{55mm}|p{110mm}|} + \hline + Прототип функции & Верхнеуровневое описание \\ [3ex] + \hline + \multirow{2}{54mm}{\code{long \_smacr(long src, int op1, int op2)}} & Функция осуществляет умножение операторов \code{op1} и \code{op2}, сдвиг полученного результата влево на один разряд, складывает результат со значением параметра \code{src}, округляет результат, добавляя число 215 и присваивает значение 0 в младшие 16 разрядов, (устанавливаются биты SATD, SMUL и FRCT).\\ + \hline + \end{tabular} +\end{table} + +Параметры функции в таблице \hrf{table:prototype} имеют типы \code{long} и \code{int}, то есть представлены в формате Q1.15 и Q1.31, соответственно. Двоичные представления чисел в данных форматах \cite{dsp:lectures} представлены в таблицах \hrf{table:qbin-15} и \hrf{table:qbin-31} соответственно. + +\begin{table}[H] + \captionsetup{labelsep=endash} + \setlength\tabcolsep{1.5pt} + \centering + \caption{Формат представления чисел с фиксированной запятой (Q1.15)} + \label{table:qbin-15} + \begin{tabular}{|c|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|} + \multirow{3}{*}{Q1.15} & $2^{0}$ & $2^{-1}$ & $2^{-2}$ & $2^{-3}$ & $2^{-4}$ & $2^{-5}$ & $2^{-6}$ & $2^{-7}$ & $2^{-8}$ & $2^{-9}$ & $2^{-10}$ & $2^{-11}$ & $2^{-12}$ & $2^{-13}$ & $2^{-14}$ & $2^{-15}$ \\ + &$15$ & $14$ & $13$ & $12$ & $11$ & $10$ & $9$ & $8$ & $7$ & $6$ & $5$ & $4$ & $3$ & $2$ & $1$ & $0$ \\ + \cline{2-17} + &S & X & X & X & X & X & X & X & X & X & X & X & X & X & X & X \\ + \hline + \end{tabular} +\end{table} + +\begin{table}[H] + \captionsetup{labelsep=endash} + \setlength\tabcolsep{1.5pt} + \centering + \caption{Формат представления чисел с фиксированной запятой (Q1.31)} + \label{table:qbin-31} + \begin{tabular}{|c|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|} + \multirow{3}{*}{Q1.31} & $2^{0}$ & $2^{-1}$ & $2^{-2}$ & $2^{-3}$ & $2^{-4}$ & $2^{-5}$ & $2^{-6}$ & $2^{-7}$ & $2^{-8}$ & $2^{-9}$ & $2^{-10}$ & $2^{-11}$ & . . . & $2^{-25}$ & $2^{-26}$ & $2^{-27}$ & $2^{-28}$ & $2^{-29}$ & $2^{-30}$ & $2^{-31}$\\ + & $31$ & $30$ & $29$ & $28$ & $27$ & $26$ & $25$ & $24$ & $23$ & $22$ & $21$ & $20$ & . . . & $6$ & $5$ & $4$ & $3$ & $2$ & $1$ & $0$ \\ + \cline{2-21} + & S & X & X & X & X & X & X & X & X & X & X & X & . . . & X & X & X & X & X & X & X\\ + \hline + \end{tabular} +\end{table} + +Для очищения младших 16ти разрядов может быть использована макрокоманда\cite[стр. 138]{ti:dsp-c-compiler}, представленная в листинге \hrf{lst:macros}. +\begin{lstlisting}[language=C,style=CCodeStyle,caption={Макрокоманда, очищающая младшие разряды},label={lst:macros}] +#define mac_r(a,b,c) (short)(_smacr((a),(b),(c)) >> 16) +\end{lstlisting} + +\subsection{Передача аргументов и возврат результата} +При вызове функции на языке Си, передача значений аргументов осуществляется в регистры и на стек по следующим правилам \cite[с. 125]{ti:dsp-c-compiler}: +\begin{itemize} +\item для функций, объявленных с переменным числом не типизированных аргументов, последний явно объявленный аргумент помещается на стек, за ним следуют оставшиеся аргументы, адрес этого аргумента может быть использован как ссылка для доступа к неявно переданным аргументам; +\item структура из двух слов или менее рассматриваются как 32-разрядный аргумент; +\item структура из более, чем двух слов передаётся по ссылке, компилятор передаст адрес структуры как указатель; +\item в основном, когда аргумент передаётся в функцию, компилятор присваивает его определённому классу и помещает в регистр (если доступен), согласно класса. Компилятор использует три класса: + \begin{enumerate}[label=\arabic*),ref=\arabic*] + \item 24-разрядный указатель на данные (\code{int*}, \code{long*}, и так далее); + \item 16-разрядные данные (\code{char}, \code{short}, \code{int}); + \item 32-разрядные данные (\code{long}, \code{float}, \code{double}, указатель на функцию). + \end{enumerate} +Если аргумент является указателем на любой тип данных, он считается указателем на данные. Если аргумент может быть помещён в 16-разрядный регистр, он считается 16-разрядными данными. Во всех остальных случаях данные считаются 32-разрядными. 40-разрядные данные передаются с использованием всего регистра, а не только его младших 32 разрядов. +\end{itemize} + +Аргументы передаются в регистры в порядке, в котором они указаны в прототипе функции и помещаются, согласно класса, в следующие регистры: +\begin{itemize} +\item 24-разрядный указатель в регистрах \code{(X)AR0}, \code{(X)AR1}, \code{(X)AR2}, \code{(X)AR3} и \code{(X)AR4}; +\item 16-разрядные данные в регистрах \code{T0}, \code{T1}, \code{AR0}, \code{AR1}, \code{AR2}, \code{AR3}, \code{AR4}; +\item 32- или 40-разрядные данные в регистрах \code{AC0}, \code{AC1}, \code{AC2}. +\end{itemize} + +Если доступные регистры для размещения аргументов отсутствуют, то не поместившиеся аргументы помещаются на стек. Стек по умолчанию выровнен по чётной границе. Затем каждый аргумент выравнивается на стеке согласно его класса. В случае необходимости вставляются пустоты для дополнительного выравнивания аргументов. + +В ячейке \code{*SP(0)} размещается адрес возврата из функции, в \code{*SP(1)} – 1-й аргумент функции, не поместившийся в регистрах, и т.д., где \code{SP} – это указатель стека операндов, а в круглых скобках указано смещение относительно этого указателя в двойных словах. + +Возврат результата выполнения функции осуществляется через регистры: +\begin{itemize} +\item данные разрядностью 16 бит размещаются в регистре \code{T0}; +\item данные разрядностью 32 или 40 бита размещаются в регистре \code{AC0}; +\item указатели разрядностью 24 бит размещаются в регистре \code{(X)AR0}; +\item структура длиной более 32 бит возвращается через первый аргумент +\item функции – указатель на структуру, если он \code{0x0}, то структура не возвращается. +\end{itemize} + +Вызываемая функция при использовании должна сохранять и восстанавливать регистры \code{T2}, \code{T3}, \code{(X)AR5}, \code{(X)AR6} и \code{(X)AR7}, а регистры \code{T0}, \code{T1}, \code{(X)AR0}, \code{(X)AR1}, \code{(X)AR2}, \code{(X)AR3}, \code{(X)AR4}, \code{AC0}, \code{AC1}, \code{AC2}, \code{AC3} может использовать без сохранения. Все другие специальные регистры микропроцессора при использовании подлежат обязательному сохранению и восстановлению, а именно: \code{RETA}, \code{BKx}, \code{BRCx}, \code{BRS1}, \code{BSAx}, \code{RSAx}, \code{REAx}, \code{RPTC}, \code{CSR}, \code{TRNx}, \code{(X)DP}, \code{(X)CDP}, \code{STx\_55}, где вместо \code{x} подставляется номер соответствующего регистра. + +Сохранение регистров производится в автоматической (локальной) памяти функции, выделяемой на стеке перед адресом возврата путем уменьшения указателя стека SP на число двойных слов выделяемой памяти. Локальная память освобождается перед возвратом из функции путем увеличения указателя стека SP на число выделенных двойных слов. После выделения локальной памяти доступ к аргументам осуществляется с учетом длины выделенной памяти. Например, после выделения двух двойных слов адрес возврата из функции может быть адресован как \code{*SP(2)}, первый аргумент в стеке – как \code{*SP(3)}, и т.д. + +Очистку стека с аргументами производит вызывающая функция после вызова вызываемой. В соответствии с вышеописанным для функции с прототипом, указанным в таблице \hrf{table:prototype} аргументы размещаются в порядке следования в регистрах \code{AC0}, \code{T0} и \code{T1}, а результат будет помещён в регистр \code{AC0}. Стек для размещения аргументов не используется. + +\subsection{Описание и форматы команд микропроцессора} +Из документации на компилятор\cite[с. 134]{ti:dsp-c-compiler} получены следующие сведения: функция устанавливает биты (флаги) \code{SATD}\footnote{Saturation Mode (D unit)}, \code{SMUL}\footnote{Saturation-on-multiplication mode}, \code{FRCT}\footnote{Fractional mode (fixed-point mathematics in C)}. Возвращает насыщенную сумму \code{src} и fractional-mode произведение параметров \code{op1} и \code{op2}. Сумма округляется так, как если бы была вызвана функция \code{_sround}\cite[с. 136]{ti:dsp-c-compiler}. +%\footnote{Returns the value \code{src} rounded by adding $2^{15}$ using saturating arithmetic (biased round to positive infinity) and clearing the lower 16 bits. The upper 16 bits of the Q31 result can be treated as a Q15 value.}. + +\subsubsection{Выбор команд} +В наборе команд микропроцессора TMS320C55x \cite{ti:dsp-mnemonics} имеется команда, позволяющая реализовать умножение с насыщением и округлением. \code{MAC} – данная инструкция выполняет умножение и суммирование. +\subsubsection{Синтаксис команд} +Команда MAC имеет следующий синтаксис \cite[с. 273]{ti:dsp-mnemonics}: +\begin{center} \code{MAC[R] ACx, Tx, ACy[, ACy]},\end{center} +где MAC – мнемоника команды умножения со сложением, R – признак округления результата операции, Tx - 16-разрядные регистры T0, T1, ACx и ACy – регистр аккумулятор AC0-AC3. + +Необязательный параметр (5) заключён в квадратные скобки. +\subsubsection{Операции команд} +Эта инструкция выполняет умножение и сложение. Входящие операнды умножителя ACx(32−16) и значение Tx знаково расширяются до 17 битов по формуле (\hrf{eq:expanding}) +\begin{equation} + ACy = ACy + (ACx * Tx). + \label{eq:expanding} +\end{equation} +Команда работает со следующими особенностями: +\begin{itemize} +\item если выставлен флаг \textbf{FRCT}, вывод умножителя сдвигается влево на один разряд; +\item обнаружение переполнения при умножении зависит от флага \textbf{SMUL}; +\item 32-разрядный результат умножения знаково расширяется до 40 бит и добавляется к аккумулятору-источнику \textbf{ACy}; +\item округление производится согласно \textbf{RDM}, если к инструкции применяется необязательное ключевое слово \textbf{R}; +\item обнаружение переполнения при сложении зависит от \textbf{M40}. Если обнаружено переполнение, конечный аккумулятор выставляет статусный бит \textbf{ACOVy}; +\item когда обнаруживается переполнение при сложении, аккумулятор насыщается согласно \textbf{SATD}. +\end{itemize} +\subsubsection{Форматы команд} +Команда \code{MAC[R] ACx, Tx, ACy[, ACy]} имеет следующий формат (opcode): + +\begin{center} \verb|0101011E DDSSss0%| \end{center} +где двоичными цифрами показаны поля кодов команд \cite[с. 779-788]{ti:dsp-mnemonics}, DD – поле регистра-аккумулятора ACy, SS – поле регистра-аккумулятора ACx, ss – поле временного регистра-источника, \% – поле округления. + +Двухразрядное поле регистра-аккумулятора DD кодируется следующим образом: +\begin{itemize} +\item 00 – регистр-аккумулятор AC0; +\item 01 – регистр-аккумулятор AC1; +\item 10 – регистр-аккумулятор AC2; +\item 11 – регистр-аккумулятор AC3. +\end{itemize} + +Двухразрядное поле регистра-аккумулятора SS (ACw, ACx, ACy, ACz) кодируется следующим образом: +\begin{itemize} +\item 00 – регистр-аккумулятор AC0; +\item 01 – регистр-аккумулятор AC1; +\item 10 – регистр-аккумулятор AC2; +\item 11 – регистр-аккумулятор AC3. +\end{itemize} + +Двухразрядное поле временного регистра-источника ss (Tx, Ty) кодируется следующим образом: +\begin{itemize} +\item 00 – временный регистр T0; +\item 01 – временный регистр T1; +\item 10 – временный регистр T2; +\item 11 – временный регистр T3. +\end{itemize} + +\subsection{Методика разработки функции} +Входными операндами команд, выполняемых умножителями-аккумуляторами \cite[с. 30]{dsp:lectures}, могут быть (рисунок \hrf{pic:mac}): +\begin{itemize} +\item 17 разрядов регистров аккумуляторов AC0-AC3 (с 32 до 15); +\item числа во временных регистрах T0-T3, расширенные до 17 разрядов; +\item константы из кода команд, расширенные до 17 разрядов; +\item содержимое 16-разрядной ячеек памяти, расширенное до 17 разрядов. +\end{itemize} +\begin{figure}[H] + \centering + \includegraphics[height=5cm]{01lab-rpt-mac.png} + \caption{Умножение с накоплением} + \label{pic:mac} +\end{figure} +Умножение с накоплением чисел разной разрядности происходит как показано на рисунке \hrf{pic:mac}. Для повторения этого действия в самостоятельно написанной функции необходимо переместить параметр, переданный в регистре \code{T0} в регистр большей разрядности \code{AC1} (строка \hrf{line:moving-to-hi}). Также необходимо выставить флаги работы с дробными числами и насыщения (строки \hrf{line:frac} и \hrf{line:satd}), предварительно сохранив на стеке старое значение регистра статуса \code{ST1_55}\cite[с. 614]{ti:dsp-mnemonics}. Такое поведение описано в полном листинге ассемблерной команды (\hrf{code:prog-asm}). + +\begin{lstlisting}[style=ASMStyle,caption={Описание функции на языке ассемблера}, label={code:prog-asm}] +_my_smacr: + PSH mmap(ST1_55) + BSET FRCT <@\label{line:frac}@> + BSET SATD <@\label{line:satd}@> + MOV T1,HI(AC1) <@\label{line:moving-to-hi}@> + MACR AC1, T0, AC0 + POP mmap(ST1_55) + RET +\end{lstlisting} + +\newpage +\printbibliography[heading=bibintoc, title={Список литературы}, resetnumbers=1] + +\end{document} diff --git a/02-dspmd-01-lab-report.tex b/02-dspmd-01-lab-report.tex new file mode 100644 index 0000000..c40b721 --- /dev/null +++ b/02-dspmd-01-lab-report.tex @@ -0,0 +1,140 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../bmstu-preamble} +\input{../fancy-listings-preamble} +\setcounter{secnumdepth}{0} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% ... работе, номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{1}{Исследование команд обработки сигналов}{Микропроцессорные устройства обработки сигналов}{}{А.И. Германчук} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель} +Целью лабораторной работы является знакомство с интегрированной средой разработки программ Code Composer Studio (CCS) компании Texas Instruments. Лабораторная работа заключается в написании в соответствие с выданным индивидуальным заданием текстов несложных программ на языке C и ассемблера, создании нового проекта в CCS, компиляции и отладке разработанных программ с помощью симулятора микропроцессора TMS320C5515 или оценочной платы TMS320C5515 DSP Evaluation Module (TMDXEVM5515). + +\section{Выполнение} +Индивидуальным заданием было написание функции умножения и сложения с насыщением и округлением: \code{long _smacr(long src1, int src2, int src3)}. В учебном пособии \cite[с. 6-68]{dsp:lectures} и технической документацией \cite{ti:dsp-mnemonics} описаны как процессы умножения со сложением, так и используемые тестовые данные для проверки работоспособности. + +Согласно документации \cite[с. 77 (3-33)]{ti:dsp-prog-guide} прототип низкоуровневой функции и описание аргументов функции на языке Си имеют вид, представленный в таблице \hrf{table:prototype}. Функция осуществляет умножение операторов \code{op1} и \code{op2}, сдвиг полученного результата влево на один разряд, складывает результат со значением параметра \code{src}, округляет результат, добавляя число 215 и обнуляет младшие 16 разрядов. + +\begin{table}[H] + \captionsetup{labelsep=endash} + \centering + \caption{Прототип и описание действия функции} + \label{table:prototype} + \begin{tabular}{|p{55mm}|p{110mm}|} + \hline + Прототип функции & Верхнеуровневое описание \\ [3ex] + \hline + \multirow{2}{54mm}{\code{long _smacr(long src, int op1, int op2)}} & Multiplies \code{op1} and \code{op2}, shifts the result left by 1, adds the result to \code{src}, and then rounds the result by adding 215 and zeroing out the lower 16 bits. (SATD, SMUL, and FRCT bits set).\\ + \cline{2-2} + & Returns the saturated sum of src1 and the fractional-mode product of src2 and src3. The sum is rounded as if the intrinsic \code{_sround} were used. \\ [5ex] + \hline + \end{tabular} +\end{table} + +В наборе команд микропроцессора TMS320C55x \cite{ti:dsp-mnemonics} имеется команда, позволяющая реализовать умножение с насыщением и округлением. \code{MAC} – данная инструкция выполняет умножение и суммирование. + +Команда MAC имеет следующий синтаксис \cite[с. 273]{ti:dsp-mnemonics}: +\begin{center} \code{MAC[R] ACx, Tx, ACy[, ACy]},\end{center} +где: +\begin{itemize} +\item [] MAC – мнемоника команды умножения со сложением; +\item [] R – признак округления результата операции; +\item [] Tx - 16-разрядные регистры T0, T1; +\item [] ACx и ACy – регистр аккумулятор AC0-AC3. +\end{itemize} +Необязательный параметр (5) заключён в квадратные скобки. + +Эта инструкция выполняет умножение и сложение. Входящие операнды умножителя ACx(32−16) и значение Tx знаково расширяются до 17 битов по формуле (\hrf{eq:expanding}) +\begin{equation} + ACy = ACy + (ACx * Tx). + \label{eq:expanding} +\end{equation} + +Умножение с накоплением чисел разной разрядности происходит как показано на рис. \hrf{pic:mac}. Для повторения этого действия необходимо переместить параметр, переданный в регистре \code{T0} в регистр большей разрядности \code{AC1} (строка \hrf{line:moving-to-hi}). Полный листинг ассемблерной команды (\hrf{code:prog-asm}) представлен в приложении \hrf{appendix:fulls}. +\begin{figure}[H] + \centering + \includegraphics[height=5cm]{01lab-rpt-mac.png} + \caption{Умножение с накоплением} + \label{pic:mac} +\end{figure} + +\section{Результаты работы} +После запуска проверочной программы (\hrf{code:prog-c}) представленной в приложении \hrf{appendix:fulls} было доказано совпадение результатов библиотечной функции и описанной в листинге \hrf{code:prog-asm}. Снимки экрана, демонстрирующие идентичность полученных результатов представлены на рис. \hrf{pic:result}. + +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.7\textwidth} + \centering + \includegraphics[width=\textwidth]{01lab-rpt-1.png} + \end{subfigure} + + \begin{subfigure}[b]{0.7\textwidth} + \centering + \includegraphics[width=\textwidth]{01lab-rpt-2.png} + \end{subfigure} + \caption{Результаты вызова функций \code{_smacr} и \code{lab1}} + \label{pic:result} +\end{figure} + + +\newpage +\printbibliography[heading=bibintoc, title={Список литературы}, resetnumbers=1] + +\newpage +\appendix +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Alph{subsection}} + +\subsection{Полные листинги программ} +\label{appendix:fulls} +\begin{lstlisting}[language=C,style=CCodeStyle,caption={Программа на языке С}, label=code:prog-c] +#include "stdio.h" + +#define SIZE 2 + +//long _smacr(long src1, int src2, int src3); +extern long lab1(long, int, int); + +void main(void) { + //Локальные переменные + int i; + int intValues[] = {0x00008001, 0xFFFE0001}; + long longValues[] = {0x00008001, 0xFFFE0001}; + + long result_lib; + long result_lab; + for (i = 0; i < SIZE; ++i) { + result_lib = 10; + result_lab = 10; + result_lib = _smacr(result_lib, longValues[i], intValues[i]); + result_lab = lab1(result_lab, longValues[i], intValues[i]); + int neq = result_lib - result_lab; + } +} +\end{lstlisting} + +\begin{lstlisting}[style=ASMStyle,caption={Описание функции на языке ассемблера}, label=code:prog-asm] + .def _lab1 + .text + +_lab1: + BSET FRCT + BSET SATD + MOV T1,HI(AC1) <@\label{line:moving-to-hi}@> + MACR AC1, T0, AC0 + RET +\end{lstlisting} + +\end{document} + diff --git a/02-dspmd-02-hw-report.tex b/02-dspmd-02-hw-report.tex new file mode 100644 index 0000000..e91d0e1 --- /dev/null +++ b/02-dspmd-02-hw-report.tex @@ -0,0 +1,162 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../bmstu-preamble} +\input{../fancy-listings-preamble} +\numerationTop +\newcolumntype{s}{>{\tiny{}}c} + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +\makeReportTitle{домашней}{2}{Библиотечная подпрограмма}{Микропроцессорные устройства обработки сигналов}{}{проф. каф. ИУЗ, д.т.н. \\В.С. Выхованец} +\newpage +\thispagestyle{empty} +\tableofcontents +\addtocontents{toc}{\vspace{2ex}} + +\newpage +\pagestyle{fancy} +\section{Задача} +Темой домашнего задания является изучение алгоритмов и исследование способов их реализации, выполняющих Вычисление арктангенсов \code{atan16} \cite[с. 32 (4-11)]{ti:dsp-lib-prog-ref}. Для выполнения домашнего задания необходимо: +\begin{enumerate}[label=\arabic*),ref=\arabic*] +\item ознакомиться с рекомендованной литературой \cite[с. 102-165]{dsp:lectures}; +\item привести в отчете теоретические сведения по методам обработки сигналов; +\item описать алгоритм обработки сигналов и данных; +\item прокомментировать текст библиотечной функции; +\item оформить\cite{gost:texts} отчет\cite{gost:links} по домашнему заданию\cite{bmstu:dsp-methodics2}. +\end{enumerate} + +Основным результатом домашнего задания является комментированный текст библиотечной функции на языке ассемблера, а также описание выполняемого ею алгоритма цифровой обработки сигналов и данных. + +\section{Выполнение} +\subsection{Теоретические сведения} +Арктангенс (arctg или arctan) – это обратная тригонометрическая функция. Арктангенс x определяется как функция, обратная к тангенсу x, где x – любое число ($x\in\mathbb{R}$). Если тангенс угла у равен х ($\tan(y) = x$), значит арктангенс x равняется y: + +\[ \arctan(x) = \tan^{-1} x = y, \text{причем} -\pi / 2 < y < \pi / 2.\] + +При этом $\tan^{-1}x$ означает обратный тангенс, а не тангенс в степени -1. Функция арктангенс непрерывна на своей области определения, то есть для всех x. Функция арктангенс является нечетной: + +\[ \arctan(–x) = \arctan(–\tan \arctan x) = \arctan(\tan(–\arctan x)) = –\arctan x.\] + +График арктангенса получается из графика тангенса, если поменять местами оси абсцисс и ординат. Чтобы устранить многозначность, множество значений ограничивают интервалом, на котором функция монотонна. Такое определение называют главным значением арктангенса. + +\subsection{Интерфейс библиотечной функции} +Согласно документации \cite[c. 32 (4-11)]{ti:dsp-lib-prog-ref} функция вычисления арктангенса вектора значений имеет прототип, представленный в листинге \hrf{lst:atan-proto}: + +\begin{lstlisting}[language=C,style=CCodeStyle,caption={Прототип функции вычисления арктангенса},label={lst:atan-proto}] + \code{ushort oflag = atan16 (DATA *x, DATA *r, ushort nx)} +\end{lstlisting} +где \code{ushort} – тип данных, определенный как \code{unsigned short}; \code{DATA} – тип данных, являющийся синонимом \code{int}; \code{x} – указатель на вектор исходных данных; \code{r} – указатель на вектор выходных данных арктангенса \code{x} в диапазоне $[-\pi/4, \pi/4]$, при этом, \code{atan(1.0) = 0.7854 или 6478h}; \code{nx} – число элементов в векторах \code{x} и \code{r}. Векторы входных и выходных данных функции представляют собой одномерные массивы, элементами которых являются 16-разрядные числа (целые или дробные), +пронумерованные в порядке увеличения их адресов в памяти данных (таблица \hrf{table:vectors}). +\begin{table}[H] + \captionsetup{labelsep=endash} + \centering + \caption{Общий вид вектора функции atan16} + \label{table:vectors} + \begin{tabular}{|c|c|c|c|c|c|c|} + \hline + Адрес & x(+0) & x+1 & x+2 & x... & x+(nx-2) & x+(nx-1) \\ [0.5ex] + \hline + Индекс & x[0] & x[1] & x[2] & x... & x[nx-2] & x[nx-1] \\ [1ex] + \hline + \end{tabular} +\end{table} + +Длина векторов \code{nx} задается в формате N16 – беззнаковом 16-разрядном целочисленном формате. Сами массивы, а также их элементы выравнены по границе слова. Разрешается использование одного и того же указателя для задания двух векторов\footnote{In-place processing allowed (r can be equal to x)}. Функция управляет флагом переполнения \code{oflag}, который выставляется в 1 или 0 если произошло или не произошло 32-разрядное переполнение, соответственно. + +\subsection{Описание алгоритма} +Функция \code{atan16} подсчитывает значение арктангенса каждого элемента вектора \code{x}, Результат записывается в выходной вектор \code{r} в диапазоне $[-\pi/4, \pi/4]$ радиан. Например, если x = [0x7fff, 0x3505, 0x1976, 0x0], что +эквивалентно $\tan(\frac{\pi}{4})$, $\tan(\frac{\pi}{8})$, $\tan(\frac{\pi}{16})$, $\tan(0)$ в формате float, то вызов функции \code{atan16(x, r, 4);} должен выдать r = [0x6478, 0x3243, 0x1921, 0x0], что эквивалентно $\frac{\pi}{4}$, $\frac{\pi}{8}$, $\frac{\pi}{16}$, $0$. + +Реализуемый функцией \code{atan16} алгоритм описан на языке программирования Cи и приведен на листинге \hrf{lst:atan-alg}. + +\begin{lstlisting}[language=C, style=CCodeStyle, caption = {Алгоритм вычисления арктангенса}, label={lst:atan-alg}] + #define DATA int + #define ushort unsigned short + void atan(DATA* x, DATA* r, ushort nx) { + ushort i; + for (i = 0; i < nx; i++) { + r[i] = atan(x[i]); + } + } +\end{lstlisting} + +В теле основного цикла функции выполняется извлечение очередных элементов вектороа \code{x} и передача их в функцию \code{atan()}, с последующим присваиванием результата в соответствующий индекс выходного вектора \code{r}. Для организации цикла используется целочисленная переменная \code{i}, которая задает индекс элементов векторов. +Комментированный текст библиотечной функции \code{atan()} на основе сведений о мнемониках \cite{ti:dsp-mnemonics} приведен в приложении \hrf{appendix:asm}. + +\section{Выводы} +В домашнем задании 2 приведено описание библиотечной функции вычисления арктангенса вектора. Для функции вычисления значений арктангенса разработан алгоритм на языке Си и приведен комментированный текст его реализации библиотечной функцией на языке ассемблера для микропроцессора цифровой обработки сигналов TMS320C5515. + +\newpage +\printbibliography[heading=bibintoc, title={Список литературы}, resetnumbers=1] + +\newpage +\begin{appendices} +\renewcommand{\thesubsection}{\Asbuk{subsection}} +\subsection{Библиотечная функция atan()} +\label{appendix:asm} +\begin{lstlisting}[style=ASMStyle] +;<@\lh{dkgreen}{************************************************************}@> +;<@\lh{dkgreen}{* Version 3.00.00 }@> +;<@\lh{dkgreen}{************************************************************}@> +;<@\lh{dkgreen}{* Функция: atan16}@> +;<@\lh{dkgreen}{* Процессор: C55xx}@> +;<@\lh{dkgreen}{* Описание: реализация арктангенса}@> +;<@\lh{dkgreen}{* Использование: short atan16( DATA *x, DATA *r, int nx)} @> +;<@\lh{dkgreen}{* nx : число элементов x и r}@> +;<@\lh{dkgreen}{* r[i] = atan(x[i]) где x и r в формате Q15}@> +;<@\lh{dkgreen}{* return 0}@> +;<@\lh{dkgreen}{*}@> +;<@\lh{dkgreen}{* Производительность (бенчмарки):}@> +;<@\lh{dkgreen}{* Циклов: (5 * nx) + 14 (Асимптотическая сложность О(n))}@> +;<@\lh{dkgreen}{* Объём кода (в байтах): 49}@> +;<@\lh{dkgreen}{*}@> +;<@\lh{dkgreen}{************************************************************}@> + + .mmregs ;<@\lh{dkgreen}{Разрешение MMR-регистров}@> + .cpl_on ;<@\lh{dkgreen}{Режим компилятора}@> + .arms_on ;<@\lh{dkgreen}{Сигнальный режим адресации}@> + +;<@\lh{dkgreen}{-----------------------------------------------------------}@> +;<@\lh{dkgreen}{| Тело функции}@> +;<@\lh{dkgreen}{-----------------------------------------------------------}@> + .def _atan16 + .text +_atan16: + ; <@\lh{dkgreen}{* AR0 присваивается \_x}@> + ; <@\lh{dkgreen}{* AR1 присваивается \_r}@> + ; <@\lh{dkgreen}{* T0 присваивается \_nx}@> + PSH T3 ; <@\lh{dkgreen}{использовать временный регистр}@> + || BSET FRCT ; <@\lh{dkgreen}{режим рациональных чисел}@> + SUB #1, T0 ; nx - 1 + MOV T0, BRC0 ; <@\lh{dkgreen}{повторить nx раз}@> + MOV #2596 << #16, AC3 ; <@\lh{dkgreen}{старшие разряды AC3 = C5}@> + MOV #-9464 << #16, AC1 ; <@\lh{dkgreen}{старшие разряды AC1 = C3}@> + MOV #32617 << #16, AC2 ; <@\lh{dkgreen}{старшие разряды AC2 = C1}@> + +; <@\lh{dkgreen}{Загрузка T3 на инструкцию раньше, чем умножение его}@> +; <@\lh{dkgreen}{использует, приведёт к задержке в один такт}@> + + MPYMR T3=*AR0+, AC3, AC0 ; <@\lh{dkgreen}{непосредственное умножение значения из х}@> + || RPTBLOCAL loop1 - 1 ; <@\lh{dkgreen}{и запустить цикл}@> + MACR AC0,T3,AC1,AC0; <@\lh{dkgreen}{вычислить смещение для следующего значения}@> + MPYR T3, AC0 ; <@\lh{dkgreen}{сохранить временный результат умножения}@> + || MOV *AR0+, T1 ; <@\lh{dkgreen}{сместить указатель на следующее значение х}@> + MACR AC0,T3,AC2,AC0; <@\lh{dkgreen}{вычислить смещение для следующего значения}@> + MPYR T3, AC0 ; <@\lh{dkgreen}{сохранить временный результат умножения}@> + || MOV T1, T3 ; <@\lh{dkgreen}{сохранить значение итератора}@> + MOV HI(AC0), *AR1+ ; <@\lh{dkgreen}{сохранить старшую часть результата вычислений}@> + || MPYR T1, AC3, AC0 ; <@\lh{dkgreen}{следующая итерация}@> + + loop1: ; <@\lh{dkgreen}{цикл}@> + POP T3 ; + || BCLR FRCT ; <@\lh{dkgreen}{вернуться в режим обычного C}@> + MOV #0, T0 ; <@\lh{dkgreen}{вернуть значение ОК}@> + || RET ; <@\lh{dkgreen}{(нет возможных ошибок)}@> +\end{lstlisting} +\end{appendices} + +\end{document} + diff --git a/02-dspmd-02-hw-var-lama.tex b/02-dspmd-02-hw-var-lama.tex new file mode 100644 index 0000000..e51d210 --- /dev/null +++ b/02-dspmd-02-hw-var-lama.tex @@ -0,0 +1,118 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +Официальное описание из комментария к функции хорошо объясняет, что именно она делает: +\begin{verbatim} +Description: minimum Value and Index of the minimum + element of a vector +\end{verbatim} + +Снаружи функция будет вызываться вот так +\begin{verbatim} +void minvec (DATA *x, ushort nx, DATA *val, DATA *idx) +\end{verbatim} +То есть передадим +\begin{itemize} +\item вектор (массив чисел) \code{DATA *x}, важно, что вектор у нас из типа \code{DATA}, который, на самом деле \code{ushort (unsigned short)}, 16-разрядный, то есть при подсчёте сдвига по вектору для получения следующего значения - нужно смещаться на 2 байта. +\item длину вектора \code{ushort nx}, +\item указатель на полученное значение \code{DATA *val}, +\item указатель на полученный индекс \code{DATA *idx}. +\end{itemize} + +Для языка ассемблера, умеющего манипулировать только регистрами, важно понимать, в какие именно регистры будут положены эти параметры +\begin{itemize} +\item \code{DATA *x} - указатель AR0 +\item \code{ushort nx} - регистр T0 +\item \code{DATA *val} - указатель AR1 +\item \code{DATA *idx} - указатель AR2 +\end{itemize} + +дальше последовательно опишем что именно делает функция и как: + +\begin{verbatim} + .text + .global _minvec +_minvec: +\end{verbatim} + +до вызова функции система находилась в каком-то статусе, соответственно, нам нужно этот статус сохранить, чтобы наша функция ничего не сломала +\begin{verbatim} + PSH mmap(ST0_55) ; Сохранение регистров статуса на стеке + PSH mmap(ST1_55) + PSH mmap(ST2_55) + PSH mmap(ST3_55) +\end{verbatim} + +далее происходит одновременное действие, знак \code{II} показывает, что два этих действия будут выполняться параллельно. Запись очередного значения из вектора во временный регистр \code{AC1} и вычитание 2 из регистра \code{T0}. Запись \code{*AR0+} означает, что мы не только разыменовали указатель (получили значение по указателю, знак *), но и сдвинули указатель вектора на следующий адрес (знак +) +\begin{verbatim} + MOV *AR0+,AC1 + || SUB #2,T0 +\end{verbatim} + +Сохраним значение из \code{T0} в \code{BRC0} и одновременно запишем 0 в \code{AR3}. Это вспомогательное действие, чтобы высвободить регистры, при помощи которых мы будем делать дальнейшие вычисления. +\begin{verbatim} + MOV T0,BRC0 + || MOV #0,AR3 +\end{verbatim} + +Далее происходит обнуление регистра \code{T0} и цикл между значением \code{RPTBLOCAL} и \code{end_block:} +\begin{verbatim} + MOV #0,T0 + || RPTBLOCAL end_block-1 +\end{verbatim} + +В цикле мы кладём следующее значение из вектора в \code{AC0}, помнишь, мы уже клали значение из вектора в \code{AC1}, вот теперь в \code{AC0}. Мнемоника \code{MAR} в явном виде не описана в документации, но есть предположение, что MAR это аббревиатура от Modify Auxiliary Register, то есть по факту это просто увеличение временного указателя на будущий вычисленный индекс на единицу. Напомню, в этот регистр два шага назад, до цикла, мы положили 0, то есть, скорее всего, это будет конечный индекс в векторе, который мы должны вернуть. +\begin{verbatim} + MOV *AR0+,AC0 + || MAR *AR3+ +\end{verbatim} + +Тут, понятно, мы ищем минимальное из двух значений (мы же положили последовательно два значения из вектора в \code{AC0} и \code{AC1}). Значение, полученное в результате сравнения, будет положено в \code{AC1}\footnote{TMS320C55x-Mnemonic Instruction Set. Reference Guide-2009, p.428}. То, что мы положим минимальное в \code{AC1} даст нам возможность на следующей итерации цикла снова сравнивать с ним прочитанное в \code{AC0} следующее значение из вектора, как мы это делаем на предыдущем шаге. +\begin{verbatim} + MIN AC0,AC1 +\end{verbatim} + +Это проверка условия завершения цикла \footnote{TMS320C55x-Mnemonic Instruction Set. Reference Guide-2009, p.749 (XCCPART), p.20(CARRY)} по биту переноса и одновременно вывод информации из \code{AR3} (в котором, напомню, у нас хранился индекс минимального значения в векторе) по указателю \code{AR2}, который, напомню, нам передали с параметрами функции +\begin{verbatim} + XCCPART end_block, !CARRY + || MOV AR3,*AR2 +\end{verbatim} + +По завершении цикла, сохраним полученное значение минимума по указателю \code{AR1}, который мы передали снаружи в параметре \code{val}. +\begin{verbatim} +end_block: + MOV AC1,*AR1 +\end{verbatim} + +Вернём на место статус системы из сохранённого ранее и выйдем из функции +\begin{verbatim} + POP mmap(ST3_55) + POP mmap(ST2_55) + POP mmap(ST1_55) + POP mmap(ST0_55) + RET +\end{verbatim} + +\begin{lstlisting}[language=C,style=CCodeStyle] +void minvec (DATA *x, ushort nx, DATA *val, DATA *idx) { + while (nx-- >= 0) { + if (*val > *(x + nx)) { + *val = *(x + nx); + *idx = nx; + } + } +} +\end{lstlisting} + +\end{document} + + + diff --git a/02-dspmd-02-lab-report.tex b/02-dspmd-02-lab-report.tex new file mode 100644 index 0000000..a8bae08 --- /dev/null +++ b/02-dspmd-02-lab-report.tex @@ -0,0 +1,248 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../bmstu-preamble} +\input{../fancy-listings-preamble} +\setcounter{secnumdepth}{0} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% ... работе, номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{2}{Исследование процессов обработки сигналов}{Микропроцессорные устройства обработки сигналов}{}{А.И. Германчук} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель} +Целью работы является изучение стандартных процедур обработки сигналов и данных, а также их реализация в интегрированной среде проектирования Code Composer Studio версии 5 и на микропроцессоре TMS320C5515 компании Texas Instruments Incorporated. При выполнении лабораторной работы используется симулятор микропроцессора TMS320C5515 или оценочноя плата TMS320C5515 DSP Evaluation Module (TMDXEVM5515). + +\section{Выполнение} +Индивидуальным заданием было написание функции вычисления арктангенса числа: \code{ushort atan16(DATA *x, DATA *r, ushort nx)}. + +\section{Результаты работы} +После запуска проверочной программы (\hrf{code:prog-c}) представленной в приложении \hrf{appendix:fulls} было доказано совпадение результатов библиотечной функции (листинг \hrf{code:std-asm}) и описанной в дизассемблированном листинге \hrf{code:asm}. Результаты работы профилировщика отражены в таблице \hrf{table:profiler}. Снимки экрана, демонстрирующие идентичность полученных результатов представлены на рис. \hrf{pic:result}. + +\begin{table}[H] + \centering + \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|} + \hline + Name & Calls & EC Av & EC Ttl & IC Av & IC Ttl & File \\ + \hline + atan(short *, short *, int) & 1 & 969.0 & 969.0 & 3384.0 & 3384.0 & main.c \\ + \hline + null() & 1 & 49.0 & 49.0 & 49.0 & 49.0 & atan16.asm \\ + \hline + \end{tabular} + \caption{Результат работы профилировщика} + \label{table:profiler} +\end{table} + +\begin{figure}[H] + \centering + \includegraphics[width=12cm]{02lab-rpt-1.png} + \caption{Результат вычислений} + \label{pic:result} +\end{figure} + + +\newpage +\printbibliography[heading=bibintoc, title={Список литературы}, resetnumbers=1] + +\newpage +\appendix +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Alph{subsection}} + +\subsection{Полные листинги программ} +\label{appendix:fulls} +\begin{lstlisting}[style=ASMStyle,caption={Стандартный ассемблерный листинг}, label=code:std-asm] +_atan16: + ;* AR0 assigned to _x + ;* AR1 assigned to _r + ;* T0 assigned to _nx + PSH T3 + || BSET FRCT ;fractional mode + SUB #1, T0 ;nx-1 + MOV T0, BRC0 ;repeat nx times + MOV #2596 << #16, AC3 ; AC3.Hi = C5 + MOV #-9464 << #16, AC1 ; AC1.Hi = C3 + MOV #32617 << #16, AC2 ; AC2.Hi = C1 + + MPYMR T3=*AR0+, AC3, AC0 ; (Prime the Pump) + || RPTBLOCAL loop1-1 + MACR AC0, T3, AC1, AC0 + MPYR T3, AC0 + ||MOV *AR0+, T1 ; (for next iteration) + MACR AC0, T3, AC2, AC0 + MPYR T3, AC0 + ||MOV T1, T3 + MOV HI(AC0), *AR1+ ;save result + ||MPYR T1, AC3, AC0 ; (for next iteration) + +loop1: + POP T3 + || BCLR FRCT ;return to standard C + MOV #0, T0 ;return OK value (no possible error) + || RET +\end{lstlisting} + +\newpage +\begin{lstlisting}[language=C,style=CCodeStyle,caption={Программа на языке С}, label=code:prog-c] +#include "TMS320.h" + +#define NX 7 +#define FNAME "t1" +#define MAXERROR 40 + +ushort atan16(DATA *x, DATA *r, ushort nx); + +short atan(DATA *x, DATA *r, int nx) { + long long ac3 = ((long long) 2596) << 16; // AC3.Hi = C5 0.0396118164062500 + long long ac1 = ((long long) -9464) << 16; // AC1.Hi = C3 -0.1444091796875000 + long long ac2 = ((long long) 32617) << 16; // AC2.Hi = C1 0.4976959228515625 + while (--nx >= 0) { + long long ac0; + DATA t3 = *(x + nx); + ac0 = (t3 * (ac3 >> 15)) << 1; // MPYMR T3=*AR0+, AC3, AC0 + ac0 = ((ac0 >> 15) * t3) + ac1; // MACR AC0, T3, AC1, AC0 + ac0 = ((ac0 >> 15) * t3); // MPYR T3, AC0 + + ac0 = ((ac0 >> 15) * t3) + ac2; // MACR AC0, T3, AC2, AC0 + ac0 = ((ac0 >> 15) * t3); // MPYR T3, AC0 + *(r + nx) = ac0 >> 16; // MOV HI(AC0), *AR1+ + } + return 0; +} + +int main(void) { + DATA x[NX] = {8192,16384,24576,32767,-8192,-16384,-24576}; + DATA rtest[NX] ={8027,15192,21086,25735,-8028,-15193,-21087}; + DATA r[NX]; + DATA r0[NX]; + + (void)atan16(x, r0, NX); + atan(x, r, NX); + + return 0; +} +\end{lstlisting} + +\newpage +\begin{lstlisting}[style=ASMStyle,caption={Дизассемблированная программа}, label=code:asm] +atan: + 4ee9 AADD #-23,SP + c408 MOV T0,*SP(#04h) + eb0495 MOV XAR1,dbl(*SP(#02h)) + eb0085 MOV XAR0,dbl(*SP(#00h)) +long long ac3 = ((long long) 2596) << 16; + 7a0a240a MOV #2596 << #16,AC0 + 46a3_110700 BSET ST1_M40 || SFTL AC0,#0,AC0 + 104720 SFTL AC0,#-32,AC1 + eb0c18 MOV AC1,dbl(*SP(#06h)) + eb1008 MOV AC0,dbl(*SP(#08h)) +long long ac1 = ((long long) -9464) << 16; + 7adb080a MOV #-9464 << #16,AC0 + 104720 SFTL AC0,#-32,AC1 + eb1418 MOV AC1,dbl(*SP(#0ah)) + eb1808 MOV AC0,dbl(*SP(#0ch)) +long long ac2 = ((long long) 32617) << 16; + 7a7f690a_47a2 MOV #32617 << #16,AC0 || BCLR ST1_M40 + 46a3_110700 BSET ST1_M40 || SFTL AC0,#0,AC0 + 104720 SFTL AC0,#-32,AC1 + eb1c18 MOV AC1,dbl(*SP(#0eh)) + eb2008 MOV AC0,dbl(*SP(#10h)) +while (--nx >= 0) + a908 MOV *SP(#04h),AR1 + 4219 SUB #1,AR1 + c908 MOV AR1,*SP(#04h) + 6d2900d6 BCC C$DW$L$_atan$2$E,AR1 < #0 +DATA t3 = *(x + nx); + 2294 MOV AR1,T0 + ed00bf MOV dbl(*SP(#00h)),XAR3 + a96b MOV *AR3(T0),AR1 + c92c MOV AR1,*SP(#16h) +ac0 = (t3 * (ac3 >> 15)) << 1; + ed1018 MOV dbl(*SP(#08h)),AC1 + ed0c28 MOV dbl(*SP(#06h)),AC2 + c21a_98 MOV AC2,mmap(@AC1G) + a02c MOV *SP(#16h),AC0 + 46a2_115531 BCLR ST1_M40 || SFTS AC1,#-15,AC1 + 6c00207d CALL _mpylli + 46a3 BSET ST1_M40 + 4450 SFTS AC0,#1 + 104720 SFTL AC0,#-32,AC1 + eb2418 MOV AC1,dbl(*SP(#12h)) + eb2808 MOV AC0,dbl(*SP(#14h)) +ac0 = ((ac0 >> 15) * t3) + ac1; + ed2808 MOV dbl(*SP(#14h)),AC0 + ed2418 MOV dbl(*SP(#12h)),AC1 + c114_98 MOV AC1,mmap(@AC0G) + a12c MOV *SP(#16h),AC1 + 46a2_110531 BCLR ST1_M40 || SFTS AC0,#-15,AC0 + 6c00207d CALL _mpylli + ed1428 MOV dbl(*SP(#0ah)),AC2 + ed1818 MOV dbl(*SP(#0ch)),AC1 + c21a_98 MOV AC2,mmap(@AC1G) + 46a3 BSET ST1_M40 + 2401 ADD AC0,AC1 + 101720 SFTL AC1,#-32,AC0 + eb2408 MOV AC0,dbl(*SP(#12h)) + eb2818 MOV AC1,dbl(*SP(#14h)) +ac0 = ((ac0 >> 15) * t3); + ed2418 MOV dbl(*SP(#12h)),AC1 + ed2808 MOV dbl(*SP(#14h)),AC0 + c114_98 MOV AC1,mmap(@AC0G) + a12c MOV *SP(#16h),AC1 + 46a2_110531 BCLR ST1_M40 || SFTS AC0,#-15,AC0 + 6c00207d CALL _mpylli + 46a3 BSET ST1_M40 + 104720 SFTL AC0,#-32,AC1 + eb2418 MOV AC1,dbl(*SP(#12h)) + eb2808 MOV AC0,dbl(*SP(#14h)) +ac0 = ((ac0 >> 15) * t3) + ac2; + ed2808 MOV dbl(*SP(#14h)),AC0 + ed2418 MOV dbl(*SP(#12h)),AC1 + c114_98 MOV AC1,mmap(@AC0G) + a12c MOV *SP(#16h),AC1 + 46a2_110531 BCLR ST1_M40 || SFTS AC0,#-15,AC0 + 6c00207d CALL _mpylli + ed1c28 MOV dbl(*SP(#0eh)),AC2 + ed2018 MOV dbl(*SP(#10h)),AC1 + c21a_98 MOV AC2,mmap(@AC1G) + 46a3 BSET ST1_M40 + 2401 ADD AC0,AC1 + 101720 SFTL AC1,#-32,AC0 + eb2408 MOV AC0,dbl(*SP(#12h)) + eb2818 MOV AC1,dbl(*SP(#14h)) +ac0 = ((ac0 >> 15) * t3); + ed2418 MOV dbl(*SP(#12h)),AC1 + ed2808 MOV dbl(*SP(#14h)),AC0 + c114_98 MOV AC1,mmap(@AC0G) + a12c MOV *SP(#16h),AC1 + 46a2_110531 BCLR ST1_M40 || SFTS AC0,#-15,AC0 + 6c00207d CALL _mpylli + 46a3 BSET ST1_M40 + 104720 SFTL AC0,#-32,AC1 + eb2418 MOV AC1,dbl(*SP(#12h)) + eb2808 MOV AC0,dbl(*SP(#14h)) +*(r + nx) = ac0 >> 16; + a408 MOV *SP(#04h),T0 + ed04bf MOV dbl(*SP(#02h)),XAR3 + ed2418 MOV dbl(*SP(#12h)),AC1 + ed2808 MOV dbl(*SP(#14h)),AC0 + c114_98 MOV AC1,mmap(@AC0G) + bc6b MOV HI(AC0),*AR3(T0) + a908 MOV *SP(#04h),AR1 + 4219 SUB #1,AR1 + c908 MOV AR1,*SP(#04h) + 6d59ff2a BCC C$L1,AR1 >= #0 +return 0; +\end{lstlisting} + +\end{document} + diff --git a/02-dspmd-03-hw-report.tex b/02-dspmd-03-hw-report.tex new file mode 100644 index 0000000..be2d51d --- /dev/null +++ b/02-dspmd-03-hw-report.tex @@ -0,0 +1,172 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../bmstu-preamble} +\input{../fancy-listings-preamble} +\numerationBottom +\newcolumntype{s}{>{\tiny{}}c} + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +\makeReportTitle{домашней}{3}{Звуковой эффект}{Микропроцессорные устройства обработки сигналов}{}{проф. каф. ИУЗ, д.т.н. \\В.С. Выхованец} +\newpage +\thispagestyle{empty} +\tableofcontents +\addtocontents{toc}{\vspace{2ex}} + +\newpage +\pagestyle{fancy} +\section{Постановка задачи} +Целью домашнего задания является разработка алгоритма звукового эффекта «Контроллер динамического диапазона». Для выполнения домашнего задания необходимо: +\begin{itemize} +\item ознакомиться с рекомендованной литературой \cite{dsp:lectures}; +\item привести в отчете описание звукового эффекта; +\item описать алгоритм обработки сигналов и данных. +\end{itemize} +При разработке алгоритма необходимо учесть, что исходный звуковой сигнал поступает на обработку от звукового кодека по одному отсчету, получаемому при вызове функции \code{sam = GetSample()}, где \code{sam} – текущий входной отсчет звукового сигнала в формате с фиксированной запятой. Обработанные отсчеты передаются звуковому кодеку обратно путем вызова функции \code{PutSample(res)}, где \code{res} – текущий выходной отсчет звукового сигнала в формате с фиксированной запятой. + +\section{Выполнение} +\subsection{Описание звукового эффекта} +Контроллер динамического диапазона - это адаптивная регулировка динамического диапазона сигнала. Динамический диапазон - это соотношение между наибольшими и наименьшими значениями, которые может принять определенная величина. Существует несколько типов контроллеров. В данной лабораторной работе будет рассматриваться ограничитель. Назначение ограничителя состоит в том, чтобы обеспечить контроль над самыми высокими пиками сигнала, но при этом, как можно меньше изменять динамику сигнала. Это достигается за счёт использования характеристической кривой с бесконечным отношением \cite[с. 109]{dsp:dafx}. Ограничитель динамического диапазона подавляет громкость звуков, пересекающих заданный порог (рисунок \hrf{pic:limiter}). + +\begin{figure}[H] + \captionsetup{labelsep=endash} + \centering + \def\svgwidth{100mm} + \input{pics/02-dsp-03lab-limiter.pdf_tex} + \caption{Иллюстрация работы ограничителя сигнала} + \label{pic:limiter} +\end{figure} + +Для достижения плавности кривой применяемого ослабления громкости используются такие параметры, как время атаки и высвобождения. Время атаки и время высвобождения соответствуют времени, за которое сигнал увеличивается или уменьшается до конечного значения (рисунок \hrf{pic:limiter-explain}). На рисунке видно, что при отсутствии времени атаки и освобождения усиление применяется сразу, создавая неплавные «обрезанные» кривые (жёсткое урезание). + +\begin{figure}[H] + \captionsetup{labelsep=endash} + \centering + \def\svgwidth{170mm} + \input{pics/02-dsp-03lab-limiter-explain.pdf_tex} + \caption{Иллюстрация влияния времени атаки и освобождения} + \label{pic:limiter-explain} +\end{figure} + +Ограничитель обычно используется для того, чтобы «поймать» самые громкие моменты источника, уменьшив их таким образом, чтобы защитить от нежелательных искажений и сохранить целостность общего баланса звука. + +\subsection{Математическое описание ограничителя} +\label{sect:description} +Динамическая обработка выполняется усилительными устройствами, где коэффициент усиления автоматически регулируется уровнем входного сигнала. Динамическая обработка проходит в несколько этапов: +\begin{enumerate}[label=\arabic*),ref=\arabic*] +\item Сначала используется схема определения амплитуды/уровня по алгоритму PEAK \cite[с. 107]{dsp:dafx}. + +В начале алгоритма значение переменной $X_{peak}$ равно нулю. Далее сравнивается модуль поступающего сигнала $|x(n)|$ с предыдущим значением $X_{peak}$. В случае если значение модуля поступающего сигнала больше, то значение $X_{peak}$ для текущего элемента вычисляется с использованием коэффициента $AT$, которое используется, как сокращение для времени атаки (attack time). В ином случае вычисление значения $X_{peak}$ для текущего элемента производится с помощью коэффициента $RT$, то есть времени освобождения (release time). Математическая формула описанного выше алгоритма + +\begin{equation} + X_{p}(n) = \begin{cases} + (1 - AT) \times X_{p}(n - 1) + AT \times |X(n)|, |X(n)| > X_{p}(n - 1)\\ + (1 - RT) \times X_{p}(n - 1), |X(n)| \leq X_{p}(n - 1), + \end{cases} +\end{equation} +где $X_{p}$ - пиковое значение $X_{peak}$, $AT$ – время атаки, $RT$ – время освобождения, $n$ – номер текущего элемента. + +\item После определения значения $X_{peak}$ выполняется функция для получения коэффициента усиления $f$ по формуле + \begin{equation} + f(n) = min \bigg( 1; \frac{lt}{X_{peak}n} \bigg), + \end{equation} +где $n$ – номер текущего элемента, $lt$ – пороговое значение. + +\item После вычисления коэффициента усиления используется сглаживающий фильтр для предотвращения слишком резких изменений усиления. Для его реализации используется формула +\begin{equation} + cfc = \begin{cases} + AT, f(n) < f(n-1)\\ + RT, f(n) \geq f(n-1), + \end{cases} +\end{equation} +где $n$ – номер текущего элемента. + +\item Далее вычисляется множитель для регулирования входного сигнала по формуле + \begin{equation} +g(n) = (1 - cfc) \times g(n - 1) + cfc \times f(n) + \end{equation} +\item После получения искомого множителя входного сигнала, его значение умножается на задержанный в буфере задержки входной сигнал. Сигнал задерживается для того, чтобы компенсировалась любая задержка при вычислении множителя \cite[с. 106]{dsp:dafx}. +\end{enumerate} + +Результирующая комбинированная система, схематично демонстрирующая все шаги преобразования, изображена на рисунке \hrf{pic:limiter-scheme} \cite[с. 109]{dsp:dafx}. + +\begin{figure}[H] + \captionsetup{labelsep=endash} + \centering + \def\svgwidth{165mm} + \input{pics/02-dsp-03lab-limiter-scheme.pdf_tex} + \caption{Принципиальная схема алгоритма работы ограничителя} + \label{pic:limiter-scheme} +\end{figure} + +\subsection{Алгоритм обработки сигналов} +Алгоритм реализован на основе раздела \hrf{sect:description}. Основная реализующая алгоритм функция приведена в приложении \hrf{appendix:dyn-control-func}. + +На вход алгоритма принимается массив с отсчетами. Пороговое значение задаётся константой \code{LT} в теле функции. + +\subsubsection{Основная программа \code{main}} +Функция \code{main} вызывается при запуске программы и реализует следующие шаги: +\begin{enumerate}[label=\arabic*),ref=\arabic*] +\item Инициализация кодека; +\item Чтение из кодека текущего отсчета сигнала; +\item Получение выходного отсчета сигнала; +\item Переход на шаг 2. +\end{enumerate} + +\subsubsection{Функция ограничителя \code{dynDiaCtrl}} +Функция ограничителя получает в качестве аргумента текуший отсчет \code{х} и возвращает его модифицированное значение \code{у}. Функция реализует следующие шаги алгоритма. +\begin{enumerate}[label=\arabic*),ref=\arabic*] +\item Получение модуля входного значения; +\item Определение коэффициента для вычисления уровня; +\item Вычисление уровня; +\item Определение коэффициента усиления; +\item Определение коэффициента для вычисления управляющего коэффициента; +\item Запись выходного отсчета; +\item Возврат из функции. +\end{enumerate} +Функция использует математические функции из стандартной библиотеки для корректной работы с числами в формате с фиксированной запятой. + +\section{Выводы} +В результате выполнения домашнего задания изучен звуковой эффект «Контроллер динамического диапазона», на примере ограничителя, для которого разработан и описан реализующий его алгоритм. +\nocite{gost:texts} + +\newpage +\printbibliography[heading=bibintoc, title={Список литературы}, resetnumbers=1] + +\newpage +\begin{appendices} + \renewcommand{\thesubsection}{\Asbuk{subsection}} + \subsection{Функция контроллера динамического диапазона} + \label{appendix:dyn-control-func} + \begin{lstlisting}[language=C,style=CCodeStyle] +volatile Int16 xpeak = 0; +volatile Int16 g = 1; +void dynDiaCtrl(Int16 *x, Int16 *y, Int16 nx) { + const Int16 at_cfc = 9830; + const Int16 rt_cfc = 328; + + int i; + for (i = 0; i < nx; i++) { + // step 1 + Int16 a = abs(x[i]); + xpeak = (a > xpeak) + ? (_smpy((32767 - at_cfc), xpeak) + _smpy(at_cfc, a)) + : _smpy((32767 - rt_cfc), xpeak); + + // step 2 + Int16 cmp = LT / xpeak; + Int16 f = (cmp < 1) ? cmp : 1; + // step 3 + Int16 cfc = (f < g) ? at_cfc : rt_cfc; + // step 4 + g = _smpy((1 - cfc), g) + _smpy(cfc, f); + y[i] = _smpy(g, x[i]); + } + \end{lstlisting} +\end{appendices} + +\end{document} + diff --git a/02-dspmd-03-lab-report.tex b/02-dspmd-03-lab-report.tex new file mode 100644 index 0000000..5bc96ab --- /dev/null +++ b/02-dspmd-03-lab-report.tex @@ -0,0 +1,263 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../bmstu-preamble} +\input{../fancy-listings-preamble} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% ... работе, номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{3}{Звуковой эффект}{Микропроцессорные устройства обработки сигналов}{}{А.И. Германчук} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель} +Целью работы является разработка и исследование программы обработки сигналов на языке программирования Си, реализующей звуковой эффект, определенный в индивидуальном задании (контроллер динамического диапазона, ограничитель). + +\section{Описание звукового эффекта} +Контроллер динамического диапазона - это адаптивная регулировка динамического диапазона сигнала. Динамический диапазон - это соотношение между наибольшими и наименьшими значениями, которые может принять определенная величина. Существует несколько типов контроллеров. В данной лабораторной работе будет рассматриваться ограничитель. Назначение ограничителя состоит в том, чтобы обеспечить контроль над самыми высокими пиками сигнала, но при этом, как можно меньше изменять динамику сигнала. Это достигается за счёт использования характеристической кривой с бесконечным отношением \cite[с. 109]{dsp:dafx}. Ограничитель динамического диапазона подавляет громкость звуков, пересекающих заданный порог (рисунок \hrf{pic:limiter}). + +\begin{figure}[H] + \centering + \def\svgwidth{100mm} + \input{pics/02-dsp-03lab-limiter.pdf_tex} + \caption{Иллюстрация работы ограничителя сигнала} + \label{pic:limiter} +\end{figure} + +Для достижения плавности кривой применяемого ослабления громкости используются такие параметры, как время атаки и высвобождения. Время атаки и время высвобождения соответствуют времени, за которое сигнал увеличивается или уменьшается до конечного значения (рисунок \hrf{pic:limiter-explain}). На рисунке видно, что при отсутствии времени атаки и освобождения усиление применяется сразу, создавая неплавные «обрезанные» кривые (жёсткое урезание). + +\begin{figure}[H] + \centering + \def\svgwidth{170mm} + \input{pics/02-dsp-03lab-limiter-explain.pdf_tex} + \caption{Иллюстрация влияния времени атаки и освобождения} + \label{pic:limiter-explain} +\end{figure} + +Ограничитель обычно используется для того, чтобы «поймать» самые громкие моменты источника, уменьшив их таким образом, чтобы защитить от нежелательных искажений и сохранить целостность общего баланса звука. + +\section{Математическое описание ограничителя} +\label{sect:description} +Динамическая обработка выполняется усилительными устройствами, где коэффициент усиления автоматически регулируется уровнем входного сигнала. Динамическая обработка проходит в несколько этапов. +\begin{enumerate} +\item Сначала используется схема определения амплитуды/уровня по алгоритму PEAK \cite[с. 107]{dsp:dafx}. + +В начале алгоритма значение переменной $X_{peak}$ равно нулю. Далее сравнивается модуль поступающего сигнала $|x(n)|$ с предыдущим значением $X_{peak}$. В случае если значение модуля поступающего сигнала больше, то значение $X_{peak}$ для текущего элемента вычисляется с использованием коэффициента $AT$, которое используется, как сокращение для времени атаки (attack time). В ином случае вычисление значения $X_{peak}$ для текущего элемента производится с помощью коэффициента $RT$, то есть времени освобождения (release time). Математическая формула описанного выше алгоритма + +\begin{equation} + X_{p}(n) = \begin{cases} + (1 - AT) \times X_{p}(n - 1) + AT \times |X(n)|, |X(n)| > X_{p}(n - 1)\\ + (1 - RT) \times X_{p}(n - 1), |X(n)| \leq X_{p}(n - 1), + \end{cases} +\end{equation} + + где + \begin{itemize} + \item [] $X_{p}$ - пиковое значение $X_{peak}$; + \item [] $AT$ – время атаки; + \item [] $RT$ – время освобождения; + \item [] $n$ – номер текущего элемента. + \end{itemize} + +\item После определения значения $X_{peak}$ выполняется функция для получения коэффициента усиления $f$ по формуле + \begin{equation} + f(n) = min \bigg( 1; \frac{lt}{X_{peak}n} \bigg), + \end{equation} + где + \begin{itemize} + \item [] $n$ – номер текущего элемента; + \item [] $lt$ – пороговое значение. + \end{itemize} + +\item После вычисления коэффициента усиления используется сглаживающий фильтр для предотвращения слишком резких изменений усиления. Для его реализации используется формула +\begin{equation} + cfc = \begin{cases} + AT, f(n) < f(n-1)\\ + RT, f(n) \geq f(n-1), + \end{cases} +\end{equation} +где $n$ – номер текущего элемента. + +\item Далее вычисляется множитель для регулирования входного сигнала по формуле + \begin{equation} +g(n) = (1 - cfc) \times g(n - 1) + cfc \times f(n) + \end{equation} +\item После получения искомого множителя входного сигнала, его значение умножается на задержанный в буфере задержки входной сигнал. Сигнал задерживается для того, чтобы компенсировалась любая задержка при вычислении множителя \cite[с. 106]{dsp:dafx}. +\end{enumerate} + +Результирующая комбинированная система изображена на рисунке \hrf{pic:limiter-scheme} \cite[с. 109]{dsp:dafx}. + +\begin{figure}[H] + \centering + \def\svgwidth{165mm} + \input{pics/02-dsp-03lab-limiter-scheme.pdf_tex} + \caption{Принципиальная схема алгоритма работы ограничителя} + \label{pic:limiter-scheme} +\end{figure} + +\section{Алгоритм обработки сигналов} +Алгоритм реализован на основе раздела \hrf{sect:description}. В реализации алгоритма учитывается средняя частота дискретизации современных аудиофайлов 44,1 КГц. Алгоритм буферизует отсчёты на 6 миллисекунд, то есть если 44 отсчета - это одна милисекунда, то величина буфера должна быть $44 * 6 = 264$ отсчётов. + +На вход алгоритма, вычисляющего значение коэффициента, принимается единичный отсчёт. Пороговое значение задаётся константой \code{LT} в теле функции. + +\subsection{Основная программа \code{main}} +Функция \code{main} вызывается при запуске программы и реализует следующие шаги: +\begin{enumerate} +\item инициализация кодека; +\item чтение из кодека текущего отсчета сигнала по прерыванию от интерфейса I2S \code{x}, \code{x = I2S2_W0_MSW_R}; +\item вычисление и корректировка коэффициента g и сохранение текущего отсчёта в буфер; +\item получение выходного отсчета сигнала \code{y}, путём умножения буферизованного отсчёта на вычисленный на текущем шаге коэффициент \code{_smpy(g, leftBuffer[qRead++]}; +\item смещение флагов чтения и записи данных в буфер, ожидание готовности контроллера прерываний; +\item запись значений обоих каналов обратно в контроллер I2S; +\item переход на шаг 2. +\end{enumerate} + +\subsection{Функция ограничителя} +Фактически, функция ограничителя разделена на две части: +\begin{enumerate} +\item приём отсчёта, буферизация и вычисление коэффициента ограничителя; +\item чтение из очереди и умножение буферизованного отсчёта на коэффициент. +\end{enumerate} + +Функция расчёта коэффициента реализует следующие шаги алгоритма: +\begin{enumerate} +\item получение входного значения \code{x}; +\item получение модуля отсчёта; +\item определение коэффициента \code{cfc} для вычисления уровня; +\item вычисление уровня \code{xpeak}, \code{xpeak = (1 - cfc) * xpeak + coeff * x}; +\item определение коэффициента усиления \code{f}, \code{f = min(1, LT / xpeak)}; +\item определение коэффициента \code{cfc} для вычисления управляющего коэффициента \code{g = (1 - cfc) * g + cfc * f}; +\item возврат коэффициента \code{g} из функции. +\end{enumerate} + +Код, вызывающий функцию, кроме буферизации прочитанного значения (\code{leftBuffer[qWrite++] = left;}) осуществляет умножение ранее буферизованного отсчёта на текущее скорректированное значение коэффициента фильтра \code{out_left = _smpy(g, leftBuffer[qRead++])} и запись выходного отсчета на шину контроллера I2S \code{I2S2_W0_MSW_W = out_left;} + +\section{Выводы} +В результате выполнения работы была разработана программа обработки сигнала на языке программирования Си, реализующая звуковой эффект - контроллер динамического диапазона, а именно, ограничитель. В ходе работы были получены графики входных и выходных отсчетов и по ним исследован результат применения звукового эффекта на входной сигнал. +\nocite{gost:texts} +\newpage +\printbibliography[heading=bibintoc, title={Список литературы}, resetnumbers=1] + +\newpage +\appendix +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Alph{subsection}} + +\subsection{Полные листинги программ} +\label{appendix:fulls} +\begin{lstlisting}[language=C,style=CCodeStyle,caption={Функция вычисления коэффициента ограничителя}, label=code:prog-coeff] +Int16 oneCountCoefficient(Int16 x) { + const Int16 LT = 28576; + Int16 at_cfc = 9830; + Int16 rt_cfc = 328; + + Int16 a = abs(x); // <@\lh{dkgreen}{модуль значения текущего отсчёта}@> + Int16 cmp; + xpeak = (a > xpeak) // <@\lh{dkgreen}{коэффициент x пиковое}@> + ? (_smpy((32767 - at_cfc), xpeak) + _smpy(at_cfc, a)) + : _smpy((32767 - rt_cfc), xpeak); + + if (abs(LT) > abs(xpeak)) // <@\lh{dkgreen}{коэффициент cmp}@> + cmp = (Int16)(((Int32) LT << 15) / ((Int32) xpeak)); + + Int16 f = (cmp < 32767) ? cmp : 32767; + Int16 cfc = (f < g) ? at_cfc : rt_cfc; // <@\lh{dkgreen}{коэффициент cfc}@> + + // <@\lh{dkgreen}{возврат вычисленного коэффициента g}@> + return _smpy((32767 - cfc), g) + _smpy(cfc, f); +} +\end{lstlisting} + +\begin{lstlisting}[language=C,style=CCodeStyle,caption={Полный листинг программы на языке С}, label=code:prog-c] +// DSP, board libraries +#include "C5515.h" +#include "gpio.h" +#include "i2c.h" +#include "i2s.h" +#include "stdio.h" +// <@\lh{dkgreen}{заголовок с функцией oneCountCoefficient}@> +#include "mylimiter.h" + +#define AIC3204_I2C_ADDR 0x18 +#define Rcv 0x08 +#define Xmit 0x20 +extern Int16 aic3204_stereo_in1(); + +volatile Int16 xpeak = 1; +volatile Int16 g = 1; + +Int16 oneCountCoefficient(Int16 x); + +void main(void) { + // <@\lh{dkgreen}{инициализация}@> + c5515_init(); + + // <@\lh{dkgreen}{конфигурирование параллельного порта}@> + SYS_EXBUSSEL &= ~0x7000; + SYS_EXBUSSEL |= 0x1000; + + // <@\lh{dkgreen}{конфигурирование последовательного порта}@> + SYS_EXBUSSEL &= ~0x0C00; + SYS_EXBUSSEL |= 0x0400; + + c5515_GPIO_init(); + c5515_GPIO_setDirection(GPIO10, GPIO_OUT); + c5515_GPIO_setOutput(GPIO10, 1); // <@\lh{dkgreen}{вывод AIC3201 из reset}@> + I2C_init(); // <@\lh{dkgreen}{инициализация I2C}@> + + // <@\lh{dkgreen}{I2S настройки}@> + I2S2_SRGR = 0x0015; + I2S2_ICMR = 0x0028; + I2S2_CR = 0x8012; + + // Режим стерео входа + aic3204_stereo_in1(); + + #define BUF_LENGTH 264 + Int16 left, right; // <@\lh{dkgreen}{отсчеты до примененого эффекта}@> + Int16 out_left = 0; // <@\lh{dkgreen}{отсчеты после примененого эффекта}@> + Int16 leftBuffer[BUF_LENGTH]; // <@\lh{dkgreen}{буфер}@> + Int16 qWrite = 0; + Int16 qRead = -255; + + while(1){ + // <@\lh{dkgreen}{Ожидание прерывания по получению отсчёта}@> + while ((Rcv & I2S2_IR) == 0); + left = I2S2_W0_MSW_R; // <@\lh{dkgreen}{16-битное значение левого канала}@> + right = I2S2_W1_MSW_R; // <@\lh{dkgreen}{16-битное значение правого канала}@> + + g = oneCountCoefficient(left); // <@\lh{dkgreen}{текущий коэффициент}@> + leftBuffer[qWrite++] = left; // <@\lh{dkgreen}{буферизация отсчёта}@> + if (qWrite == BUF_LENGTH) + qWrite = 0; // <@\lh{dkgreen}{не дать флагу записи переполниться}@> + + if (qRead >= 0) { + // <@\lh{dkgreen}{прочитать из буфера и умножить на коэффициент}@> + out_left = _smpy(g, leftBuffer[qRead++]); + if (qRead == BUF_LENGTH) + qRead = 0; // <@\lh{dkgreen}{не дать флагу чтения переполниться}@> + } else { + ++qRead; + } + + while ((Xmit & I2S2_IR) == 0); // <@\lh{dkgreen}{Ждём контроллер прерывания}@> + + // <@\lh{dkgreen}{записать изменённое}@> + I2S2_W0_MSW_W = out_left; + + // <@\lh{dkgreen}{записать не изменённое}@> + I2S2_W1_MSW_W = right; + } +} +\end{lstlisting} + + + +\end{document} diff --git a/02-information-processes-and-sysems-modeling-lecture.tex b/02-information-processes-and-sysems-modeling-lecture.tex new file mode 100644 index 0000000..a48d2a7 --- /dev/null +++ b/02-information-processes-and-sysems-modeling-lecture.tex @@ -0,0 +1,469 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\author{Кадырбаева Анастасия Рустемовна} +\title{Методы исследования и моделирования информационных процессов и технологий} +\date{2022-02-08} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\numerationTop +\usepackage{subfiles} + +\begin{document} +\maketitle +\newpage +\tableofcontents +\newpage +\section{Введение} +Можно послушать курс на курсере. Или курс Systems Engineering Focus Area. + +Литература: Системноинженерное мышление Левенчук 2020. 3 РКх10, 4 ЛРх10. + +ИСО 15288-2015, 42010-2011 + +Курс о процессах, проектируемых системах, нотациях, техтребования, тз, системноинженерное мышление. + +Системная инженерия отличается от инженерий по специальности тем, что в ней используются специальные средства мышления о целостности целевой системы: средства системного мышления, когда слово “система” обозначает не просто любой объект, а именно систему — и в явном виде используются практики системной инженерии. В инженериях по специальности есть свои способы удержания целостности целевой системы в сборке различных требуемых для её создания деятельностей — но эти способы основаны не столько на общих принципах, сколько на глубоком опыте разработки тысяч и тысяч более-менее однотипных систем. Этот опыт достигается специализацией инженерной работы, обучением и воспитанием. + +\subsection{Термины} +\textbf{Процесс} - это набор взаимосвязанны или взаимодействующих действий, преобразующих входы и выходы. Процессы состоят из действий, а действия из задач, которые могут выполнять некоторые акторы(деятели) над/с системой. + +\textbf{Нотация} - множество символов и правил их применения, используемые для представления леусических единиц и их взаимоотношений. + +\textbf{Архитектурный метод описания} - спецификация соглашений для конструирования и применения группы описаний. + +\textbf{Системная инженерия} - междисциплинарный подход и средства для обеспечения реализации успешных систем, определяющий полный набор технических и управленческих усилий, которые требуются для преобразования совокупности потребностей и ожиданий заказчика, имеющихся ограничений. Помогает создателям систем в выделении точек зрения, которые следует использовать для описания мира или разрабатываемой системы. Включает в себя: +\begin{itemize} +\item Эргономика +\item Программная инженерия +\item Управление проектами +\item Управление качеством +\item Менеджмент +\item Математика +\item Компьютерные науки +\item Компьютерная инженерия +\end{itemize} + +Помогает создателям систем в выделении точек зрения, которые следует использовать для описания мира или разрабатываемой системы. Определяет сферу ответственности системного инженера. Предлагает инструментарий для осуществления этой деятельности. + +Суть курса: +\begin{itemize} +\item заложить основы системноинженерного мышления +\item научится работать с нотациями, разрабатывать их по ТЗ и читать +\item освоить методы моделирования информационных процессов. +\end{itemize} + +\textbf{Методологический статус системной инженерии} +\begin{itemize} +\item Методы и процедуры, почерпнутые из современной науки и созданные специально для неё +\item Развитие системной инженерии не имеет законченной теории и строгой формализации, это связано с тем, что чрезвычайно высокая сложность и разнообразие крупномасштабных систем существенно затрудняет использование точных формализованных методов при их создании. +\item В настоящее время системная инженерия представляет собой междисциплинарный комплекс исследований, подходов и методологий к построению и эксплуатации сложных систем любого масштаба и назначения в различных областях человеческой деятельности +\end{itemize} + +Работа с \textbf{терминологией} - в первую очередь работа с естественным человеческим языком. В каждом языке сформировались наборы терминов для разных областей человеческой деятельности. В этих областях термины приобретают значения, то есть обозначают какие-то объекты и их отношения + +Работа с \textbf{онтологией} - попытка понять, как и почему мы выделяем в мире те объекты и отношения, которые обозначаются терминами. Т.о. терминология – про язык и слова, онтология – про мир и его объекты. + + +\textbf{Сообщество} знаний - совокупность людей, которые одинаково понимают суть окружающих предметов и явлений. + +\textbf{Семантика} - наука о связи разных обозначений, символов и общими для разных людей и ситуаций значениями и реального мира. + +\textit{На слайде изображение карты с размеченными разным цветом областями}. Пример: карта, это один уровень описания, на неё можно дополнительно нанести описание дорог, создание меток о наличии препятствий, карта высот. Получается, что класс А описан языком В который содержит грамматики С. Карта будет являться описанием некоторого уровня. Такие многоуровневые описания называются метамоделями. +\begin{figure}[H] + \centering + \begin{tikzpicture}[ + x=0.75pt, y=0.75pt, yscale=-1, xscale=1, + outline/.style={draw=#1, thick}, + outline/.default=black, + antenna/.pic={ + \draw(0,0) -- (0,2); + \draw(0,1) -- (1,2); + \draw(0,1) -- (-1,2); + }, + ] + \tkzblk{outline}{-100,0}{Concept} + \tkzblk{outline}{100,0}{Occurence} + \tkzblk{outline}{0,-75}{Descriptor} + \tkzblk{outline}{0,-200}{Symbol} + \draw[thin] (-100, -15) -- (-10, -185); + \draw[thin] (100, -13) -- (10, -185); + \draw[thin] (-80, -15) -- (-45, -60); + \draw[thin] (80, -13) -- (45, -60); + \draw[thin] (0, -90) -- (0, -185); + \draw[thin] (-62, 0) -- (53, 0); + \node [] at (0,10) {classifies}; + \node [rotate=90] at (-10,-130) {describes}; + \node [rotate=62] at (-70,-100) {symbolises}; + \node [rotate=-62] at (70,-100) {symbolises}; + \end{tikzpicture} + \caption{Метауровни} + \label{pic:metalevels} +\end{figure} + +Метамодели и метауровни позволяют описывать модели мира на разных уровнях. Кто будет составлять? И учёные и инженеры, но у них будут разные уровни описания. + +\subsection{Инженерия и исследования} +\begin{figure}[H] + \centering + \begin{tikzpicture}[ + x=0.75pt, y=0.75pt, yscale=-1, xscale=1, + outline/.style={draw=#1, thick}, + outline/.default=black, + antenna/.pic={ + \draw(0,0) -- (0,2); + \draw(0,1) -- (1,2); + \draw(0,1) -- (-1,2); + }, + ] + \tkzblk{outline}{0,-200}{Компактное описание} + \tkzblk{outline}{0,0}{Создание систем} + \tkzdarr{-30,-185}{-30,-15} + \tkzdarr{30,-185}{30,-15} + + \node [rotate=90] at (-50,-100) {Инженерия}; + \node [rotate=-90] at (50,-100) {Исследования}; + \end{tikzpicture} + \caption{Цикл разработки системы} + \label{pic:metadevel} +\end{figure} + +Инженерия описывает то, как работают инженеры. Другие предметы и науки, которые изучаются инженерией, вроде механики, электроники, математики - описывают поведение инженерных объектов. + +Инженерия, кроме научных теорий активно использует эвристики - догадки о закономерностях, которые вовсе необязательно научны + +Формальные описания инженерных систем позволяют проводить формальный анализ, находить ошибки без создания системы, вычислить необходимые или оптимальные характеристики системы + +Инженерная работа не делается в одиночку. Компактные описания нужны для того, чтобы люди могли иметь одинаковое описание того, что они делают + +Системных инженеров учат на работах предшественников, показывают положительные и отрицательные моменты, учат приёмам работы, которые должны давать хорошие результаты. + +\paragraph{Развитие и совершенствование инженерии} +S-образные графики по диагонали внахлёст как по х так и по у. От нуля перечисляются поколения: +\begin{enumerate} +\item Алхинженерия - неформальные тексты и эскизы +\item Современная (классическая) инженерия - диаграммы, чертежи, псевдокод +\item Моделе-ориентированная (model-based) инженерия - формальные языки (вычисляемый код) +\item ИИ, гибридные вычисления +\end{enumerate} + +\subsection{Система} +\begin{itemize} +\item Иерархия холонов +\item Классы и классификаторы +\item наборы правил, обычаев, процедур, имеющих какую-то структуру +\end{itemize} + +\textbf{Успешная система} - результирующая система проекта, учитывающая ролевые потребности затрагивающих систему и её людей, равно как и потребности, затрагиваемых системой и её проектом людей. + +\textbf{Система} - индивидуальный, уникальный объект, имеющий некоторую протяжённость в пространстве и времени. Имеет изменяющиеся состояния. Системы меняются по мере взаимодействия с окружающими системами, которые тоже находятся в физическом мире, а внутри них меняются взаимодействующие подсистемы. + +\textbf{Документация} - абстрактное описание, записанное на каком-то физическом носителе информации. + +\paragraph{Системность и систематичность.} + +Систематичность - формальное обращение внимания на определённые моменты. Системность - про документацию и предметы окружающего мира. Системность - специальный трансдисциплинарный набор концептов, обращающий внимание на главное и важное. Системность - содержание мышления. Системность - структурирование, представление формального описания, формальное обращение внимание на необходимые вещи, про документацию и предметы окружающего мира. Сразу подразумевает огромное количество умственной и документарной работы. + +\paragraph{Многоуровневость системного разбиения.} + +На самом верхнем уровне - вселенная, на самом нижнем - суперструны. + +Явное указание системного уровня важно для управления вниманием + +Системные уровни принципиальны, они отражают саму суть системного подхода + +Никакого «истинного» или «объективного» разбиения системы на части нет. + +\section{Стандартный язык нотаций UML} +Для разработки ПО нужно понимать, что нужно пользователю. Обсуждать конкретные требования к разрабатываемой системе. Для быстрой и эффективной разработки ПО с имнимальным браком требуется: привлечи рабочую силу, выбрать технологию... + +Зачем нужно моделирование? +\begin{itemize} +\item наглядная демонстрация структуры и поведения +\item визуализация и управление архитектуры системы +\item помогает добить ся лучшего понимания создаваемой системы +\item упрощение системы +\item обеспечивает возможность повторного использования +\item минимизация рисков +\end{itemize} + +Если вы хотите соорудить собачью будку, то можете приступить к работе, имея в наличии лишь кучу досок, горсть гвоздей, молоток, плоскогубцы и рулетку. Несколько часов работы после небольшого предварительного планирования – и вы сколотите вполне приемлемую будку, причем, скорее всего, без посторонней помощи. Если будка получится достаточно большой и не будет сильно протекать, собака останется довольна. В крайнем случае никогда не поздно начать все сначала. + +Если вам надо построить дом для своей семьи, вы, конечно, можете воспользоваться тем же набором инструментов, но времени на это уйдет значительно больше, и ваши домочадцы, надо полагать, окажутся более требовательными, чем собака. Стоит, по меньшей мере, сделать хотя бы несколько эскизов будущей постройки. + +\textbf{Моделирование} – это устоявшаяся и повсеместно принятая инженерная методика. Мы строим архитектурные модели зданий, чтобы помочь их будущим обитателям во всех деталях представить готовый объект. Иногда применяют даже математическое моделирование зданий, чтобы учесть влияние сильного ветра или землетрясения. Очевидно, моделирование применяется не только в строительстве. + +\textbf{Модель} – абстракция физической системы, рассматриваемая с определенной точки зрения и представленная на некотором языке или в графической форме. С точки зрения общих принципов системного анализа одна и та же физическая система может быть представлена несколькими моделями. При этом назначение отдельной модели системы определяется характером решаемой проблемы. Основные требования к модели программной системы состоит в том, что она должна быть понятна заказчику и всем специалистам проектной группы, включая бизнес-аналитиков и программистов. Разработка и использование моделей языка UML осуществляется в рамках общей концепции объектно-ориентированного анализа и проектирования, которая, в свою очередь, является обобщением методологии объектно-ориентированного программирования. + +Модель позволяет: +\begin{itemize} +\item визуализировать систему в её текущем или желательном сосотоянии, +\item описать структуру или поведение системы, +\item получить шаблон, позволяющий сконструировать систему, +\item докуентировать принимаемые решения, используя полученные модели. +\end{itemize} + +\subsection{Принципы моделирования} +\begin{enumerate} +\item Выбор модели оказывает определяющее влияние на подход к решению проблемы и на то, как будет выглядеть это решение. Правильно выбранная модель высветит самые опасные проблемы разработки и позволит описать суть задачи. Даёт дополнительную информацию, позволяет проработать больше различных сценариев. Каждая модель может быть представлена с различной степенью точности. + +Мы будем использовать диаграммы Феймана, которая позволит описать задачу с разных точек зрения. Если вы смотрите на систему глазами разработчика баз данных, то внимание будете уделять моделям «сущность-связь», где поведение инкапсулировано в триггерах и хранимых процедурах. Аналитик, использующий структурный подход создал бы модель, в центре которой находятся алгоритмы и передача данных от одного процесса к другому. Результатом труда разработчика, пользующегося объектно-ориентированным методом, будет система, архитектура которой основана на множестве классов и образах взаимодействия, определяющих как классы действуют совместно. Любой из этих вариантов может оказаться подходящим для разработки методики или приложения. Хотя более эффектинвой будет объектно-ориентированная точка зрения при создании гибких архитектур. +\item Каждая модель может быть представлена с различной степенью точности. + +Лучшей моделью окажется та, которая позволит выбрать уровень детализации в зависимости от того, кто и с какой целью на нее смотрит. Для аналитика или конечного пользователя наибольший интерес представляет вопрос «что», а для разработчика – «как». В обоих случаях необходима возможность рассматривать систему на разных уровнях детализации в разное время. +\item лучшие модели те, что ближе к реальности. Модель всегда упрощает реальность, задача - чтобы упрощение не повлекло за собой существенные потери. Проблема при проектировании ПО - несоответствие принятой в нём модели и модели системного проекта. При объектно ориентированного подхода можео объединить все почти независимые представления системы в единое семантическое целое. + +При объектно-ориентированном подходе можно объединить все почти независимые представления системы в единое семантическое целое. +\item нельзя ограничиваться созданием только одной модели. + +Наилучший подход при разработку любой нетривиальной системы – использовать совокупность нескольких моделей, почти независимых друг от друга. Если вы конструируете здание, никакой отдельный комплект чертежей не поможет вам прояснить все детали до конца. Понадобятся как минимум поэтажные планы, виды в разрезе, схемы электропроводки, центрального отопления и водопровода. +\end{enumerate} +Для понимания архитектуры подобной системы требуется несколько взаимодополняющих представлений: +\begin{itemize} +\item представление с точки зрения вариантов использования (чтобы выявить требования к системе); +\item с точки зрения проектирования (чтобы построить словарь предметной области и области решения); +\item с точки зрения взаимодействий (чтобы смоделировать взаимодействия между частями системы, системой в целом и средой ее функционирования); +\item с точки зрения реализации (позволяющее рассмотреть физическую реализацию системы); +\item с точки зрения размещения (помогающее сосредоточиться на вопросах системного проектирования). +\end{itemize} +Каждое из перечисленных представлений имеет множество структурных и поведенческих аспектов, которые в своей совокупности составляют детальный чертеж программной системы. + +\subsection{Методы моделирования, UML} +Алгоритмический +\begin{itemize} +\item традиционный подход к созданию ПО; +\item основан на процедурах и функциях; +\item вопросы передачи управления и декомпозиции б\'{о}льших алгоритмов на меньшие. +\end{itemize} + +Объектно-ориентированный +\begin{itemize} +\item современный подход; +\item основные блоки - объекты и классы; +\item каждый блок обладает идентичностью, состоянием и поведением. +\end{itemize} + +ОО подход помогает отвечать на вопросы: +\begin{itemize} +\item какая структура должна быть у хорошей ОО архитектуры +\item какие артефакты должны быть созданы в процессе работы над проектом +\item кто создаёт артефакты +\item как оценить результат работы +\end{itemize} + +Унифицированный язык моделирования (Unified Modeling Language – UML) – это стандартный инструмент для разработки «чертежей» программного обеспечения. Его можно использовать для визуализации, спецификации, конструирования и документирования артефактов программных систем. UML – всего лишь язык, и как таковой представляет только одну из составляющих процесса разработки программного обеспечения. Хотя UML не зависит от моделируемых процессов, лучше всего применять его в тех случаях, когда процесс моделирования основан на применении вариантов использования, сконцентрирован на архитектуре системы, является итеративным и пошаговым. + +UML – это язык для визуализации, специфицирования, конструирования и документирования артефактов программных систем. Язык представляет словарь и правила комбинирования входящих в него слов в целях коммуникации. Язык моделирования – это язык, словарь и правила которого сосредоточены на концептуальном и физическом представлении системы. UML – стандартное средство представления «чертежей» программного обеспечения. Нотация представляет собой совокупность графичеких элементов, которые используются в моделях. + +Моделирование необходимо для понимания системы. При этом ни одна модель не является абсолютно достаточной. Напротив, чтобы понять большинство систем, кроме самых тривиальных, часто требуется множество взаимосвязанных моделей. В отношении программных систем это означает, что необходим язык, средствами которого можно описать архитектуру системы с различных точек зрения, причем на протяжении всего жизненного цикла ее разработки. +Словарь и правила такого языка, как UML, говорят о том, как создавать и читать хорошо согласованные модели, но не говорит о том, какие именно модели в каких случаях требуется создавать. Это задача всего процесса разработки программного обеспечения. Хорошо организованный процесс должен сам подсказать, какие потребуются рабочие продукты, какие ресурсы понадобятся для их создания и управления ими, как их использовать для оценки выполненной работы и управления проектом в целом. + +UML имеет три вида блоков: +\begin{itemize} +\item Сущности – абстракции, которые являются основными элементами модели + \begin{itemize} + \item Структурные – в основном это статические части модели, представляющие либо концептуальные, либо физические элементы. В совокупности структурные сущности называются классификаторами. Структурные сущности это: класс, интерфейс, кооперация (collaboration), компонент, артефакт, сервер. + \item Поведенческие – динамические части моделей. Так сказать «глаголы», представляющие поведение во времени и пространстве. Это: взаимодействие (interaction, обмен сообщениями между наборами объектов или ролей в определенном контексте достижения целей), автомат (state machine, поведение, характеризуемое последовательностью состояний объекта), деятельность (activity – последовательность шагов вычислений). + \item Группирующие сущности – организованная часть моделей. Самый распространенный элемент – пакет, т.е. механизм общего назначения для организации проектных решений, который упорядочивает конструкцию реализации. + \item Аннотирующие сущности – т.е. поясняющие части, комментарии для описания выделения и пояснения любого элемента модели. Примечания. + \end{itemize} +\item Связи – соединяют между собой сущности + \begin{itemize} + \item Зависимость – связь между двумя элементами модели, в которой изменение одного элемента может привести к изменению семантики другого элемента. + \item Ассоциация – структурная связь между классами, которая описывает набор связей, существующих между объектами – экземплярами классов. Агрегация – особая разновидность ассоциации, представляющая структурную связь целого с его частями. + \item Обобщение – связь, в которой специализированный элемент (потомок) строится по спецификациям обобщенного элемента (родителя). + \item Реализация – семантическая связь между классификаторами, когда один из них специфицирует соглашение, которого второй обязан придерживаться. + \end{itemize} +\item Диаграммы – группируют представляющие интерес наборы сущностей. +\end{itemize} + +\subsection{Правила UML} +Хорошо согласованная модель - та, которая семантически самосогласована и находится в гармонии со всеми другими моделями, связанными с ней. + +\subsection{Механизмы UML} +\textbf{Спецификация.} За каждой частью его графической нотации стоит спецификация (specification) содержащая текстовое представление синтаксиса и семантики определенного строительного блока. С помощью графической нотации UML вы визуализируете систему, с помощью спецификаций UML описываете ее детали. Таким образом, допускается последовательное построение модели – шаг за шагом, когда сначала рисуются диаграммы, а затем добавляется семантика к спецификациям модели, – или же напрямую, когда в первую очередь создаются спецификации (возможно, при выполнении обратного проектирования существующей системы), а затем рисуются диаграммы, представляющие их проекции. +Спецификации UML создают семантический задний план, который включает в себя все составные части всех моделей системы, согласованные между собой. Таким образом, диаграммы UML – это простые визуальные проекции на этот задний план, при этом каждая из них раскрывает некоторый существенный аспект системы. + +\subsection{Архитектура} +Архитектура программного обеспечения касается не только его структуры и поведения, но также пользовательских свойств, функциональности, производительности, гибкости, возможности повторного использования, понятности, экономических и технологических ограничений и компромиссов, а также эстетических вопросов. + +\textbf{Архитектура} набор существенных решений относительно организации программной системы, выбора структурных элементов, составляющих систему и их интерфейсов; поведения этих элементов, определенного в их кооперациях; объединения структурных и поведенческих элементов в более крупные подсистемы; архитектурного стиля, определяющего организацию системы? Статические и динамические элементы и их интерфейсы, кооперацию и композицию. + +\subsection{Представления} +\section{MDA, MDD, генерация кода} +MDA - model-driven architecture - суть в построении метамодели управления и обмена метаданными с заданием разных способов и технологий программирования. Модель - это основной артефакт разработки, из которой будет генерироваться не только код, но и другие артефакты. Главный стандарт - UML. Достоинство - множество методов описания, множество уровней. Есть недостаток в выразительности, ограниченности архитектуры языком UML. + +MOF - meta object facility. Стандарт, целью которого является предоставление системы типов для сущностей и набор интерфейсов с помощью которых можно создавать эти типы. Реализовано как четырёхслойная архитектура. Помимо этих уровней есть средства описания моделей, например стандарт XMI который может и поддерживать МОФ и описывать модели сам по себе, аналогично уровням 1-3 МОФа. + +EMF - Eclipse Modeling Framework. Предназначен для понятного метамоделирования и визуализации моделей. Модели просты, но предназначены для смешивания с написанным «от руки» кодом. обеспечивает унифицированное представление структур данных, описанных в приложении. Модели представлены в виде внутренней структуры. + +(слайд 13) Применение моделе-управляемого подхода. Получаем второй этап: платформо-независимые модели. Важным аспектом будет визуальное моделирование. Третий этап - это платформо-зависимые модели. Четвёртый этап - это генерация кода. Ecore поддерживает джавские аннотации и поэтому может создавать экземпляры модели. ЕКор поддерживает ряд других концепций, которые не поддерживаются джавой, например, двунаправленные отношения. + +Представление вариантов использования системы охватывает варианты использования, описывающие поведение системы с точки зрения конечных пользователей, аналитиков и тестировщиков. +Их взгляд в дейст вительности специфицирует не истинную организацию программной системы, а лишь некие движущие силы, формирующие системную архи тектуру. В языке UML статические аспекты этого представления передаются диаграммами вариантов использования, а динамические его аспекты – диаграммами взаимодействий, состояний и деятельности. +Представление системы с точки зрения дизайна охватывает классы, интерфейсы и кооперации, формирующие словарь проблемы и ее решение. Это представление в основном поддерживает функциональные требования к системе, то есть сервис, который она должна предоставлять конечным пользователям. Статические аспекты этого представления в UML сосредоточены в диаграммах классов и объектов, а динамические передаются диаграммами взаимодействий, состояний и деятельности. Диаграмма внутренней структуры класса, в частности, также полезна. +Представление взаимодействия системы показывает поток управления, проходящий через разные ее части, включая возможные механизмы параллелизма и синхронизации. Это представление касается производительности, масштабируемости и пропускной способности системы. Статические и динамические аспекты этого представления в UML представлены в некоторых видах диаграмм, используемых в представлении дизайна, но сфокусированы на активных классах, управляющих системой, и передаваемых между ними сообщениях. +Представление реализации системы охватывает артефакты, используемые для сборки и физической реализации системы. Это представление в первую очередь относится к управлению конфигурацией версий системы, состоящей из независимых (в определенной степени) файлов и компонентов, которые могут быть собраны различными способами для формирования работающей системы. +Оно также связано с отображением из логических классов и компонентов в физические артефакты. В UML статические аспекты этого представления отражены в диаграммах артефактов, динамические аспекты – в диаграммах взаимодействия, состояний и деятельности. +Представление развертывания системы охватывает узлы, образующие топологию оборудования, на котором работает система. Это представление в основном связано с поставкой, распределением и установкой частей, составляющих физическую систему. Его +статические аспекты в UML описываются диаграммами размещения, а динамические – диаграммами взаимодействий, состояний и деятельности. Каждое из этих пяти представлений может быть достаточным для различных заинтересованных лиц, имеющих отношение к разработке и эксплуатации системы, позволяя им сосредоточиться только на тех аспектах архитектуры, которые непосредственно их касаются. Однако все эти представления также взаимодействуют друг с другом. Узлы из представления размещения содержат компоненты из представления реализации, которые, в свою очередь, представляют собой физическую реализацию классов, интерфейсов, коопераций и активных классов из представлений дизайна, и взаимодействия. + +\section{X-Text} +Язык DSL - структура отражает решаемые языком задачи. DSL - это предметно-специфический язык (domain-specific language). Объединяет кроме текста и графики ещё и концептуальную часть. Деление довольно условно, потому что любой описанный протокол на общих языках - это вариация DSL. Это ЯП более высокого уровня абстракции и оперируют правилами. + +Преимущества языка и движка трансформации позволяет значительно повышать эффективность определённых этапов разработки. Позволяет отдельить важное от неважного. размывает границы между аналитиками и техническими специалистами. + +Использует грамматику основного языка, может формировать внутренние DSL. + +Правила Х-текста +\begin{itemize} +\item правила лексем +\item правила данных +\item правила разбора +\end{itemize} +Х-текст значительно упрощает формальный язык. + +Семантические правила закладываются в два этапа - на этапе написания грамматика и на этапе внедрения. Можно описывать валидацию программ (статический анализ на предмет корректности). Формируем абстрактное синтаксическое дерево. + +эклипс предоставляет интерфейс для встраивания новых отладчиков. платформа многопоточна. + +\section{Archmate Framework} +архитектор предприятия - это технический специалист, который получил специальное образование, способный заниматься проектированием, анализом и внедрением информационных систем. Архитектура организации это область знаний об организованности отдельных элементов предприятия. Архитектура - это совокупность некоторых принципов и правил. + +Корректная архитектура несёт преимущества для бизнеса. Потребность в архитектуре есть в организациях со сложной организацией. Сложные структуры легче разбивать на модели. Для адекватного моделирования следует различать функциональные, организационные и поведенческие модели. + +Модель закмана - это таблица из 6 столбцов и 6 строк, описывающая 6 точек зрения и 6 аспектов деятельности (вопросов). В общем виде самая распространённая и простая, но есть ряд недостатков - не накладывает ограничений на изменение, нет динамики. С другой стороны можно расширять, не накладывает ограничений на использование единой программной системы моделирования. + +Модель TOGAF. включает 4 области описаний: бизнес, приложения, архитектура данных, технологическая (инфраструктура). + +Модель Garner фактически не определяет ничего. в методике сформулированы ряд шагов, не детализированных до конкретных процессов. этапов 4 - бизнес, техническая архитектура, инфраструктура, безопасность. в 2007 добавили таймлайн, то есть наложили изменения системы на временную ось. Архитектура предприятия может иметь больше трёх осей (измерений). Элементы очень похожи на UML. Есть механизм типов. Для каждого типа вопросов есть своя диаграмма. + +Archmate. +делит модели на внутреннюю и внешнюю структуру. Сервис и интерфейс - это единицы функциональности, которые предоставляют приложения внутри или снаружи + +При описании часто описываются только внутренние работы, только один уровень работы или ориентированно на сервис. + +\newpage +\section{BPMN} +модель должна давать полное точное и адекватное описание системы. +нотация - это графические элементы для построения модели +аналитическое моделирование заключается в построении модели, основанной на описании поведения объекта или системы объектов в виде аналитических выражений. разработка исполняемых моделей использует более точные методы моделирования. + +бпмн чаще используется для более верхнеуровневого описания. если модель перестала быть актуальной то надо выявлять целесообразность документирования часто меняющейся модели. Задача бпмн - описание продуктов и процессов для бизнес-аналитиков и руководителей. Связующее звено между пользователями и разработчиками. то есть понятно широкому кругу людей. нотация позволяет начать с высокоуровневой аналитики. по мере понимания работы модель уточняется и преобразуется в исполняемую модель. + +бизнес-процесс, в отличие от бизнес-проекта (достигающего уникального результата) есть технология достижения результата, предполагается повторяемость действий и воспроизводимость результата. технология - совокупность методов и инструментов. Операция - единица работы, выполняемая непрерывно. Действие - акта взаимодействия оператора с обрабатываемым изделием. + +Есть три уровня управления: +\begin{enumerate} +\item оперативное - исполнение каждого экземпляра с целью выявить те, которые выполняются с отклонениями. уменьшает число брака +\item тактическое - контроль показателей на краткосрочном интервале. не предполагает изменения процессов +\item стратегическое - контроль параметров на долгосрочном интервале. маркетинговые исследования, корпоративный дизайн. +\end{enumerate} + +применяется для описания и документации процессов. на втором уровне - аналитические процессы, позволяет описать и для айти сферы. на третьем уровне - описание для исполнителей. + +\section{GSN, i*} +Зачем выявлять требования? чтобы сделать точные и достаточные сценарии. Цели помогают понять кто чего хочет, объяснить угрозы, понять корректирующие меры и альтернативы. + +все сценарии пишутся в определённой последовательности. обычно описывается луковичной диаграммой. на таких диаграммах показывают как позитивных так и негативных стейкхолдеров. + +ставим цель, выбираем стратегию, строим предположения. в целях описываются все цели и требования заинтересованных сторон, кандидаты в требования, альтернативные варианты, могут противоречить одни другим, могут быть не всегда реалистичны, могут оказаться возможными только для некоторых вариантов. + +Варианты - альтернативные подходы к решениям на любом уровне - функции ПО, конкурирующие за время/бюджет разработки, свойства ПО, конкурирующие за энергосбережение, массу итд, альтернативные алгоритмы достижения данной цели. + +Критерии прохождения развилок на основе целей - размерности в котором оцениваются цели. + +Предполагается следующий алгоритм: +\begin{itemize} +\item моделируем цели +\item определяем контекст +\item определить интерфейс +\item исследовать варианты +\item ... +\end{itemize} + +в модели требований обозначается область применения, область проекта и область конструирования системы. + +SD - Strategic dependency - обеспечивает намеренное описание процесса в терминах отношений зависимости между участниками. состоит из набора узлов и ссылок. Для такого описания нам нужны сущности, действия и утверждения. зависимости потребуются от ресурсов, задач, целей и программных целей - основан на понятии нефункциональных требований в разработке ПО. Модель зависимостей использует роли и агентов. + +GSN - Goal Structuring Notation +Результат должен быть достижим. Цели структурируют чтобы предварительно подготовить аргументы, используется для выделения того, чего не хватает на схеме или в начинании. + +\appendix +\setcounter{secnumdepth}{0} +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Alph{subsection}} + +\subsection{Семинар 1 2022-02-11} +Систему можно рассматривать с разных точек зрения (программист, аналитик, заказчик). Система имеет назначение в своём физическом окружении. Назначение системы - это её функция или поведение, игра по роли. Система прежде всего называется по её роли/назначению/поведению, функции. + +Ролевой объект может иметь имя, отличающееся от имени конструктивных объектов, которые рассматриваются вне окружения. Роли и стейтхолдеры в танцах: танцор, партнёр, зритель, хореограф, тренер/педагог, музредактор, организатор мероприятия, худкостюм, гримёр, фотограф/видеограф, судьи. + +В роль неправильно указывать +\begin{itemize} +\item человека +\item начальника +\item звание +\item организацию +\end{itemize} + +В проекте достаточно указать 5 внешних ролей. Обычно забывают про множественность интересов и собственные интересы. Системные уровни: +люди 5 мин в локации с 16.05 и до 16.10 танцуют: +\begin{itemize} +\item врач смотрит с точки зрения здоровья +\item тренер смотрит на системные органы +\item учитель смотрит на то как выполняются движения +\item хореограф смотрит на общую композицию +\item зрители и родственники смотрят на сочетание картинки и ритма +\end{itemize} + +\subsubsection{Задание: диаграмма активности} +Испольуется для описания процессов в зависимости от текущего состояния системы (см диаграмму состояний). Стандартизирует внешний вид описания действий, непосредственной логики. +\begin{itemize} +\item прямоугольник с закруглениями - обычная операция +\item ромб - обычно if, но формально - switch +\item широкие полосы - многопоточность, параллелизм +\item начало +\item конец +\end{itemize} + +% -танец +% --начало (партнёры вместе) +% --свимлейны +% --танцор-девушка +% ---упасть назад +% --танцор-мужчина +% ---попытаться поймать партнёршу +% ---условие: если поймал +% ----да (ничего не делать) - следующее действие - параллельность +% ----нет (упасть рядом) +% -----конец +% --параллельность +% ---свои собственные движения каждого партнёра происходящие одновременно +% --конец параллельности +% --танец (движения партнёров, элементы парного танца) +% --условие: в процессе танца на сцену бросили букет +% ---да (сделать его элементом танца) +% ---нет (ничего не делать) +% --вернуться к условию +% --конец + +% -а ещё есть расширение SDL которое формализует прямоугольники для описания +% СОСТОЯНИЕ +% ВЫЗОВ ПРОЦЕДУРЫ +% ВВОД +% ВЫВОД +% СОХРАНЕНИЕ +% ЗАДАЧА +% РЕШЕНИЕ + +\subsection{Семинар 2 2022-02-25} +Диаграмма классов. +\begin{enumerate} +\item в е ж \item а б \item б е ж \item б в г д е +\item в \item г \item б г \item е \item в г +\item а б в г е з \item б \item а б в г \item в +\end{enumerate} +\end{document} diff --git a/02-information-systems-knowledge-representation.tex b/02-information-systems-knowledge-representation.tex new file mode 100644 index 0000000..8074d72 --- /dev/null +++ b/02-information-systems-knowledge-representation.tex @@ -0,0 +1,3209 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\author{Девятков Владимир Валентинович (Лычков Игорь Игоревич)} +\title{Представление знаний в информационных системах} +\date{2022-02-08} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\numerationTop + +\begin{document} +\maketitle +\newpage +\section{Искусственный интеллект и знания} +\textit{Повтор тем из бакалавриата.} + +Чем отличается искусственный интеллект от не искусственного? Возможность генерации новых знаний + +Что такое слабый ИИ и что такое сильный ИИ? Осознание себя. + +Человек именует себя homo sapiens, что означает мудрое существо или существо, обладающее умом (интеллектом), тем самым, подчеркивая важность для своего существования именно умственных или интеллектуальных способностей. Область знаний искусственного интеллекта (ИИ) пытается понять и использовать сущность этих способностей. + +\paragraph{John McCarthy} +Ввёл термин более 50 лет назад (1956). Предложение: «Область исследования ИИ отталкивается от гипотезы, состоящей в том, что каждый аспект поведения человека, имеющий признаки интеллектуальности может быть, в принципе, настолько точно описан, что по этому описанию может быть создана машина способная моделировать это поведение». + +\paragraph{А́лан Мэ́тисон Тью́ринг} +Английский математик, логик, криптограф, оказавший существенное влияние на развитие информатики. \textit{Фильм: Игра в имитацию}. +А. Тьюринг предложил «игрушечный» тест, называемый в настоящее время «тестом Тьюринга», который мог бы служить средством выявления интеллектуальности. Суть этого теста состоит в следующем. В одном помещении находится человек, а в другом машина, созданная кем-то, например, тем же человеком. Они беседуют друг с другом на интересующие человека темы. Если в процессе этой беседы человек не может отличить, кто же там за стеной, человек или машина, то в этом случае машину следует признать интеллектуальной. Этот тест основан на предположении, что любая беседа двух людей является интеллектуальной. + +\paragraph{Психология} +Психологи считают, что интеллект - это «свойство личности, выражающееся в способности глубоко и точно отражать в сознании предметы и явления объективной действительности в их существенных связях и закономерностях, а также в творческом преобразовании опыта. ... система ориентировки на существенные отношения решаемой задачи... ядро ... собственно интеллекта составляет способность выделить в ситуации ее существенные для действия свойства в их связях и отношениях и привести свое поведение в соответствие с ними» + +\paragraph{Информатика} +«Восхищающие новые усилия заставить компьютеры думать... машины с разумом в полном и языковом смысле» (J.Haugeland, 1955). + +«Автоматизация деятельности, которую мы ассоциируем с человеческим мышлением, такой как принятие решений, решение задач, усвоение знаний» (R. E. Bellman, 1978). + +«Исследование умственных способностей с помощью ипользования вычислительных моделей» (E. Charniak and D. McDermot, 1985). + +«Область исследования, которая пытается понять и моделировать разумное поведение в терминах вычислительных процессов» (R. J. Schalkoff, 1990). + +«Исследование того, как заставить компьютеры делать вещи не хуже людей» (E. Rich and K. Knigpt, 1991). + +\textit{«Изучение исчислений, которые позволяют понимать, рассуждать и действовать»} (P. H. Winston, 1992). + +«Отрасль науки о компьютерах, которая интересуется автоматизацией разумного поведения» (J. I. Luger and W. A. Stubblefield, 1993). + +\subsection{Сильный и слабый искусственный интеллект} +\textbf{Сильный} искусственный интеллекта предполагает, что компьютеры могут приобрести способность мыслить и осознавать себя, хотя и не обязательно их мыслительный процесс будет подобен человеческому. +\textbf{Слабый} искусственный интеллект отвергает такую возможность. + +На английском соответствующие термины это — «Artificial Intelligence», «strong AI», «full AI» для сильного ИИ и «applied AI», «narrow AI» или «weak AI» — для слабого ИИ. Термин «сильный ИИ» был введён Джоном Сёрлем, который охарактеризовал его следующим образом: «Сильный ИИ - это не просто модель разума, а собственно разум в том же смысле, в котором человеческий разум — это разум». + +\paragraph{Свойства сильного ИИ} +\begin{itemize} +\item Представление знаний, включая общее представление о реальности; +\item Планирование; +\item Обучение; +\item Общение на естественном языке; +\item Сознание: Быть восприимчивым к окружению; +\item Самосознание: Осознавать себя как отдельную личность, в частности, понимать собственные мысли; +\item Сопереживание: Способность «чувствовать», соучаствовать; +\item Мудрость. +\end{itemize} + +\paragraph{Системы ИИ} +Под системами искусственного интеллекта или интеллектуальными системами принято понимать системы, которые с участием человека или без позволяют решать различные сложные интеллектуальные задачи Пример: мультиагентные интеллектуальные системы. + +\paragraph{ИИ и сложные задачи} +Одна из главных причин прикладного интереса к искусственному интеллекту - это стремление создавать на его основе интеллектуальные искусственные системы способные решать сложные задачи. Это не означает, что сложные задачи не могут решаться без искусственного интеллекта. Но поскольку человек способен решать сложные задачи благодаря своему интеллекту, то, следовательно, копируя и развивая системы искусственного интеллекта, можем надеяться, что они будет способны делать то же самое. +Оценка сложности задачи +\begin{itemize} +\item Время, затрачиваемое на решение задачи, как функция размера задачи, называется временной сложностью ее решения. +\item Поведение этой сложности в пределе при увеличении размера задачи называется асимптотической временной сложностью. +\item Аналогично можно определить емкостную сложность и асимптотическую емкостную сложность. +\item Асимптотическая сложность решения определяет размер задач, которые возможно решить, используя соответствующие средства. +\end{itemize} +Зададим функции $f(n), q(n)$, где $n = 0, 1,...$ – размерность задачи. +Введем обозначение $f(n) = O[q(n)]$, означающее $f(n) = q(n)$ для больших n, если $\lim f(n)/q(n) = 1$. + + Пример: $f(n) = kn + kn - 1 + ... k0, q(n) =kn$, + + \[ \lim (f(n)/q(n)) = \lim (1 + 1 / k + ... + 1 / kn - 1) = 1. \] +Здесь $k$ – достаточно большая константа. + + +Решение задачи имеет асимптотическую сложность $O[q(n)]$, если $f(n)=O[q(n)]$. Функцию $f(n)$ называют функцией сложности. + +Задачи, для которых $f(n) = O(nc)$, где $с$ – неотрицательная константа, называют полиномиальными. В частности, при $с=0$ сложность $О(1)$ означает, что время работы задачи не зависит от n. + +Если $f(n) = O(n)$, то задача линейна по сложности. + +Задачи полиномиальной сложности принято считать эффективными. Для них $f(n)$ имеет вид: и т.п. $O(1)$, $O(n)$, $O(n \log n)$, $O(n2)$, $O(n3)$. + +Существуют неполиномиальные задачи, функции сложности которых растут быстрее любого полинома. Это высокозатратные задачи с точки зрения требуемых вычислительных ресурсов. +Пусть $f(n)$ и $f^{*}(n)$ – функции сложности задач $A$ и $A^{*}$ соответственно. + +Задача $A^{*}$ считается асимптотически менее сложной, чем задача $A$, если $f^{*}(n) = O[f(n)]$. + +При выборе функции сложности $f(n)$ возможна ориентация на один из следующих случаев: +\begin{itemize} +\item $f(n)$ характеризует максимально возможное время работы задачи; +\item $f(n)$ характеризует минимальное время выполнения задачи при некоторых «хороших» входных данных; +\item $f(n)$ учитывает вероятности появления тех или иных («хороших» или «плохих») входных данных. +\end{itemize} +С практической точки зрения важны случаи 1 и 2, поскольку они позволяют оценивать потенциальные возможности решать задачи большой размерности за приемлемое время + +\paragraph{Трудноразрешимые задачи} +Задачи, которые не удается решать за полиноминальное время, трудноразрешимыми. К классу трудноразрешимых задач относится большое число задач алгебры, математической логики, теории графов, теории автоматов и других разделов дискретной математики. В большинстве своем это так называемые переборные задачи. Переборная задача характеризуется экспоненциальным множеством вариантов, среди которых нужно найти решение, и может быть всегда решена полным перебором. + +Полный перебор имеет экспоненциальную сложность и может хорошо работать только для небольших размеров задачи. С ростом размера задачи число вариантов быстро растет, и задача становится практически неразрешимой. Возникает вопрос: если известно, что некоторая задача разрешима, то неудача в разработке для нее полиномиального решения является следствием неумения конкретного разработчика или следствием каких-то свойств самой задачи? + +\paragraph{Распознавательные задачи} +Ответ на этот вопрос дает классическая теория алгоритмов, которая классифицирует задачи по сложности. При этом классифицируются лишь распознавательные задачи – задачи, имеющие распознавательную форму. В распознавательной форме суть задачи сводится к распознаванию некоторого свойства, а ее решение – один из двух ответов: «да» или «нет». С точки зрения математической логики задаче распознавания свойства соответствует задача выяснения при каких значениях переменных х предикат $Р(х)$ истинен, а при каких ложен. + +Существуют задачи, которые изначально имеют распознавательную форму. Например, являются ли два графа изоморфными? Другой пример – задача о выполнимости булевой функции, которая является исторически первой распознавательной задачей, глубоко исследованной в теории алгоритмов. Многие задачи, которые в исходной постановке представлены в иной форме (к ним относятся задачи дискретной оптимизации), довольно просто приводятся к распознавательной форме. + +Между тем, имеются задачи, которые нельзя привести к распознавательной форме. Это, в первую очередь, конструктивные задачи, например, задачи на построение объектов дискретной математики, обладающих заданными свойствами: генерация всех подмножеств конечного множества; Такие задачи могут быть как трудноразрешимыми, так и полиноминально разрешимыми. Они пока не попадают под существующую в теории алгоритмов классификацию. + +\textit{Распознавательные задачи удобно решать методами искусственного интеллекта.} + +\subsection{Знания} +Знания – основа интеллектуальности систем. Обычно выделяют 2 типа знаний: +\begin{itemize} +\item Декларативные +\item Процедурные +\end{itemize} +Знания в системах искусственного интеллекта обычно хранятся в базах знаний. Знания содержат информацию как о конкретных (константных) фактах о той или иной предметной области (среде, мире), так и о более общих законах и свойствах, позволяющих получать (выводить) новые знания. Понятие «знание» имеет два аспекта: декларативный и процедурный. + +\paragraph{ИИ и знания} +\begin{itemize} +\item ИИ функционирует на основе знаний +\item ИИ занимается созданием специализированных моделей и языков для представления знаний в ЭВМ, +\item ИИ занимается созданием специальных средств, позволяющих пополнять и обобщать знания. +\item ИИ занимается созданием программных и аппаратных средств для работы со знаниями; +\item ИИ занимается созданием методов формирования планов достижения целей и решения сложных задач, не поддающихся решению другими методами, кроме как на основе использования знаний; +\item ИИ занимается созданием средств восприятия мультимодальной информации (зрительной, слуховой, тактильной и др), +\item ИИ занимается развитием методов мультимодальной обработки и формирования ответных реакций на воздействия внешней среды, +\item ИИ занимается развитием методов адаптации искусственных систем к среде путем обучения. +\end{itemize} + +\subsection{Формальная теория, формальный язык} +\label{subsec:formal-theory} +Формальная теория (формальная система, в значительной части - исчисления) - это тройка $\Re = \{L, S, C\}$, где +\begin{itemize} +\item [] $L$ – язык формальной модели с присущими ему синтаксисом, т.е. $L = \{T, G\}$, +\item [] $S$ – совокупность начальных знаний, сформулированных на языке $L$; +\item [] $C$ – абстрактная машина или машина вывода, которая, используя правила вывода $P$ и определенную стратегию вывода, осуществляет формирование в языке $L$ новых знаний, начиная с начальных. +\end{itemize} + +Таким образом машина вывода является двойкой $C = \{P, \Omega\}$, где $\Omega$ - стратегия вывода, согласно которой абстрактная машина $C$, используя правила вывода $P$ осуществляет вывод. Правила вывода не обязательно являются правилами логического вывода, поскольку формальные модели могут быть не только логическими. Формальную теорию называют также формальной моделью, формальной системой или исчислением. + +\textbf{Дедуктивное рассуждение} развивается от общего к частному (от посылки к следствию). Пример дудуктивного рассуждения: «Все люди смертны, Сократ – человек, следовательно, Сократ смертен». + +\textbf{Абдуктивное рассуждение} – это «обратная» дедукция, так сказать, дедукция, поставленная с ног на голову. Абдуктивное рассуждение развивается по сравнению с дедуктивным в противоположном направлении, то есть от следствия к посылке. Пример абдуктивного рассуждения: «Все люди смертны, Сократ смертен, следовательно, Сократ человек». Может показаться, что здесь все нормально, но если вдуматься, то становится ясно, что вывод неправильный. Из того, что Сократ смертен, совсем не следует, что Сократ человек, ведь смертны и кошки, и собаки, и бабочки, и, может быть, деревья. + +\textbf{Индуктивное рассуждение} развивается от частного к общему (от следствия к посылке). + +\paragraph{Формальный язык} +Формальный язык $L$ в соответствии с современными представлениями требует рассмотрения двух его неотъемлемых частей: синтаксиса и семантики. + +\textbf{Синтаксис} языка описывает допустимые в языке предложения, состоящие из цепочек терминальных символов, принадлежащих определенному терминальному алфавиту. Синтаксис языка позволяет отличать предложения, принадлежащие языку, от предложений, ему не принадлежащих. + +\textbf{Семантика} языка определяет смысл предложений языка. Без семантики предложения языка являются ничего незначащими цепочками символов. + +\textbf{Формализацией задачи} будем называть создание для ее решения формальной модели. Формальным решением задачи будем называть осуществление решения задачи с помощью формальной модели. + +\paragraph{Декларативные и процедурные знания} +\textbf{Декларативные знания} не содержат в явном виде описание процедур, которые необходимо выполнить в процессе вывода. Вывод на основе декларативных знаний осуществляется по определенной стратегии вывода специальной машиной вывода (решателем). Например, вывод (поиск решения) может быть организован как поиск в пространстве состояний, и сводится к нахождению последовательности состояний ведущих из начального состояния (начальных) в целевое состояние. + +\textbf{Процедурные знания} - это знания, представляемые в виде процедур, с помощью которых осуществляется вывод. Вывод на основе процедурных знаний также может осуществляться машиной вывода, организующей вызов процедур в соответствии с определенной стратегией. + +Сочетание преимуществ декларативного и процедурного подхода к представлению знаний по-разному воплощается в различных языках и моделях представления знаний. + +Какое представление знаний нам необходимо? +\begin{itemize} +\item Насколько представление знаний должно быть понятным и ясным? +\item Насколько представление знаний должен быть лаконичным? +\item Насколько оно должно быть вычислительно эффективным (способным порождать новые знания)? +\item Насколько оно должно быть модульным? +\item Насколько оно должно быть доступным из разных мест? +\item Какова должна быть охватываемая область представления? +\item Какова должна быть неделимая часть? +\item Каков должен быть уровень детализации? +\item Должен ли быть базовый словарь? +\item Насколько легко можно знания модифицировать? +\item Могут ли быть изменены отдельные элементы без влияния на другие? +\item Как представлять отдельные модули? +\item \textbf{Каков должен быть механизм извлечения знаний?} +\item Каковы должны быть отношения между старыми и новыми знаниями? +\item Какова должна быть форма обобщения и специализации знаний? +\item Какова должна быть процедура поиска необходимых знаний? +\item Как знания должны быть организованы: иерархически, на базе отношений, ассоциативно? +\item Какие отношения возможны между группами знаний? +\item Нужны ли оба механизма работы со знаниями: синтаксический и семантический? +\item Какой нужен механизм вывода? +\item Нужно ли поддерживать дедуктивный, индуктивный и абдуктивный выводы? +\item Нужно ли продолжать вывод, если информация стала неопределенной? +\item Нужно ли продолжать вывод, если информация отсутствует? +\item Должны ли все знания быть явно представленными или решатель может дополнять их? +\item Какие знания должны быть представлены обязательно явно? +\item Может ли структура представления знаний расширяться и модифицироваться? +\item Может ли решатель модифицироваться? +\end{itemize} + +\paragraph{Трудности обмена знаниями} +Представление знаний даже об одних и тех же вещах и на одном и том же языке может быть различным. Это приводит к трудностям обмена знаниями между людьми, организациями и программами, и, в частности, к трудностям формирования однозначно понимаемых требований и спецификаций для сложных систем. Несмотря на достаточно продвинутый уровень развития сложных систем, возможности повторного использования и распространения знаний ограничены. Это приводит к повторным усилиям по извлечению и необходимых знаний. + +\paragraph{Стандартизация знаний} +Ответ на многие из поставленных вопросов может быть получен путем стандартизации знаний? Стандартизация устранит или сведет к минимуму концептуальную и терминологическую путаницу и установит однозначное понимание языка, используемого для представления знаний + +Такой язык должен служить средством +\begin{itemize} +\item стандартизации представления знаний, +\item коммуникации между людьми, имеющими различный взгляд на одни и те же вещи, +\item взаимодействия между программными системами путем трансляции в него и из него, +\item обеспечения возможности повторного использования благодаря формальной спецификации, +\item автоматизации проверки корректности знаний, +\item адекватного представления других языков представления знаний. +\end{itemize} + +\paragraph{Онтология} +Онтологией называются представленные на некотором стандартном языке, обладающем перечисленными выше свойствами, знаний о некоторой области интересов (среде, мире). Онтологии хранятся в базах знаний. Онтологии непременно сопутствует некоторая концепция этой области интересов. + +Чаще всего эта концепция выражается посредством определения базовых объектов (индивидуумов, атрибутов, процессов) и отношений между ними. Определение этих объектов и отношений между ними обычно называется концептуализацией. Концептуализация может быть явной или ментальной, т.е. существующей только в чьей-то голове. Однако мы будем полагать, что онтология является явным представлением некоторой концептуализации. Онтология может иметь несколько уровней представления знаний. + +Уровни онтологий: +\begin{itemize} +\item \textbf{неформальная} на каком-либо естественном языке, +\item \textbf{полуформальная} на каком-либо структурированном подмножестве естественного языка, +\item \textbf{слабоформализованная} на каком-либо языке из области искусственного интеллекта с формальным синтаксисом, +\item \textbf{формализованная} на каком-либо языке из области искусственного интеллекта с формальным синтаксисом, семантикой, значимым и полным механизмом вывода. +\end{itemize} + +Следующее определение онтологии, суммирует различные определения онтологий: +\begin{frm}\textbf{Онтологией является} общепринятая и общедоступная концептуализация определенной области знаний (мира, среды), содержащая базис для моделирования этой области знаний, определяющая протоколы для взаимодействия между модулями системы искусственного интеллекта, использующими знания из этой области, и наконец, включающая соглашения о представлении теоретических основ данной области знаний. +\end{frm} +Этапы формирования онтологии +\begin{enumerate} +\item \textit{Определение цели и постановка задачи.} На этом этапе особенно важно понять зачем нужна онтология, как и кем она будет использоваться. +\item \textit{Построение.} Этот этап разбивается на три подэтапа: формализация понятий, кодирование и интеграция. + \begin{itemize} + \item Процесс формализации понятий: + \begin{enumerate} + \item выявление основных объектов и отношений предметной области, + \item текстовое описание этих объектов и отношений, + \item сопоставление этим объектам и отношениям термов. + \end{enumerate} + \item Процесс кодирования в каком-либо формальном языке результатов предыдущего подэтапа. Обычно кодирование включает 1) описание с использованием введенных термов необходимых утверждений, 2) выбор формального языка для кодирования, 3) кодирование в выбранном языке. + \item Процесс интеграции выполняется параллельно двум упомянутым и требует тщательного обдумывания, каким образом вновь создаваемая онтология будет интегрироваться с уже существующими. + \end{itemize} +\item \textit{Оценка.} На этом этапе осуществляется обдумывание и формирование вопросов, на которые онтология должна давать ответы, выбирается программная среда для реализации онтологии. +\item \textit{Документирование.} На этом этапе осуществляется тщательное составление руководства к онтологии на естественном языке. +\end{enumerate} + +\subsection{Языки представления знаний} +\begin{figure}[H] + \centering + \includegraphics[width=15cm]{01-langs.png} + \caption{Языки представления знаний} + \label{pic:know-langs} +\end{figure} + +\section{Формализация логических рассуждений в исчислении логики высказываний} +\textbf{Рассуждением} (а также выводом, поиском, умозаключением) называют ряд мыслей (суждений) изложенных в логически последовательной форме. Процедура математического доказательства - это наиболее чистая форма рассуждения. Все естественно-научные наблюдения и эксперименты, используемые для установления законов природы, используют рассуждения. Аргументация в процессе споров, обсуждений, согласований, судебных процедур основана на рассуждениях. + +\subsection{Задача для агента в системе} +Изучим, каким образом агент может находить интересующие его состояния среды (целевые состояния), зная что-либо о других состояниях среды. Нахождение целевых состояний осуществляется с помощью поиска или рассуждения в пространстве состояний путём восприятия состояний и воздействия на среду с помощью опеределённых действий (реакций). То есть, если уже существует чёткий алгоритм решения задачи, то это не задача для искусственного интеллекта. + +Существует среда: два объекта (двери) возле которых появляется цель (кусочек сыра), существует агент (кот), который может находиться в некоторых состояниях (лежать, есть) и совершать некоторые действия (перемещаться, есть). +\begin{figure}[h] + \centering + \includegraphics[height=6cm]{01-cats.png} + \caption{Среды и состояния кота} + \label{pic:cats} +\end{figure} + +На рис. \hrf{pic:cats} каждые три выделенные горизонтальные клетки - это состояние среды. То есть еда может появиться сразу у обеих дверей, может у ближенй, дальней или вовсе не появиться. Пользуясь языком логики мы можем понять в каком состоянии находится кот, и что нужно делать для достижения цели. Кот может совершать в один и тот же момент времени только одно из следующих действий: +\begin{itemize} +\item переходить к дверям левой комнаты, +\item переходить к дверям правой комнаты, +\item съедать кусочек сыра, около той комнаты, где он находится. +\end{itemize} +Эти действия обозначим соответственно: +\begin{itemize} +\item c\ts{1} = Идти налево, +\item c\ts{2} = Идти направо, +\item c\ts{3} = Съесть. +\end{itemize} + +То есть любой объём данных может быть закодирован. Основная задача извлечения знаний - получение результатов из таких представлений и моделирований, построение моделей на каком-то языке. + +\begin{figure}[H] + \centering + \includegraphics[width=10cm]{01-cats-graph.png} + \caption{Граф переходов состояний среды} + \label{pic:cats-graph} +\end{figure} +Цель кота - не оставить ни одного кусочка сыра, где бы он изначально ни находился. В терминах состояний среды целью кота является перевод ее с помощью своих действий (реакций) в одно из состояний b\ts{7} и b\ts{8}. Состояния, в которые с помощью набора допустимых действий необходимо перевести среду, называются целевыми. Будем полагать для нашего примера, что каждое восприятие совпадает с одним из состояний. Решением задачи поиска целевых состояний является нахождение последовательности пар (плана) «восприятие/действие», ведущей из начального состояния в целевые. Процесс нахождения этих последовательностей называется поиском, выводом или рассуждением. +\begin{frm} +\textbf{Постановкой задачи} называется задание всех состояний (не обязательно явно) и действий, которые могут использоваться для решения задачи, начального состояния и целевых состояний, а также всех допустимых переходов между состояниями при выполнении соответствующих действий. Для среды кота постановка задачи уже осуществлена. Все состояния, которые могут использоваться при решении задачи, перечислены +\end{frm} +Целевыми состояниями являются b\ts{7} и b\ts{8}. Все допустимые переходы между состояниями показаны на графе переходов. По графу можно проверить, что решениями задачи являются последовательности (пути) $b_1c_2\to b_2c_3\to b_4c_1\to b_3c_3$, и $b_1c_3\to b_5c_2\to b_6c_3$, ведущие соответственно в целевые состояния b\ts{7} и b\ts{8}. + +Для решения задач нахождения путей, ведущих из начального состояния в целевые в пространстве состояний применяются различные стратегии поиска. Эти стратегии состоят в построении деревьев поиска тем или иным способом. В реальных задачах эти деревья могут быть очень большими, вследствие чего целесообразно разрабатывать такие стратегии поиска, которые с точки зрения оценок сложности являются эффективными. + +Однако, какая бы из этих стратегий не использовалась, элементарным шагом поиска является переход из одного состояния среды в другое и анализ состояния, в которое переход был осуществлен, на принадлежность к числу целевых. + +Одной из очевидных, но чрезвычайно неэкономных стратегий поиска, позволяющей найти все решения является стратегия поиска в ширину\footnote{простыми словами: в процедурном программировании для этого используется обычная очередь FIFO и цикл, с условием итерации «пока очередь не пуста». В теле цикла из очереди забирается узел и в очередь кладутся все непосещённые смежные узлы взятого узла (прим. Овчинников)}, состоящая в следующем: +\begin{enumerate} +\item Образовать множество B = {b\ts{1}}, состоящее из одного начального состояния b\ts{1}; +\item Для каждого состояния множества B и каждого действия c\ts{j} найти все состояния b\ts{k}, в которые переходит среда. Совокупность всех таких состояний, за исключением тех, которые уже встречались в ранее образованных множествах B, принять за новое множество B; +\item Проверить, нет ли среди элементов этого множества целевых состояний. Если целевых состояний нет, то перейти к п. 2. Если целевые состояния есть, то выписать в порядке использования правил все пути, которые привели к целевым состояниям, удалить эти состояния из множества B и перейти к выполнению следующего пункта. +\item Проверить, все ли целевые состояния найдены. Если найдены все, то прекратить поиск. Если найдены не все, то перейти к п. 2. +\end{enumerate} + +\subsection{Формализация} +Рассуждения агента (поиск решений задачи) сводится к вычислению правил перехода в соответствии с выбранной стратегией поиска решения. Каждый шаг вычисления состоит в проверке истинности левой части правила (факта нахождения среды в состоянии b\ts{i} и допустимости действия c\ts{j}) и, в случае её истинности, признанию факта перехода из состояния b\ts{i} в состояние b\ts{k} в результате действия c\ts{j}. + +Нам хотелось бы иметь математический аппарат, используя который можно было бы осуществлять постановку и поиск решения задачи формально, используя наилучшую стратегию поиска. Осуществить постановку задачи формально - это значит, имея некий формальный язык, выразить на нем все знания о среде, необходимые для решения задачи. + +Решить задачу формально - это значит иметь множество правил и стратегию их использования, позволяющих осуществить вывод одних синтаксически правильных истинных предложений из других синтаксически правильных истинных или предполагаемых истинными. Рассуждения в пространстве состояний могут быть формализованы в языке логики высказываний, на языке логики высказываний можно формально поставить задачу. Логика высказываний может использоваться для формального решения задач. Логика высказываний является одним из простейших языков формализации рассуждений. Синтаксис логики высказываний прост и имеет прямые синтаксические и семантические аналоги в естественных языках, что чрезвычайно облегчает понимание логики высказываний. + +Символами языка логики высказываний, составляющими ее алфавит, являются логические константы ИСТИНА и ЛОЖЬ, сокращенно обозначаемые буквами И и Л, логические переменные x, y, z,..., обозначаемые строчными буквами латинского алфавита, логические связки $\wedge$ (И), $\vee$ (ИЛИ), $\neg$ (НЕ), $\equiv$ (ЭКВИВАЛЕНТНО), $\supset$ (ВЛЕЧЕТ) и круглые скобки. + +Значениями логических переменных являются логические константы. Предложения языка логики высказываний, называемые также формулами или высказываниями составляются по следующим правилам: +\begin{itemize} +\item Логические константы являются простыми предложениями; +\item Логические переменные также являются простыми предложениями; +\item Сложные предложения формируются из простых с помощью связок $\wedge$ (И), $\vee$ (ИЛИ), $\neg$ (НЕ), $\equiv$ (ЭКВИВАЛЕНТНО), $\supset$ (ВЛЕЧЕТ); +\item Простые и сложные предложения, заключенные или незаключенные в скобки являются предложениями языка логики высказываний. +\item Из предложений с помощью связок и скобок могут образовываться новые предложения языка логики высказываний. +\end{itemize} + +Связки имеют следующий порядок старшинства $\neg$, $\wedge$, $\vee$, $\supset$, $\equiv$, т.е. связка $\neg$ самая старшая, а связка $\equiv$ - самая младшая. Формулы логики высказываний, составленные по этим правилам называются правильно построенными формулами или сокращенно \textbf{ппф-формулами}. + +\subsection{Формулы логики высказываний} +Формула задает отношение между объектами (свойствами объектов), представленными переменными. Истинностное значение формулы: ИСТИНА или ЛОЖЬ, позволяет судить о наличии или отсутствии у объектов среды тех или иных совокупных свойств или отношений. Истинное значение формулы определяет наличие отношения, а ложное - его отсутствие. Подстановка в формулу констант вместо каких-либо переменных называется ее конкретизацией. Истинностные значения любой формулы, то есть её семантика, всегда могут быть заданы таблицей, состоящей из двух частей: в левой части таблицы перечисляются все наборы значений аргументов, а в правой соответствующие наборам значения формулы. Такие таблицы истинности в логике высказываний называются таблицами истинности (таблица \hrf{table:truthTable}). + +\begin{table}[H] + \centering + \begin{tabular}{|c|c|c|c|c|c|c|} + \hline + x & y & $\neg x$ & $x\wedge y$ & $x\vee y$ & $x\supset y$ & $x\equiv y$ \\ [0.5ex] + \hline\hline + Л & Л & И & Л & Л & И & И \\ + Л & И & И & Л & И & И & Л \\ + И & Л & Л & Л & И & Л & Л \\ + И & И & Л & И & И & И & И \\ + \hline + \end{tabular} + \caption{Таблица истинности для связок} + \label{table:truthTable} +\end{table} + +Формулы, истинные на всех наборах значений своих аргументов, называются общезначимыми формулами. Если какая-либо формула $\alpha$ является общезначимой, то этот факт обычно записывается с использованием знака общезначимости $\models$, который ставится перед формулой: $\models\alpha$. + +Проверка формулы на общезначимость может быть осуществлена с помощью таблицы истинности. Если формула истинна во всех строках таблицы истинности, которая содержит все возможные наборы аргументов формулы, то эта формула общезначима (таблица \hrf{table:alpha-formulae}). В логике высказываний известно много общезначимых формул, называемых обычно законами логики высказываний. +\begin{table}[h!] + \centering + \begin{tabular}{|c|c|c|c|c|c|c|} + \hline + x & y & $\neg x$ & $(\neg y\wedge y)$ & $\neg x\vee (\neg y\wedge y)$ & $\neg x\vee (\neg y\wedge y)\supset \neg x$ \\ [0.5ex] + \hline\hline + Л & Л & И & И & И & И \\ + Л & И & И & И & И & И \\ + И & Л & Л & Л & Л & И \\ + И & И & Л & Л & Л & И \\ + \hline + \end{tabular} + \caption{Общезначимые формулы} + \label{table:alpha-formulae} +\end{table} + +\subsection{Законы логики высказываний, выполнимость} +\begin{itemize} +\item Коммутативные законы: +\[w1 \vee w2 \equiv w2 \vee w1\] +\[w1 \wedge w2 \equiv w2 \wedge w1\] +\item Дистрибутивные законы: +\[(w1 \vee w2) \wedge w3 \equiv (w1 \wedge w3) \vee (w2 \wedge w3)\] +\[(w1 \wedge w2) \vee w3 \equiv (w1 \vee w3) \wedge (w2 \vee w3)\] +\item Ассоциативные законы: +\[(w1 \wedge w2) \wedge w3 \equiv w1 \wedge (w2 \wedge w3)\] +\[(w1 \vee w2) \vee w3 \equiv w1 \vee (w2 \vee w3)\] +\item Законы Де Моргана: +\[\neg (w1 \wedge w2) \equiv \neg w2 \vee \neg w1\] +\[\neg (w1 \vee w2) \equiv \neg w2 \wedge \neg w1\] +\item Закон двойного отрицания: +\[\neg \neg w1 \equiv w1\] +\end{itemize} +Законы логики высказываний – общезначимые формулы + +Формула называется выполнимой, если существуют наборы значений ее аргументов, на которых она принимает истинное значение и наборы значений, на которых она принимает ложное значение. Если формула на всех наборах значений ее аргументов принимает ложное значение, то она называется невыполнимой. Заключение об истинности следствия $\alpha2$ по истинному условию $\alpha1$ и общезначимой импликативной формуле $\alpha1\supset\alpha2$ достаточно универсальный способ для вывода заключений, но требует проверки общезначимости последней. + +Если формула $\alpha1\supset\alpha2$ не является общезначимой, то подобного заключения делать нельзя. + +\subsection{Импликативные формулы} +Общезначимость формул вида $\alpha1\supset\alpha2$, называемых импликативными формулами, является важным свойством для получения заключения об истинности $\alpha2$, называемого заключением, при истинности $\alpha1$, называемого посылкой. Упрощенно импликативные формулы $\alpha1\supset\alpha2$ называются также, как связка $\supset$, т.е. импликацей. Проверка общезначимости может быть сделана с помощью построения таблицы истинности, однако построение таблицы истинности слишком трудоемко для того, чтобы можно было решать реальные задачи: $О(2^n)$, вместо этого используются специальные правила вывода, применение которых базируется не на понятии общезначимости формулы, в частности общезначимости импликативной формулы, а на понятии модели формулы. + +Семантика логики высказываний может быть пояснена смысловой интерпретацией ее предложений или формул. Под интерпретацией обычно понимается установление соответствия между логическими переменными и изменяющимися свойствами объектов (или просто объектами) среды и между значениями переменных (константами) и конкретными значениями свойств объектов. Пример со средой кота: +\begin{itemize} +\item соответствие между логической переменной x\ts{к} и свойствами кота находиться слева или справа, +\item соответствие между значениями логической переменной x\ts{к} = И и x\ts{к} = Л и одним из местонахождений кота слева или справа. +\end{itemize} + +\subsection{Модель высказываний. Выводимость} +Среда, любая интерпретация в которой делает данную формулу истинной, называется моделью этой формулы. Понятие модели является важным в логике высказываний и в других логиках, поскольку позволяет удачно ввести понятие выводимости одних, истинных при соответствующей интерпретации формул, из других истинных. + +Говорят, что формула $\alpha$ выводима из формул $\alpha1$, $\alpha2$,...,$\alpha k$, если любая (но одна и та же) модель всех этих формул $\alpha1$, $\alpha2$,...,$\alpha k$ является также моделью формулы $\alpha$. Иными словами, если формулы $\alpha1$, $\alpha2$,...,$\alpha k$ истинны на некотором множестве интерпретаций в данной среде, то формула $\alpha$ выводима из них, если она также истинна на всех интерпретациях этого множества. +Факт выводимости записывают с помощью символа выводимости $\vdash$: +\[\alpha1, ... ,\alpha k \vdash \alpha\] + +\subsection{Формальная теория, исчисление высказываний} +Формальной теорией (см. \hrf{subsec:formal-theory}), называемой также формальной моделью, формальной системой, исчислением называется тройка $\Re = \{L, S, P\}$, где +\begin{itemize} +\item [] $L$ – язык формальной модели с присущими ему синтаксисом, +\item [] $S$ – совокупность начальных знаний, сформулированных на языке $L$; +\item [] $P$ - правила вывода позволяющие формирование по определенной стратегии в языке $L$ новых знаний, начиная с начальных. +\end{itemize} + +Правила вывода не обязательно являются правилами логического вывода, поскольку формальные модели могут быть не только логическими. + +Языком исчисления высказываний является язык логики высказываний. Начальные знания (аксиомы) – это формулы языка логики высказываний. Правила вывода исчисления высказываний – это \setword{модус поненс}{text:modus-ponens-definition}\footnote{Modus ponens (лат. «правило вывода»), обычно называемое правилом отделения или гипотетическим силлогизмом, позволяет от утверждения условного высказывания $A \to B$ и утверждения его основания $A$ (антецедента) перейти к утверждению следствия $B$ (консеквента). Например, металлы — проводники тока, цинк — металл, значит цинк проводит ток. Обратное утверждение не всегда верно: никель и морская вода проводят ток, но никель — металл, а морская вода не металл. Итого, если из $A$ следует $B$, и $B$ — истинно, то $A$ может быть как истинно, так и ложно.}, правило подстановки, правило резолюции и другие, которые будут рассмотрены ниже. + +\textbf{Классическое исчисление высказываний} +\begin{itemize} +\item [] Язык: язык логики высказываний. +\item [] Аксиомы: общезначимые формулы. +\item [] Правила: модус поненс и правило подстановки. +\end{itemize} +В результате получим исчисление, называемое обычно классическим счислением высказываний. Аксиомы классического исчисления высказываний истинны при любой интерпретации. Классическое исчисление высказываний может служить основой для вывода в любой среде. + +\textbf{Натуральное исчисление высказываний} +\begin{itemize} +\item В натуральных исчислениях высказываний в качестве аксиом используются не законы логики высказываний, а формулы на языке логики высказываний, для которых среда является моделью. +\item Правила должны быть состоятельными для данной среды. +\item В качестве правил в натуральных исчислениях могут использоваться правила классического исчисления высказываний. +\item В качестве аксиом в натуральных исчислениях могут использоваться аксиомы классического исчисления высказываний. +\item Поскольку количество различных сред бесконечно, то и натуральных исчислений высказываний может быть сколько угодно. +\end{itemize} + +\subsection{Правила вывода} +Правила вывода записываются в виде $\frac{\alpha}{\beta}$. Символы $\alpha$ и $\beta$ в правиле вывода обозначают одну или несколько формул. +$\alpha$ называется условием, а $\beta$ - следствием. Если в условии или следствии формул несколько, то они записываются через запятую. Используются только такие правила, которые называются \textbf{состоятельными}, т.е. по которым на основании истинности всех формул, входящих в условие правила вывода, можно сделать заключение об истинности всех формул, входящих в следствие правила вывода. + +Примеры правил: +\begin{itemize} + \item \setword{\textbf{Модус поненс}}{text:modus-ponens}. Из истинности условия импликации и истинности самой импликации следует истинность следствия импликации: + \[ \frac{\alpha,\alpha\supset\beta}{\beta} \] + \item \textbf{Правило подстановки}. Из формулы $\alpha(p)$ выводима формула $\alpha(P)$, получающаяся подстановкой в формулу $\alpha(p)$ вместо каждого вхождения переменной $p$ формулы $P$: + \[\frac{\alpha(p)}{\alpha(P)}\] +\end{itemize} + +Примеры правил натуральных исчислений высказываний: +\begin{itemize} + \item \setword{\textbf{Исключение конъюнкта}}{text:conjunction-exclude}. Из истинности конъюнкции следует истинность любого ее конъюнкта: + \[\frac{\alpha_1\wedge\alpha_2\wedge...\wedge\alpha_n}{\alpha_i}\] + \item \setword{\textbf{Введение конъюнкции}}{text:conjunction-inject}. Из списка истинных формул следует истинность их конъюнкции: + \[\frac{\alpha_1,\alpha_2,...,\alpha_n}{\alpha_1\wedge\alpha_2\wedge...\wedge\alpha_n}\] + \item \setword{\textbf{Введение дизъюнкции}}{text:disjunction-inject}. Из истинности формулы следует истинность ее дизъюнкции с любыми другими формулами: + \[\frac{\alpha_i}{\alpha_1\vee\alpha_2\vee...\vee\alpha_n}\] + \item \setword{\textbf{Исключение двойного отрицания}}{text:double-not-exclude}. Из истинности двойного отрицания формулы следует истинность ее самой: + \[\frac{\neg(\neg\alpha)}{\alpha}\] + \item \setword{\textbf{Простая резолюция (удаление дизъюнкта)}}{text:simple-resolution}. Из истинности дизъюнкции и отрицания одного из ее дизъюнктов следует истинность формулы, получающейся из дизъюнкции удалением этого дизъюнкта. + \[\frac{\alpha\vee\beta,\neg\beta}{\alpha}\] + \item \setword{\textbf{Резолюция}}{text:resolution}. Из истинности двух дизъюнкций, одна из которых содержит дизъюнкт, а другая - его отрицание, следует формула, являющаяся дизъюнкцией исходных формул без упомянутого дизъюнкта и его отрицания. + \[\frac{\alpha\vee\beta,\neg\beta\vee\gamma}{\alpha\vee\gamma}\] +\end{itemize} + +\section{Формализация логических рассуждений в исчислении логики предикатов первого порядка} +\subsection{Преимущества и недостатки} +Недостатки +\begin{itemize} +\item Выразительные возможности логики высказываний невысоки; +\item Требуется слишком много переменных логики высказываний для описания даже простых сред; +\item В случае простых сред приходится вводить для каждого объекта и каждого его свойства логическую переменную; +\item Число таких переменных равно произведению числа объектов на число их свойств. +\end{itemize} +Преимущества: выразительность логики предикатов является следствием ее основополагающей идеи: +\begin{itemize} +\item каждому уникальному (не совпадающему ни с каким другим) объекту сопоставляется индивидуальная объектная константа; +\item она обозначается именем (названием) объекта; +\item классу однотипных по каким-либо свойствам объектов сопоставляется - объектная переменная, значением которой являются объектные константы; +\item объектные константы и переменные в литературе часто называются индивидными или предметными. +\end{itemize} + +\subsection{Предикат} +\textbf{Предикатом} называется высказывательная функция, определенная на множестве термов: + +\code{предикатный_символ(терм,терм,...,терм)} + +Эта функция может принимать только два значения Истина (\code{И}) и Ложь (\code{Л}), называемые истинностными значениями. + +\textbf{Термами} называются константы, переменные и функции. + +Пример: среда имеет такие объекты как птицы и другие объекты, и нам известно, что «птицы имеют крылья». Спрашивается, как выразить это знание? Введем константы, обозначающие конкретный вид птиц, например, \textit{Воробей}, \textit{Синица}, \textit{Соловей}, и предикатный символ \textit{имеет\_крылья}. Ведем переменную \code{x}, обозначающую все объекты, нашей среды. Тогда предикат \code{имеет_крылья(x)} задает свойство объекта \code{x} иметь или не иметь крылья. + +Если \code{x = Воробей}, то \code{имеет_крылья(Воробей) = И}. +Если \code{x} на является птицей, например \code{x = Лошадь}, то \code{имеет_крылья(Лошадь) = Л}. + +\textbf{Объектная константа} называемая в дальнейшем, если это не вызывает путаницы, просто константой, взаимно однозначно сопоставляется в процессе интерпретации какому-либо одному объекту среды. Константа обозначается строкой символов, начинающейся с прописной буквы, и, чаще всего, эта строка символов совпадает с именем или наименованием объекта и записывается курсивом, например, \textit{Владимир}, \textit{Чудовище}, \textit{Кот} и т.д. + +\textbf{Более сложные отношения} объектов среды представляются на языке логики предикатов, как и на языке логики высказываний, в виде определенных предложений (высказываний, формул логики предикатов), использующих предикаты, кванторы, связки и скобки. + +\textbf{Объектные переменные} или просто переменные обозначаются строкой символов, начинающейся со строчной буквы и записываемой курсивом. Областью значений каждой переменной является множество объектных констант, в общем случае даже бесконечное. + +\textbf{Функции в логике предикатов} + +\code{функциональный_символ (терм,терм,...,терм)} + +Функция в логике предикатов не предполагает обязательного наличия какого-либо алгоритма вычисления значения функции по ее аргументам. Она лишь задает определенное отношение между термами и возвращает объектную константу. + +\subsection{Синтаксис логики предикатов} +\begin{itemize} +\item [] <Формула> $\to$ <Атом> (по сути, предикат) +\item [|] <Формула> +\item [|] <Формула> <Связка> <Формула> +\item [|] <Квантор> (<Переменная>, ...,<Переменная>) <Формула> +\item [] $\neg$ <Формула> +\item [|] (Формула) <Атом> $\to$ <Предикатный символ> (<Терм>, ...,<Терм>) +\item [|] <Терм> = <Терм> +\item [] <Терм> $\to$ <Функциональный символ> (<Терм>, ...,<Терм>) | <Константа> | <Переменная> +\item [] <Связка> $\to \supset | \wedge | \vee | \equiv | \neg$ +\item [] <Квантор> $\to \forall | \exists$ +\item [] <Константа> $\to$ <Строка символов, начинающаяся с прописной буквы> +\item [] <Переменная> $\to$ <Строка символов, начинающаяся со строчной буквы> +\item [] <Предикатный символ> $\to$ <Строка символов, начинающаяся со строчной буквы> +\item [] <Функциональный символ> $\to$ <Строка символов, начинающаяся со строчной буквы> +\end{itemize} + +\textbf{Кванторы} +Когда имеем дело с объектами, то возникает естественная потребность выразить какие-либо общие свойства целого множества объектов. Кванторы как раз служат этим целям. Таких кванторов в логике предикатов всего два. +\begin{itemize} +\item Квантор общности $\forall$ +\item Квантор существования $\exists$ +\end{itemize} + +\textbf{Взаимосвязь между кванторами} +Квантор связывает переменные, которые записываются за знаком квантора в скобках. Они называются связанными. Переменные, которые ни один квантор не связывает, называются свободными. + +Обозначая $P(x)$ любую формулу, переменная x которой связана кванторами, получим следующие законы, характеризующие взаимосвязь между кванторами: + +\begin{itemize} +\item $\forall (x) \neg P(x) \equiv \neg \exists(x) P(x)$, +\item $\neg \forall (x) P(x) \equiv \exists (x) \neg P(x)$, +\item $\forall (x) P(x) \equiv \neg \exists(x) \neg P(x)$, +\item $\neg \forall(x) \neg P(x) \equiv \exists (x) P(x)$. +\end{itemize} + +\subsection{Аксиомы, теоремы, факты и цели} +Определения таких понятий, как интерпретация, общезначимость, модель, выводимость формул, введенных для логики высказываний, остаются справедливыми и для логики предикатов. +В математической литературе, посвященной логике предикатов первого порядка, аксиомами обычно называют формулы, истинные при всех интерпретациях в некоторой среде. +Как и в случае логики высказываний, это можно сказать и другими словами: аксиомами называются такие формулы логики предикатов, для которых среда является моделью при всех их интерпретациях. +Аксиомы, являющиеся литералами, все аргументы которых являются константами, часто называются фактами. +Аксиомы, не являющиеся фактами часто называют правилами. +Факты и правила являются формулами логики предикатов. Основной задачей агента является вывод на основании фактов и правил истинных формул, называемых обычно теоремами, целями или целевыми формулами. + +\textbf{Переход от естественного языка к языку логики предикатов} +\begin{itemize} +\item [] \code{Если существо имеет крылья, то это существо - птица.} +\item [] \code{Если существо летает и несет яйца, то это существо - птица.} +\item [] \code{имеет_крылья(существо)} $\supset$ \code{птица (существо)} +\item [] \code{летает(существо)} $\wedge$ \code{несет_яйца(существо)} $\supset$ \code{птица(существо).} +\end{itemize} + +\textbf{Одноместные и многоместные предикаты} +\begin{itemize} +\item Одноместные предикаты имеют по одному аргументу. +\item Предикаты могут быть также многоместными (имеют более одного аргумента). +\item В случае одноместного предиката предикатный символ соответствует какому-либо свойству объекта. +\item В случае многоместных предикатов предикатный символ рассматривается как некоторое общее свойство объектов, соответствующих аргументам, либо, чаще всего, как отношение, в котором эти объекты находятся. +\item Формулы задают отношения с использованием связок. +\end{itemize} + +\subsection{Правила вывода} +\textbf{\hrf{text:modus-ponens}}. Сноска с определением \hrf{text:modus-ponens-definition}. + +\textbf{Правила введения кванторов} +\[\frac{\alpha(x)\supset\beta(x)}{\alpha(x)\supset\forall(x)\beta(x)}\] +\[\frac{\alpha(x)\supset\beta(x)}{\exists(x)\alpha(x)\supset\beta(x)}\] + +\textbf{Правила исключения кванторов} +\[\frac{\forall(x)\alpha(x)}{\alpha(x)}\] +\[\frac{\alpha(y)}{\exists(x)\alpha(x)}\] + +\textbf{\hrf{text:conjunction-exclude}} + +\textbf{\hrf{text:conjunction-inject}} + +\textbf{\hrf{text:disjunction-inject}} + +\textbf{\hrf{text:double-not-exclude}} + +\textbf{\hrf{text:simple-resolution}} + +\textbf{\hrf{text:resolution}} + +\subsection{Вопросы к лекции 1} +Представьте на языке логики предикатов следующие предложения русского языка: +\begin{enumerate} +\item Не все студенты любят математику и физику. +\item Только один студент любит историю. +\item Только один студент любит историю, и не любит электронику. +\item Любой охотник, не употребляющий дичь в пищу, вызывает удивление. +\item Известны женщины, которые любят мужчин, не являющихся охотниками. +\item Живет в городе охотник, который знаком со всеми мужчинами-охотниками этого города. +\item Никто не любит охотника, который убивает дичь ради развлечения. +\end{enumerate} + +\subsection{Вопросы к лекции 2} +Представьте следующие условные предложения русского языка в виде правил логики предикатов: +\begin{enumerate} +\item Если вы любите детективы, то сегодня вечером можете посмотреть прекрасный фильтр из этой серии. +\item По утрам подают кофе и бутерброды с ветчиной. +\item Может быть я заскочу к вам вечером, если успею. +\item Я её одновременно люблю и ненавижу. +\end{enumerate} + +\section{Неопределённость и нечёткие множества} +«По мере увеличения сложности системы наша способность делать точные и все еще значимые суждения о ее поведении все время ослабевает, и после некоторого порога точность и значимость становятся вообще взаимоисключающими.» Лотфи Заде. +\subsection{Сложность и точность} +Какую среду или окружающий мир человек называет сложными? + +Интуитивно сложность среды ощущается человеком как неспособность понять точно ее структуру, выделить отдельные ее составляющие и их взаимосвязи, описать происходящие в среде явления и события. Всё это приводит к неопределенности, двусмысленности, неоднозначности, запутанности знаний о подобной среде. \textit{Большинство проблем}, с которыми сталкивается человечество в современном мире, с указанной точки зрения являются сложными. + +Как, тем не менее, человечеству удается решать сложные задачи, в условиях, когда оно не способно и даже не может надеяться понять и однозначно описать во всех деталях процедуры решения подобных задач? Такие задачи человек решает \textbf{приближенно} и, что очень существенно, этого оказывается достаточно для многих приложений. + +По мере того, как человек узнает о среде все больше и больше, сложность такой среды с его точки зрения уменьшается, а понимание того, как она устроена увеличивается. Поскольку сложность уменьшается, появляется возможность использовать более точные вычислительные методы для моделирования среды. + +\begin{figure}[H] + \begin{tikzpicture}[domain=0.1:8] + \draw[->] (-0.2,0) -- (8.2,0) node[anchor = north, pos = 0.5,] {Сложность среды}; + \draw[->] (0,-0.2) -- (0,4.2) node[anchor = south, rotate = 90, pos = 0.5] {Точность модели}; + \draw[thick, domain=0.3:1.7, color=blue] plot (\x,{(1/\x)+0.3}) node[anchor = south, text width = 3cm, above = 80] {Чёткие\\ математические\\ модели}; + \draw[thick, domain=1.3:5, color=black] plot (\x,{(5/\x)-0.5}) node[anchor = south, text width = 3cm, above = 80] {Чёткие\\ имитационные\\ модели}; + \draw[thick, domain=3:8, color=red] plot (\x,{(10/\x)-0.8}) node[anchor = south, text width = 3cm, above = 10] {Нечёткие\\ модели}; + \end{tikzpicture} + \caption{Отношение точности модели к сложности среды} + \label{plot:accuracy-complexity} +\end{figure} + +Рис. \hrf{plot:accuracy-complexity} иллюстрирует эту взаимосвязь сложности среды и точности вычислительных моделей. + +Для сред с небольшой сложностью и, следовательно, маленькой неопределенностью могут быть использованы четкие математические модели на основе использования систем математических уравнений различного типа, обеспечивающие точное описание свойств среды. Для систем, которые несколько более сложны и для которых существует достаточное количество численных экспериментальных данных, могут быть использованы четкие имитационные модели. Например, это могут быть, нейросети, которые являются довольно мощным средством моделирования сред, позволяющим уменьшить неопределенность знаний об изучаемой среде. Для сложных сред, для которых мал\'{о} числовых данных, а доступна только не очень достоверная информация, нечеткие модели открывают путь для представления сред, позволяя приближённо моделировать поведение среды (интерполировать отношения между воздействиями на среду и ее ответными реакциями). + +Все модели, используемые для представления сред, являются математическими абстракциями. При выборе моделей важно использовать наиболее подходящую. Для сред, допускающих точное описание, нечеткие модели менее эффективны, чем четкие, обеспечивающие однозначный алгоритм моделирования и позволяющие лучше понять поведение среды. Нечеткие модели хороши для изучения сред, информация о поведении которых содержит неопределенности и неоднозначности. В 1965 году появилась основополагающая статья Л.Заде, посвященная нечетким множествам и вызвавшая во всем мире большое количество теоретических и прикладных работ на эту тему. Начиная с 1970 года, нечеткие подходы стали внедряться в промышленность. Особенно в этом преуспела Япония. Теоретической основой для этого послужила развитая за это время нечеткая логика. + +\textbf{Нечеткая логика}, как теоретическая основа, стала использоваться во многих приложениях, например: +\begin{itemize} +\item В видеографии (Fisher, Sanyo) для фокусировки и стабилизации видеоизображений. +\item Для управления температурой воздуха кондиционеров (Mitsubishi) в соответствии с предпочтениями потребителей. +\item Для управления режимами стиральных машин (Mitsubishi) в соответствии с нечёткими сигналами датчиков состояния стираемого белья. Датчики определяют цвет и вид белья, степень загрязнения. Нечёткий микропроцессор на основании показаний этих датчиков из 600 вариантов выбирает один наиболее подходящий, имеющий соответствующую температуру воды, количество моющих средств, время стирки и скорость вращения барабана. +\item В Японии в городе Сендай для управления движением поездами подземки использовался нечеткий компьютер. В результате количество ошибок при выборе режимов управления и торможения сократилось на 70\%. +\item Для управления автомобилем (Nissan) ввела нечёткую автоматическую коробку и нечёткую антиблокировочную систему в один из недавних автомобилей представительского класса. +\item В Японии имеются нечеткие диагностические системы для гольфа, вакуумной чистки, машин приготовления риса, тостеров и многих других систем управления изделиями промышленности. +\end{itemize} + +Почему подход, развитый в США для моделирования неопределенности в больших сложных системах, нашел огромное количество применений в сравнительно простых изделиях промышленности азиатских стран, таких как Япония? + +Одно из объяснений следующее: предпринимательский менталитет японцев таков, что они доводят любые исследовательские результаты до коммерческой реализации гораздо быстрее, чем другие нации. Кроме того, западная культура тяготеет к Аристотелевской логике черно-белого двоичного мира, который не склонен признавать его серые или нечеткие оттенки, которые столь естественны для Востока. + +Термин «нечеткий» (fuzzy) в англоязычном мире несет скрытый негативный смысл, которого нет в азиатской культуре. Например, выражение «нечеткая фокусировка для новых камер, стабилизирующая изображение» вызывает у рядового западного покупателя ощущение некой их ущербности, поскольку интуитивно интерпретируется как недостаток: фокусировка изображения будет нечеткой. + +\subsection{Случайность и нечёткость} +Теория нечетких множеств предлагает аппарат для представления неопределенности. Теория вероятностей, еще до появления нечетких множеств, также была развита для представления неопределенности с помощью вероятностных математических моделей. Из-за этого долгое время предполагалось, что единственным источником неопределенности является случайность. Для описания случайных неопределенностей в теории вероятностей важную роль играет случайный процесс, в котором любое событие является случайным. Предсказание этих событий невозможно. Что возможно в случайном процессе, так это точное описание распределения вероятностей событий, наблюдаемых долгое время. + +Однако не все неопределенности случайны. Некоторые виды неопределенностей не случайны и, следовательно, не могут моделироваться с помощью теории вероятностей. Фактически, и это достаточно легко показать, неопределенность событий подавляющего большинства сложных сред не является случайной. Теория нечетких множеств как раз является чрезвычайно адекватным аппаратом для моделирования сред с неслучайной неопределенностью. В то же время, у тех, кто не глубоко задумывался над этой проблемой, часто бытует мнение, что теория нечетких множеств – это замаскированная форма теории вероятностей. \textbf{Это не верно.} Базовый статистический анализ основан на теории вероятностей (случайных процессах). Один из классов случайных процессов, а именно стационарные случайные процессы, имеет следующие особенности: +\begin{enumerate} +\item они описывают простую среду, в которой процессы не могут изменяться от одного эксперимента к другому; +\item вероятность событий в среде является постоянной и не может изменяться от одного эксперимента к другому; +\item исходы событий должны повторяться от эксперимента к эксперименту. +\item исходы одних событий не влияют на исходы предыдущих или последующих. +\item события характеризуются частотой появления, которая может быть измерена. +\end{enumerate} + +Примером стационарных случайных процессов являются задачи извлечения разноцветных шаров из урны, бросание монет или костей, многие карточные игры. Много ли процессов принятия решений, с которыми человек сталкивается каждый день, могут быть отнесены к случайным процессам подобного типа? Как, например, выразить в виде случайного процесса неопределенность, связанную с прогнозом погоды? Как выразить теми же средствами неопределенность в выборе одежды на следующий день, выборе автомобиля при покупке, предпочтение в выборе цветов для любимой, риск заболеть раком в ближайшие годы и т.п.? + +В принципе моделирование всех этих видов неопределенности можно осуществить с помощью различных классов случайных процессов, однако такой подход вряд ли заслуживает доверия. Моделирование таких форм неопределенности с помощью нечеткой логики также следует осуществлять с осторожностью. Прежде необходимо тщательно изучить характер неопределенности, а только затем выбрать подходящий метод для моделирования. Многие параметры каждой задачи, которые изменяются во времени и пространстве, должны быть изучены, прежде, чем переходить к моделированию. + +В человеческом сообществе общепринятым способом передачи информации является естественный язык. \textbf{Естественный язык} является мощным средством коммуникации и обмена информацией между людьми и люди, несмотря на неопределенность и неточность языка, не испытывают больших трудностей в общении. Например, что означает на естественном языке выражение «высокий человек»? Высоким может считаться как человек, имеющий рост 1м 80см, так и человек, имеющий рост 1м 90см. Какое из этих значений вкладывает каждый говорящий в понятие «высокий человек» зависит от его точки зрения. Остается удивительным, что, несмотря на различное толкование понятия «высокий» двумя говорящими, понимание и речевое общение между ними \textit{возможны}, поскольку в процессе речевого общения они не требуют идентичного толкования значения термина «высокий». + +Базисом для формализации подобной неопределенности естественного языка служит теория нечетких множеств и основанная на них нечеткая логика. При этом следует понимать, что нечеткая логика будет полезной в двух случаях: +\begin{enumerate} +\item для моделирования сложных сред, изученность поведения которых весьма ограничена; +\item для моделирования сред, в которых человеческие рассуждения, восприятия и принятия решений являются важной составляющей. +\end{enumerate} + +Модели сред, являющиеся системами линейных уравнений, улучшить с помощью использования нечеткой логики невозможно. Нечеткая логика не является средством решения всех проблем. Однако ее роль и значение не следует приуменьшать. Многими примерами в дальнейшем будет показана польза и оправданность ее применения. Понимание многих физических сред и процессов, где нечеткая логика особенно удачно работает, в значительной степени базируется на неточных человеческих суждениях. + +\subsection{Неопределённость} +\begin{figure}[H] + \centering + \begin{tikzpicture} + \draw[ultra thick] (0,0) circle [radius=5]; + \draw[thick] (0,-5)--(0,5) (0,0)--(45:5) (0,0)--(75:5); + \draw[] node at (-3,0) {Неопределённая}; + \draw[] node at (3,-2) {Нечёткая}; + \draw[] node[rotate=60] at (1.6,2.8) {Случайная}; + \draw[] node[rotate=83] at (0.45,3.4) {Определённая}; + \end{tikzpicture} + \caption{Структура информации при решении сложных задач} + \label{plot:info-structure} +\end{figure} +Рис. \hrf{plot:info-structure} характеризует структуру информации, требуемой при решении сложных задач. Круг на этом рисунке очерчивает всю информацию о среде или мире, с которой мы имеем дело при решении каких-либо проблем. Как видно из рисунка, только небольшая часть этой информации является определенной или детерминированной. Но в подавляющем большинстве случаев при преподавании в университетах технических дисциплин исходят из предположения, что используемые для решения тех или иных задач модели носят детерминированный характер. + +Моделируемые процессы или объекты упрощаются до уровня, который позволяет сформулировать четкий алгоритм решения на основе использования уравнений или формул. Учась в университете, студенты постепенно забывают большинство из этих формул и опасаются, что это помешает им достойно войти в окружающий мир. И только после окончания университета, столкнувшись с решением реальных задач, многие из них осознают, что в определенной степени в университете они были введены в заблуждение. Ни в одной из задач, с которыми приходится сталкиваться, информация не является полностью известной, она полна неопределенностей, неточностей, случайностей, двусмысленностей. Источники неопределенности различны: сложность среды, недостаток знаний о среде, неточность измерений и т.п. например: +\begin{itemize} +\item «положить немного лука», +\item «бросить щепотку соли», +\item «добавить небольшое количество растительного масла», +\item «обжарить до золотистого цвета» и т.п. +\end{itemize} +Ни одна из этих рекомендаций не является точной или случайной. Тем не менее, человек способен на основе этих рекомендаций приготовить вполне сносное блюдо, хотя и может его, например, пересолить, если его представление о том, что такое «немного лука» и «щепотка соли» ошибочны. + +\subsection{Принадлежность множеству и нечёткие множества} +В своей основополагающей статье Л.Заде впервые высказал идею, что для математического представления неслучайной неопределенности, которая особенно характерна при описании мира на естественных языках, может быть использована характеристика принадлежности элемента множеству. Например, если в поваренной книге речь идёт о щепотке соли, то на самом деле речь идет о множестве $\text{Щ}=\{\text{щ}_1, \text{щ}_2, ..., \text{щ}_n\}$ таких щепоток: от самой большой у крупного повара большого ресторана до самой маленькой у миниатюрной хозяйки дома. Объединение всех этих щепоток, пусть, например, их будет 10, образует некоторое более или менее известное читателю поваренной книги множество $\text{Щ}=\{\text{щ}_1, \text{щ}_2, ..., \text{щ}_{10}\}$. Каждая щепотка щ\ts{i} является элементом множества. Если считать, что все щепотки равнозначны для приготовления наилучшего блюда, то может быть использована любая из них. Эта равнозначность может быть выражена одним и тем же характеристическим значением, например, числом 1, интерпретируемым как равнозначность всех щепоток щ\ts{i} множества Щ, допустимых для использования. + +Это число называется \textbf{степенью принадлежности} щепоток множеству Щ. Если все степени принадлежности одинаковы, то никакой неопределенности, какую из щепоток следует использовать, нет. Использовать можно любую. Но если щепотки неравнозначны, то, как выразить, какие из них являются наилучшими, исключающими пересол или недосол, какие наихудшими, использование которых не рекомендуется, а какие могут быть использованы, но лучше этого не делать? + +В этом случае тем щепоткам, которые не являются наилучшими, степени принадлежности можно выбрать меньшими 1. И считать, что чем сильней они отличаются от наилучшей, тем меньше должно быть значение степени принадлежности. В этом случае значение степени принадлежности позволяет \textbf{математически охарактеризовать неопределенность}, содержащуюся в рекомендациях поваренной книги. Для этого, конечно, нужно знать множество Щ и уметь задавать значение степени принадлежности для щепоток этого множества. Именно эту идею выражения неопределенности и развил Л.Заде в своих основополагающих работах, основываясь на рассмотренной степени принадлежности множеству. + +Рассмотрим наиболее важные из понятий, используемых для представления неслучайной неопределенности. +\begin{frm} + \textbf{Универсумом X} в математике обычно называют совокупность объектов, рассматриваемых в той или иной теории и имеющих одинаковые характеристики. Отдельный объект универсума обозначают x и называют также элементом. +\end{frm} + +Число объектов универсума называют \textbf{мощностью универсума} и обозначают чаще всего как \code{|X|}. Часть элементов универсума называют множеством или подмножеством универсума. В крайнем случае, подмножество универсума может совпадать со всем универсумом. Множества подразделяются на \textbf{четкие} (или классические) и \textbf{нечеткие}. В теории четких множеств любой элемент универсума либо принадлежит, либо не принадлежит какому-либо множеству или подмножеству универсума. Для обозначения факта принадлежности элемента x универсуму X или подмножеству A используют знак $\in$ и выражения «элемент x принадлежит универсуму X» или «элемент x принадлежит множеству A» записывают, соответственно как +\[x \in X,\] +\[x \in A.\] + +Если элемент x не принадлежит множеству A, то это записывают как $x \notin A$. Для четких множеств A, B и универсума X используют также следующие обозначения: +\begin{itemize} +\item $A \subset B$, если множество A является подмножеством множества B, но не совпадает с ним, +\item $A \subseteq B$, если множество A является подмножеством множества B или совпадает с ним, +\item $A \not\subset B$, если множество не A является подмножеством множества B и не совпадает с ним. +\item $A = B$, если множество A совпадает с множеством B, +\item $A \neq B$, если множество A не совпадает с множеством B. +\end{itemize} + +Над четкими множествами могут совершаться различные операции, основными из которых являются следующие: +\begin{itemize} +\item Объединение: $A \cup B = \{x| x \in A или x \in B\}$, +\item Пересечение: $A \cap B = \{x| x \in A и x \in B\}$, +\item Дополнение: $\neg A = \{x| x \notin A и x \in X\}$, +\item Вычитание: $A | B = \{x| x \in A и x \notin B\}$. +\end{itemize} +Четкие множества удобно характеризовать так называемой характеристической функцией, суть которой состоит в следующем: отложим по оси абсцисс в некотором порядке все элементы какого-либо универсума. Для простоты пусть это будут целые числа, начиная с 0. Выделим в этом универсуме какое-либо подмножество чисел, например А = \{3, 4, 5\}. Значение характеристической функции для этого множества будет иметь следующий вид: +\begin{equation} + \chi_A(x) = \begin{cases}\frac{1, x \in A}{0, x \notin A}\end{cases} + \label{eq:characteristical-function} +\end{equation} +Таким образом, для четкого множества характеристическая функция равна 1, если элемент принадлежит множеству, и равна 0 в противном случае. Значением характеристической функции фактически является степень принадлежности элементов универсума. + +Зная характеристические функции четких множеств A, B легко вычислить характеристические функции множеств, получаемых в результате применения к этим множествам перечисленных выше операций, т.е. +\begin{itemize} +\item если $C = A \cup B$, то $\chi_C(x) = max\{\chi_A(x), \chi_B(x)\}$, +\item если $C = A \cap B$, то $\chi_C(x) = min\{\chi_A(x), \chi_B(x)\}$, +\item если $C = \neg A$, то $\chi_C(x) = 1 - \chi_A(x)$. +\end{itemize} +Для случая, когда множество A содержится в множестве B, имеет место +\begin{itemize} +\item если $A \subseteq B$, то $\chi_A(x) \leq \chi_B(x)$. +\end{itemize} + +Выражение $A \supset B$ в теоретико-множественном смысле задает отношение между множествами A и B, которое может использоваться для суждений. Суждение делается на основе вычисления характеристического значения $\chi_{A \supset В}(x)$ множества $A \supset B$. Выражение $A \supset B$ рассматривается с одной стороны как множество, а с другой, как импликативная формула. Характеристическая функция множества $A \supset B$, как результат применения операции следования $\supset$ вычисляется по формуле (\hrf{eq:applying}). +\begin{equation} + \chi_{A \supset B}(x) = \begin{cases}\frac{1, \text{ если } x \in A, x \in B}{0, \text{ если } x \notin B}\end{cases} + \label{eq:applying} +\end{equation} + +Для нечеткого множества принадлежность или непринадлежность ему элементов не является столь определенной, как для четких. Эта принадлежность определяется характеристической функцией, называемой \textbf{функцией принадлежности}. Нечеткое множество A – это, по существу, всегда функция, обозначаемая $\mu_A(u)$. Она задает в явном виде отображение некоторого универсума U на отрезок [0,1]: $\mu_A(u): U \to [0, 1]$. + +Функций принадлежности для одного и того же универсума может быть сколько угодно. И каждая из них задает свое нечеткое множество А. Иногда, для того чтобы подчеркнуть, что это не простое множество, а нечеткое, оно подчеркивается «тильдой». Мы этого делать не будем. Функция принадлежности определяет степень принадлежности множества элементов универсума множеству A. Часто, нечеткое множество задается в виде конечного упорядоченного множества пар (\hrf{eq:defined-pairs}): +\begin{equation} + A=\{<\mu_A(u)/u>\} + \label{eq:defined-pairs} +\end{equation} +Любое четкое множество \textit{можно рассматривать} как частный случай нечеткого. + +\subsection{Отличия случайной и нечёткой неопределённостей} +Предположим, что в семье должен родиться ребенок, и в поликлинике на основании многолетних наблюдений сказали, что у всех отцов, живущих в данной местности схожий генотип, и поэтому с вероятностью 95\% рождаются мальчики. Это вероятностная оценка будущего события - рождения ребенка, основанная на случайности (из 1000 случаев или событий рождения детей у отцов, живущих в данной местности, в 950 случаях рождался мальчик, а в 50 – девочка). + +Если отец страстно ожидает мальчика, то риск иметь девочку в зависимости от слепого случая составляет 5\%. Информация, содержащаяся в такой вероятностной оценке, основанной на случайности, особенно если с этой оценкой связано какое-то важное последующее событие, например, наследование большого состояния, если это будет мальчик, содержит для отца слишком высокий риск. + +В другом случае отцу было сказано, что по результатам научных исследований у отцов, генотип которых принадлежит множеству из 100 схожих генотипов отцов, функция принадлежности отцов с генотипом $i \in \{1,2,..., 95\}$, характеризующая принадлежность рожденного к мальчикам равна 1, а к девочкам равна 0, а с генотипом $j\in\{96,..., 100\}$ функция принадлежности, характеризующая принадлежность рожденного к мальчикам равна 0 , а к девочкам равна 1. + +И еще отцу было сказано, что его генотип принадлежит множеству $\{1,2,..., 95\}$. Это нечеткая оценка будущего события рождения ребенка. Она гораздо более информативна для отца, поскольку основана не на случайных событиях, не на воле случая, а на накопленных неслучайных исследованиях и анализе его генотипа, свидетельствующих, что функция принадлежности будущего ребенка к категории мальчиков составляет 1. Это не исключает ошибки в анализе генотипа или ошибки в получении функции принадлежности. + +Другой пример, аналогичный изложенному. +На стол поставили два стакана с прозрачными жидкостями, взяв их из 100 стаканов с прозрачными жидкостями. В одном стакане с жидкостью находится чистая вода, в другом – яд. Имеется две оценки ситуации. +\begin{enumerate} +\item Одна основана на случайности: вероятность того, что в первом стакане содержится чистая вода, равна 95\%. +\item Другая основана на принадлежности множеству: функция принадлежности к стаканам с чистой водой первых 95 стаканов из множества всех 100 стаканов равна 1, а остальных – 0. +\end{enumerate} +Какая разница между этими двумя оценками неопределенности? + +Предположим, что можно наугад попробовать жидкость в первом стакане. +После этой пробы, вероятность того, что в стакане чистая вода, станет равной 100\% или 0\%. Во втором случае степень принадлежности какой была такой и останется. Точно также и с оценкой рождаемости. Если провести томографическое исследование роженицы, которое покажет, что будущий ребенок – это мальчик, то вероятность рождения мальчика станет 100\%, а если томография покажет, что это девочка, то вероятность рождения мальчика станет равно 0\%, а девочки 100\%. Степень же принадлежности будущего ребенка к категории мальчиков в зависимости от генотипа какой была такой и останется. + +Два приведенных примера ясно иллюстрируют разницу между нечеткой и случайной представлениями неопределенности. Нечеткость описывает \textbf{неоднозначность принадлежности} каждого элемента множеству. Случайность описывает \textbf{неоднозначность события} появления каждого элемента множества. Для того, чтобы можно было описывать и вычислять неопределенность неслучайных сред необходимо уметь задавать функции принадлежности. + +Рассмотрим, как это можно делать на примере некоторых геометрических фигур, которые иллюстрируют возможность связывать неопределенность с определенными математическими отношениями. + +\subsection{Нечёткие множества геометрических фигур} +Рассмотрим три геометрические фигуры: диск, цилиндр и стержень (рис. справа). +Различие между этими тремя фигурами зависит от отношения $d / h$ диаметра d к высоте h. +\begin{multicols}{2} +\begin{itemize} +\item При $d / h \ll 1$ форма фигуры стремится к стержню. +\item При $d / h \to 0$ достигает прямой линии. +\item При $d / h \gg 1$ фигура стремится к форме плоского эллипса. +\item При $d / h \to \infty$ становится круговым цилиндром. +\end{itemize} +\columnbreak +\begin{tikzpicture}[shape aspect=1] +\node (A) [cylinder, shape border rotate=90, draw, minimum height=1cm,minimum width=3cm] at (0,0) {A}; +\node (B) [cylinder, shape border rotate=90, draw, minimum height=3cm,minimum width=2cm] at (3,0) {B}; +\node (C) [cylinder, shape border rotate=90, draw, minimum height=4cm,minimum width=3mm] at (5,0) {C}; +\end{tikzpicture} +\end{multicols} +Геометрическая фигура на рис. \hrf{pic:undef-ellipse} является эллипсом с параметрами a и b. Из геометрии известно: +\begin{itemize} +\item при $a / b = 1$ эллипс превращается в окружность, +\item при $a / b \ll 1$ и $a / b \gg 1$ является эллипсом, +\item при $a / b \to\infty$ превращается в отрезок. +\end{itemize} +Используя эти знания, можем задать функцию принадлежности на универсуме +\[\{0,..., a / b\}.\] + +Этой функцией может быть, например кривая Гаусса (Гауссиан), уравнением которой является следующее + +\[\mu(a / b) = exp\{-3 [(a / b) -1] 2\}.\] + +В графическом виде Гауссиан показан на рис. \hrf{pic:undef-gaussian}. + +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.4\textwidth} + \centering + \begin{tikzpicture} + \draw[<->] (-2,0) -- (2,0) node[right] {a}; + \draw[<->] (0,-1) -- (0,1) node[above] {b}; + \draw[thick] (0,0) ellipse [x radius=2, y radius=1]; + \end{tikzpicture} + \caption{Эллипс} + \label{pic:undef-ellipse} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.4\textwidth} + \centering + \begin{tikzpicture} + \draw[->] (-0.2,0) -- (3.2,0) node[right] {$a/b$}; + \draw[->] (0,-1.2) -- (0,2.2) node[above] {$\mu(a/b)$}; + \draw[domain=1.2:2.8] plot (\x,{(sin(\x * 225)) + 1}); + \end{tikzpicture} + + \caption{Гауссиан} + \label{pic:undef-gaussian} + \end{subfigure} + \caption{Пример нечёткого множества в геометрии} + \label{pic:undefined-geometry} +\end{figure} + +Носителем Support(A) нечеткого множества A называется такое его подмножество, на всех элементах u которого функция принадлежности имеет значение, большее 0, т.е: +\[Support(A) = \{u \in U|\mu_A(u)>0\}\] + +Ядром нечеткого множества A называется его подмножество +\[A = \{u \in U|\mu_A(u) = 1\}\] + +Нечеткое множество A называется \textbf{нормальным}, если во множестве A существует хотя бы один элемент, функция принадлежности которого равна 1. В противном случае нечеткое множество является аномальным. Для нечетких множеств на упорядоченных универсумах вводится понятие \textbf{выпуклости}. Нечеткое множество A называется выпуклым, если его функция принадлежности выпукла, т.е. для любых трех упорядоченных точек справедливо: +\[u_1 \leq u_2 \leq u_3 \supset \mu_A(u_2) \geq min [\mu_A(u_1),\mu_A(u_3)]\] + +\subsection{Некоторые свойства нечётких множеств} +Для ряда задач, использующих совокупности нечетких множеств, заданных на одном универсуме, функции принадлежности должны обладать определенными свойствами. Необходимость удовлетворения этим свойствам вытекает не из каких-либо строгих доказательств, а из интуитивных соображений, связанных с интерпретацией человеком нечетких множеств как совокупностей объектов какого-либо универсума и рассмотрением функций принадлежности как оценки степени принадлежности этих объектов тому или иному подмножеству этого универсума. +\begin{itemize} +\item \textbf{Нечеткое множество должно быть нормальным и выпуклым.} Это объясняется тем, что для человеческого мышления естественно сопоставлять каждому нечеткому подмножеству объектов универсума, (например, значений температуры, давления, веса и т.п), некоторый интервал, упорядоченный таким образом, что в центре его находится значение (объект), принадлежность которого данному интервалу оценивается как наибольшая (функция принадлежности равна 1), а на краях – как наименьшая (функция принадлежности равна или близка к 0). Между этими объектами должны находится такие, принадлежность которых нечеткому множеству либо постепенно увеличивается (от краев к центру), либо уменьшается (от центра к краям) без скачков и провалов. +\item \textbf{Множества должны быть упорядочены} таким образом, чтобы для любых двух нечетких множеств $C_i$, $C_{i+1}$ имело место пересечение +\[ Support(C_i) \cap Support(C_{i+1}) \neq \varnothing \] +но такое, чтобы ядра этих множеств не пересекались +\[ \mathring{C_i} \cap \mathring{C}_{i+1} = \varnothing \] + +Это объясняется тем, что нечеткие множества предназначены для приближенного неоднозначного представления (описания) сред. Пересекаемость является как раз средством задания этой неоднозначности. +\item Универсум должен иметь верхнюю и нижнюю границы +\[\exists x_1, x_1 = inf U; \exists x_2, x_2 = \sup U\] +и эти величины должны принадлежать ядрам крайних нечетких множеств $C_1$, $C_n$ +\[\mu_{C_1}(x_1) = 1, \mu_{C_n}(x_2) = 1\] +Такое требование к универсуму и крайним нечетким множествам объясняется тем, что в противном случае формирование нечетких множеств не может считаться законченным. Так, например, если нечеткое множество $C_n$ является крайним справа, но не существует границы $x_2$ такой, что +\[\mu_{C_n}(x_2) = 1\] +то это наводит на мысль, что $x_2$ должно принадлежать не только множеству $C_n$, но и ещё какому-то справа. Но $C_n$ является крайним справа, а это значит, что такое множество нельзя добавить. +\end{itemize} + +\textbf{Дополнение} +Дополнение, обозначаемое знаком $\neg$. В результате этой операции по исходному нечеткому множеству $R \alpha$ получается новое нечеткое множество $\neg R \alpha$ . + +\[R'_\alpha = \neg R_\alpha = \bigcup_{x\in U} 1 - \mu_{R_\alpha} (x) / x\] +\begin{figure}[H] + \centering + \includegraphics[height=4cm]{04-addition.png} + \caption{Пример применения операции дополнения} + \label{pic:addition-example} +\end{figure} +На рис. \hrf{pic:addition-example} справа представлен пример применения операции дополнения. На этом рисунке с помощью выносных линий показаны функции принадлежности и нечеткие множества, в которые они входят. + +\textbf{Объединение и пересечение} +\begin{figure}[H] + \centering + \includegraphics[height=4cm]{04-addition2.png} + \caption{Пример применения операции объединения и пересечения} + \label{pic:union-example} +\end{figure} +Объединение, обозначаемое знаком $\bigcup$: +\[R_\alpha \bigcup R_\beta = \bigcup_{x\in U} max (\mu_{R_\alpha} (x), \mu_{R_\beta} (x)) / (x) \] + +Пересечение, обозначаемое знаком $\bigcap$. +\[R_\alpha \bigcap R_\beta = \bigcap_{x\in U} min (\mu_{R_\alpha} (x), \mu_{R_\beta} (x)) / (x) \] + +\textbf{Следование} +\begin{figure}[H] + \centering + \includegraphics[height=4cm]{04-follow.png} + \caption{Пример применения операции следования} + \label{pic:follow-example} +\end{figure} +Следование, обозначаемое знаком $\supset$. (в строгой обозначает принадлежность) +\[ (R_\alpha \supset R_\beta) = \{\mu_{R_\gamma}(x)/x \}, \] +где +\begin{equation*} + \mu_{R_\gamma}(x) = \begin{cases} + 1, \mu_{R_\alpha}(x) \leq \mu_{R_\beta}(x)\\ + \mu_{R_\beta}(x), \mu_{R_\alpha}(x) > \mu_{R_\beta} (x) + \end{cases} +\end{equation*} + +Следующие законы, называемые также нечеткими законами, являются общими для четких и нечетких множеств. +\begin{itemize} +\item Коммутативности: + \begin{equation*} + \begin{gathered} + A \cup B = B \cup A,\\ + A \cap B = B \cap A. + \end{gathered} + \end{equation*} +\item Ассоциативности: + \begin{equation*} + \begin{gathered} + A \cup (B \cup C) = (A \cup B) \cup C,\\ + A \cap (B \cap C) = (A \cap B) \cap C. + \end{gathered} + \end{equation*} +\item Дистрибутивности: + \begin{equation*} + \begin{gathered} + A \cup (B \cap C) = (A \cup B) \cap (A \cup C),\\ + A \cap (B \cup C) = (A \cap B) \cap (A \cap C). + \end{gathered} + \end{equation*} +\item Идемпотентности: + \begin{equation*} + \begin{gathered} + A \cup A = A,\\ + A \cap A = A. + \end{gathered} + \end{equation*} +\item Идентичности: + \begin{equation*} + \begin{gathered} + A \cup \oslash = A,\\ + A \cap U = A,\\ + A \cup \oslash = \oslash,\\ + A \cup U = U. + \end{gathered} + \end{equation*} +\item Транзитивности: если $A \subseteq B \land B \subseteq C$, то $ A \subseteq C$. +\item Инволюции: $\neg\neg A = A$, +\item Де Моргана: + \begin{equation*} + \begin{gathered} + \neg (A \cup B) = \neg A \cap \neg B,\\ + \neg (A \cap B) = \neg A \cup \neg B + \end{gathered} + \end{equation*} +\end{itemize} + +Два закона, справедливые для четких множеств, не выполняются для нечетких, – это законы исключенного третьего и противоречия. Для четких множеств эти законы выглядят следующим образом. +\begin{itemize} +\item Исключенного третьего: $A \cup \neg A = U$, +\item Противоречия: $A \cap \neg A = \oslash$. +\end{itemize} + +Для нечетких множеств они выглядят иначе: +\begin{itemize} +\item Исключенного третьего: $A \cup \neg A \neq U$, +\item Противоречия: $A \cap \neg A \neq \oslash$. +\end{itemize} + +\subsection{Пример} +\textbf{Нечёткая среда:} Стальной шарик, находится на плоской горизонтальной площадке, имеющей квадратную форму. На этой площадке проделана канавка так, как показано на рисунке \hrf{pic:uncertain}. Мы хотим смоделировать эту систему в терминах понятных человеческой речи и получить какие-то новые знания. +\begin{figure}[h] + \centering + \begin{tikzpicture} + \draw [->] (0, -2) -- (0, 2) node [right] {Y}; + \draw [->] (-2, 0) -- (2, 0) node [right] {X}; + \draw (-1, 1) rectangle (1, -1); + \draw (-1, 0.9) -- (0.9, -1); + \draw (-0.9, 1) -- (1, -0.9); + \end{tikzpicture} + \caption{Визуализация нечёткой среды} + \label{pic:uncertain} +\end{figure} + +Шарик может перемещаться только вдоль этой канавки. Его координаты определяются положением его центра. Расположение шарика на плоскости характеризуется двумя лингвистическими переменными: +\begin{equation*} + \begin{gathered} + ,\\ + . + \end{gathered} +\end{equation*} +где: + +\begin{itemize} +\item [] X и Y - координаты шарика; +\item [] $\theta_Б(X)$ = $\theta_Б(Y)$ = \{Слева, В-центре, Справа\} - базовые терм-множества; +\item [] $U = V = [-1, 1]$ - универсумы координат $X$ и $Y$; +\item [] $G, M$ - синтаксическое и семантическое правила. +\item [] Базовые терм-множества лингвистических переменных $X$ и $Y$ совпадают. +\end{itemize} +Универсумами $X$ и $Y$ являются два отрезка действительной прямой: $[-1, 1]$, а область рассуждений представляет собой их декартово произведение: $[-1, 1] \times [-1, 1]$. +\begin{figure}[h] + \centering + \includegraphics[height=4cm]{04-ball-location.png} + \caption{Графики функций принадлежности} + \label{pic:submissions} +\end{figure} + +\begin{itemize} +\item Лингвистические значения: Слева, В-центре, Справа, +\item Нечеткие множества: M(Слева), M(В-центре), M(Справа), +\item Универсумы: $[-1, 1]$, +\item Функции принадлежности: $\mu_L, \mu_C, \mu_R$ +\end{itemize} + +Имеем следующие аксиомы, выражающие свойства расположения шарика. +\begin{itemize} +\item (X = Слева $\supset$ Y = Справа) +\item (X = В-центре $\supset$ Y = В-центре) +\item (X = Справа $\supset$ Y = Слева) +\item (Возможно-50 X = В-центре $\land$ Возможно-50 X = Справа). +\end{itemize} + +Требуется установить расположение шарика. Заметим, что лингвистическое значение координаты X уже задано. Необходимо найти значения координаты Y. Для этого необходимо найти нечеткое множество S(Y), исходя из имеющихся аксиом. + +Лингвистическая переменная X: +\begin{equation*} + \begin{gathered} + \{\\ + X,\\ + \theta_б(X) = \{ \text{Слева, В-центре, Справа} \},\\ + U_х = [ -1, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1],\\ + G_х = \oslash,\\ + M_х = \{M_х(\text{Слева}), M_х(\text{В-центре}), M_х(\text{Справа})\\ + \} + \end{gathered} +\end{equation*} + +Лингвистическая переменная Y: +\begin{equation*} + \begin{gathered} + \{\\ + Y,\\ + \theta_б(Y) = \{ \text{Слева, В-центре, Справа} \},\\ + U_y = [ -1, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1],\\ + G_y = \oslash,\\ + M_y = \{M_y(\text{Слева}), M_y(\text{В-центре}), M_y(\text{Справа})\\ + \} + \end{gathered} +\end{equation*} + +\section{Нечёткие исчисления} +Связь нечетких множеств с естественным языком устанавливается с помощью понятия лингвистической переменной, которая характеризуется пятеркой: +\[< X, \theta(X), U, G, M>.\] +Здесь +\begin{itemize} +\item [] $X$ - название лингвистической переменной; +\item [] $\theta(X)$ - множество лингвистических значений переменной X, каждое из которых представляет собой слово или выражение естественного языка. +\item [] $\theta(X)$ - базовое множество лингвистических значений. Оно считается заданным, а остальные лингвистические значения (имена) порождаются синтаксическими правилами G. +\item [] Каждому лингвистическому значению ставится в соответствие нечеткое множество, заданное, на универсуме U. +\item [] Лингвистическое значение представляется словом естественного языка (именем лингвистического значения), а соответствующее нечеткое множество выражает его смысл. +\item [] Соответствие между лингвистическим значением из множества и каким-либо нечетким множеством задается с помощью отображения M, называемого также семантическими правилами. +\end{itemize} + +Введенные понятия лингвистической переменной позволяют ввести исчисление, значениями формул которого будут не ИСТИНА или ЛОЖЬ, а нечеткие множества. Сами формулы при этом становятся лингвистическими формулами, а исчисление называется нечетким исчислением. Интерпретация лингвистических формул осуществляется теперь на нечеткой среде и состоит в установлении соответствия между лингвистическими значениями и атрибутами термов, между нечеткими формулами и атрибутами нечетких схем отношений. Значениями формул теперь являются нечеткие множества. Моделью лингвистической формулы теперь является такая нечеткая среда, интерпретация в которой данной формулы позволяет вычислить по ней нечеткое множество с определенными свойствами, позволяющее характеризовать отношение, соответствующее этой формуле. + +Нечеткое исчисление, как и любое другое включает: +\begin{itemize} +\item язык, который будем называть нечетким языком (алфавит, синтаксис, семантика) +\item аксиомы, +\item правила вывода. +\end{itemize} + +В различного рода экспертных и управляющих системах используется нечеткий ввод на основе знаний, формируемых в простейшем случае в виде совокупности нечетких правил вида: +\begin{equation*} + \begin{gathered} + \text{Если } x = a_1, \to y = b_1,\\ + \text{Если } x = a_2, \to y = b_2,\\ + ...\\ + \text{Если } x = a_n, \to y = b_n.\\ + \end{gathered} +\end{equation*} + +где $a_i$ и $b_i$ —лингвистические значения лингвистической переменной соответственно x и y. В более сложном случае в посылке может стоять выражение, содержащее несколько термов, связанных операциями. + +\subsection{Алгоритмы элементарного вывода. Алгоритм Mamdani} + \includegraphics[width=11cm]{05-mamdani1.png} + + \includegraphics[width=11cm]{05-mamdani2.png} + + \includegraphics[width=11cm]{05-mamdani3.png} + + \includegraphics[width=11cm]{05-mamdani4.png} + +\section{Представление пространственно-временн\'{ы}х нечётких знаний (06)} +\subsection{Введение} +Охранные, географические, игровые, бытовые, медицинские, транспортные и многие другие системы требуют развития информационных технологий, которые позволяли бы анализировать сложные пространственно-временные ситуации. Эти технологии развиваются в искусственном интеллекте (ИИ), в частности, как системы, основанные на пространственно-временных представлениях знаний с использование нечетких отношений. + +\textbf{Конечный автомат} +Следуя подходу, изложенному в работах Р.А. Брукса, это прстранственно-временн\'{о}е поведение объектов может быть представлено иерархией взаимосвязанных конечных автоматов. Если мы точно знаем, какое поведение нас интересует, то принцип построения указанной совокупности автоматов состоит в следующем. + +Начиная наблюдение за средой с момента времени $t_e$ и заканчивая моментом времени $t_s$ строим все интересующие нас автоматы, начиная с простейших. + +\begin{itemize} +\item Шкала времени $T = \{t | t \in N \} $ +\item Временной интервал $[t_s,t_e] = \{t | t_s \leq t \leq t_e \} $ +\item Объект $ \theta$ +\item Значение признака 1-го уровня объекта (отсчёт) $y_{i_1} (\theta_t), i_1 = 1, ..., m_1 $ +\item Тренд $Y[\theta_{t_s}, \theta_{t_e}] = Y \langle y(\theta_{t_s}), ..., y(\theta_{t_s})\rangle$ +\item Поток трендов + \begin{equation*} + \begin{gathered} +Y_1 \langle y_1(\theta_{t_s}), ..., y_1(\theta_{t_s})\rangle,\\ +Y_2 \langle y_2(\theta_{t_s}), ..., y_2(\theta_{t_s})\rangle,\\ +...\\ +Y_n \langle y_n(\theta_{t_s}), ..., y_n(\theta_{t_s})\rangle. + \end{gathered} + \end{equation*} +\item Макроотсчет $Y(\Theta_t) = Y\langle y_i(\theta_{t_s}), ..., y_i(\theta_{t_s})\rangle$ +\item Макротренд $Y[\Theta_{t_s}, \Theta_{t_e}] = Y \langle y(\Theta_{t_s}), ..., y(\Theta_{t_s})\rangle$ +\item Поток макротрендов + \begin{equation*} + \begin{gathered} +Y_1 [\Theta_{t_s}, \Theta_{t_e}],\\ +Y_2 [\Theta_{t_s}, \Theta_{t_e}],\\ +...\\ +Y_n [\Theta_{t_s}, \Theta_{t_e}]. + \end{gathered} + \end{equation*} +\end{itemize} + +\subsection{Объекты, отрезки, признаки} +Предположим, есть два объекта, расположенные на плоскости в каком-то отношении друг к другу. Возможно описать взаиморасположение этих объектов формулами (предикатами первого порядка, фактами). и определить поведение этих объектов как в статике, так и в динамике. +\begin{multicols}{2} +\includegraphics[width=5cm]{06-obj-prop.png} + \columnbreak +\begin{equation*} + \begin{gathered} + \Theta = \{ \theta_t^1, \theta_t^2 \}\\ + y_{11}(\theta_t^1) = x_{\theta(t)}^1,\\ + y_{12}(\theta_t^1) = y_{\theta(t)}^1,\\ + y_{13}(\theta_t^1) = \alpha_{\theta(t)}^1,\\ + y_{21}(\theta_t^2) = x_{\theta(t)}^2,\\ + y_{22}(\theta_t^2) = y_{\theta(t)}^2,\\ + y_{23}(\theta_t^2) = \alpha_{\theta(t)}^2,\\ + \end{gathered} +\end{equation*} +\end{multicols} + + +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.31\textwidth} + \centering + \includegraphics[width=\textwidth]{06-obj-dir.png} + \caption{направлений (совпадающие} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.31\textwidth} + \centering + \includegraphics[width=\textwidth]{06-obj-orien.png} + \caption{ориентаций (сзади} + \end{subfigure} + \caption{Макроотсчёты} +\end{figure} + +Что может происходить со временем-пространством и объектами? Возможно подсчитать тренды расстояния, направления и ориентации, чтобы понять, как изменяются соответствующие параметры. +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.47\textwidth} + \centering + \includegraphics[width=\textwidth]{06-macro-s.png} + \caption{$Y_{\text{расстояние}} [ \Theta_t, \Theta_{t+2\Delta t}] $} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.47\textwidth} + \centering + \includegraphics[width=\textwidth]{06-macro-or.png} + \caption{$Y_{\text{ориентация}} [ \Theta_t, \Theta_{t+2\Delta t}] $} + \end{subfigure} + + \begin{subfigure}[b]{0.5\textwidth} + \centering + \includegraphics[width=\textwidth]{06-macro-dir.png} + \caption{$Y_{\text{направление}} [ \Theta_t, \Theta_{t+2\Delta t}] $} + \end{subfigure} + \caption{Макротренды} +\end{figure} + + +Представим макротренд +\[ Y[\Theta_{t_s}, \Theta_{t_e}] = Y \langle y(\Theta_{t_s}), ..., y(\Theta_{t_s})\rangle \] + +конечным автоматом $M_i [\Theta_{t_s}, \Theta_{t_e}]$. + +\[ f[t,b_i(\Theta_t] = b_i(\Theta_{t+\Delta}), t \in [t_s, t_e - \Delta], \varphi[b_i(\Theta_t)] = y_i(\Theta_t) \] + +Вводим состояния, время и переходы (граф) как тренды. Время в КА конечно, то есть мы его зацикливаем. Описываем функции выхода + +(06-15-16) описываем КА. каждое состояние КА ведёт себя как малый КА. Или, например, показывает как меняется расстояние в зависимости от времени. как ведут себя объекты. + +(06-17-18-19) мы строим эталон поведения системы в виде КА и можем моделировать или сразу делать программу, устанавливая КА в исходное состояние. Если эталонная и реальная модель совпадают на всём участке времени мы делаем вывод о правильном поведении. + +\subsection{Замечания} +Рассмотрены детерминированные четкие автоматы, для построения которых использовались линейные тренды (время в этих трендах линейно). Для многих сред это может быть не адекватно и не удобно. Может оказаться, что нелинейные (ветвящиеся тренды), более адекватно описывают среду. Автоматы в этом случае могут быть недетерминированными. +Любой автомат может быть представлен не только в виде графа, но и в виде множества правил или уравнений специального вида. Это потребует модификации предложенного метода применительно к такому представлению. +Четкие автоматы слишком чувствительны для распознавания ситуаций в нечетких средах. Для таких сред требуется развитие методов, использующих нечеткие автоматы, а также методы нечеткого агрегирования отношений. + +\subsection{Нечёткие множества} +(06-23) вместо КА получаем нечёткий КА. функции перехода остаются почти неизменные, а вот признаки меняются. Каждому состоянию соответствует нечёткое множество. +(06-24-25-26) Сравниваем поведение срежды с поведением НА. если на каждом шаге значение совокупности признаков (совокупной функции принадлежности) не является нулевым, получаем знание о правильности поведения (нахождение в рамках допустимых). +(06-27-28-29) Вводим множество функций принадлежности для НА, описывающего систему, в которой человек хочет включить телевизор. +(06-30-31) Вводим состояния и переходы, распознаём ситуации +% Здесь в прошлогодних презентациях пробел. Распознавание аварийной ситуации на перекрёстке. +% Вводим лингвистические переменные (место относительно перекрёстка: далеко, близко, содержится. скорость: большая маленькая). +% можем создать граф автоматов первого уровня (начальные графы). Это будут разные графы с одной и той же формулой. +% Универсум нечёткого множества лингвистической переменной + +% строим граф второго уровня исходя из соображений правил вождения. тогда общая эталонная модель характеризует и физическую среду и некоторые субъективные правила поведения на перекрёстке. + +Самый очевидный способ проверить работу КА - это тестирование. взяв у некоего эксперта набор знаний и тестовых данных - получаем ок/не ок на выходе. Если же есть модель знаний, мы можем сформулировать более точную модель поведения программы по парвилам. Продолжение в разделе \hRf{section:modal} +(06-32-33-34-35) + + +\section{Стратегии извлечения знаний в пространстве состояний} +Состояния среды, с которых начинается поиск достижения цели называются \textbf{начальными состояниями}. Состояния среды, которые надо найти (вывести), называются \textbf{целевыми состояниями}. Множество всех состояний, достижимых из начального с помощью всех \textit{допустимых последовательностей действий} называется \textbf{пространством поиска} (пространством состояний), обозначаемым B. Последовательность состояний ведущих из начального состояния в другое в данном пространстве состояний называется \textbf{путем}. Процесс нахождения целевых состояний называется \textbf{стратегией вывода} (поиска) цели или просто поиском цели. Агент, являющийся исполнителем той или иной стратегии должен действовать таким образом, чтобы при анализе состояний среды максимизировать меру своего успеха. Это требование носит общий характер, чтобы его можно было непосредственно воплотить в конкретную стратегию. Рассмотрим сначала, какие оценки могут характеризовать \textbf{меру успеха} (оценку успеха). + +\subsection{Оценки успеха стратегий поиска} +Оценки успеха, характеризующие эффективность поиска цели, могут быть самыми различными. +\begin{itemize} +\item Самая очевидная оценка - это возможность достижения цели вообще. +\item Другая оценка может быть ценой пути, вычисляемой с помощью функции цены пути. +\item Третья оценка может быть ценой поиска, характеризующейся объемом необходимых для поиска времени и памяти. +\item Наконец, еще одна оценка успеха может быть общей ценой, являющейся некоторой функцией от цены пути и цены поиска. +\end{itemize} + +Критерии оценки стратегий поиска +\begin{itemize} +\item Полнота: стратегия является полной, если она всегда обеспечивает достижение цели (целевого состояния или состояний) если оно вообще существует в данном пространстве состояний. +\item Сложность по времени: время, необходимое для достижения цели. +\item Сложность по памяти: объем памяти, необходимый для достижения цели. +\item Оптимальность: стратегия называется оптимальной, если она обеспечивает достижение цели не с самой лучшей оценкой успеха, но известно, что оно принадлежит некоторому классу или подмножеству стратегий, обладающих неким общим свойством или свойствами, по которым мы их относим их к оптимальным решениям. +\item Минимальность: стратегия является минимальной, если она обеспечивает достижение с наилучшей оценкой успеха. Минимальность таким образом является частным и более сильным случаем оптимальности. +\end{itemize} + +\subsection{Слепой и направленный поиск} +Стратегии поиска разбиваются на две большие группы: +\begin{itemize} +\item слепой поиск, +\item направленный поиск. +\end{itemize} +Различие между слепым и направленным поиском можно продемонстрировать на следующем простом примере. + +Представим себе, что агент приехал в Россию по туристической путевке с целью совершить путешествие по золотому кольцу России. Его самолет сел в аэропорту Шереметьево. Обратный вылет тоже из Шереметьева. Дальнейший маршрут агента должен был осуществляться на автобусе и почти благополучно завершился. Посетив все города золотого кольца, агент самостоятельно поехал в близлежащий город Иваново, где отстал от автобуса. В отличие, например, от Ярославля, Иваново не имеет прямой автострады, соединяющей его с Москвой. Агент имеет билет на самолет с датой вылета на следующий день, билет не может быть продлен, да к тому же билетов вообще нет ранее, чем через две недели. Срок визы также заканчивается через два дня. + +Отправляясь в поездку, агент ставил перед собой, помимо чисто туристических, несколько других целей: улучшить знание русского языка, завязать полезные деловые контакты, написать несколько пейзажей с видами русской природы и т.п. Но, учитывая серьезность ситуации, главной его целью теперь стало вовремя добраться до аэропорта Шереметьево, не опоздав на свой самолет. После формулировки главной цели агент может принимать во внимание и другие факторы, влияющие на ее достижение. Прежде всего, следует решить, что мы будем понимать под действиями и состояниями. Если бы вдруг нам пришло в голову в качестве действий выбрать такие, как «повернуть руль на 10 градусов» или «продвинутся вперед на 1 метр», то решение задачи на таком уровне детализации стало бы практически неразрешимой задачей. + +В нашем случае в качестве действий лучше всего выбрать переезд из одного города в другой, а в качестве состояний нахождение агента в том или ином населенном пункте. \textbf{Целевым состоянием} в этом случае будет достижение агентом аэропорта Шереметьево (в Москве). Поиск будет слепым, если агент не имеет никакой информации о дорогах, ведущих из Иваново в другие города, и будет просто перебирать все дороги подряд. Поиск станет направленным, если он ознакомится с картой, увидит, что Москва лежит на юго-западе от Иваново, и будет пытаться выбирать дороги, ведущие в юго-западом или близком к нему направлениям. + +\subsection{Слепой поиск в ширину} +Одна из самых очевидных стратегий поиска называется поиском в ширину: +\begin{itemize} +\item начинается поиск с корневой вершины, +\item находятся все последователи корневой вершины, +\item затем все последователи каждого из последователей корневой вершины, +\item затем все последователи каждого из последователей, найденных на предыдущем шаге, +\item и т.д. до тех пор, пока не будут найдены все вершины, соответствующие целевым состояниям. +\end{itemize} +По этой стратегии вершины глубины k + 1 ищутся после того, как будут найдены все вершины глубины k. + +На рис. ниже показана последовательность нахождения вершин при поиске в ширину и при числе последователей каждой вершины, равной 2. При поиске в ширину сначала рассматриваются все пути длины 1, затем длины 2 и т.д. Очевидно, что поиск в ширину удовлетворяет критерию полноты, поскольку в процессе этого поиска рассматриваются все пути, ведущие из начальной вершины (состояния) во все остальные. + +(07-10) + +Будем полагать, что число последователей каждой вершины равно l. Тогда в начале поиска в ширину мы имеем 1. В общем случае при глубине дерева поиска, равном k число вершин, получаемых в процессе поиска равно + \[ 1 + l + l^2 + l^3 + ...+ l^k.\] +При конкретных значениях l и k по этой формуле можно вычислить максимальное число вершин дерева поиска, которое может быть получено в процессе поиска в ширину. Решение может быть найдено раньше, чем будут найдены все последователи. Однако для некоторых задач эта величина может быть достигнута. Обычно вместо этой формулы употребляют ее обозначение в виде $O(l^k)$, которое называют экспоненциальной оценкой сложности. Если полагать, что получение каждого последователя требует одной единицы времени, то $O(l^k)$ является также оценкой сложности по времени. Если полагать, что для этого сохранения требуется единица памяти, то та же формула является одновременно и оценкой сложности по памяти для поиска в ширину. + +Посмотрим, что это будут за величины при числе последователей l = 10 для различных значений глубины дерева поиска k. Предположим, что 1000 вершин-последователей могут быть получены за 1 сек, и что одна вершина требует 100 байт памяти. Эти величины соответствуют средним затратам времени и памяти, требуемым для решения многих иллюстративных задач типа головоломок. При этих предположениях получим следующую таблицу. + +(07-14) + +Глядя на нее, можно сделать два важных вывода. +\begin{enumerate} +\item рост требований к памяти для решения задач поиском в ширину гораздо более серьезная проблема, чем рост требований ко времени решения тех же задач. Так, например, вполне приемлемо подождать решения задачи в течение 18 минут при l = 6, но необходимость наличия 111 мегабайт памяти для решения таких сравнительно простых задач кажется слишком высокой ценой. +\item Для задач, в которых $l \geq 10$, помимо катастрофического роста требований к памяти, наблюдается быстрый рост временных затрат, не позволяющий решать реальные задачи с помощью поиска в ширину даже на современных мощных компьютерах. Это приводит к следующему заключению. +\end{enumerate} +Стратегии поиска, имеющие экспоненциальные оценки сложности решения задач по времени или памяти, в частности стратегия поиска в ширину, не могут быть использованы для решения задач большой размерности, т.е. задач, у которых $l \geq 10$. + +\subsection{Монотонный поиск в ширину} +Монотонный поиск в ширину является некоторой модификацией поиска в ширину. Модификация заключается в том, что в процессе поиска в ширину всякий раз, когда определяется очередная вершина-последователь, одновременно вычисляется цена пути, ведущего в эту вершину. Эта цена пути используется для оценки целесообразности поиска вершин, продолжающих данный путь, сравнением с другими, уже полученными ценами путей. Если цена данного пути меньше цен всех этих путей, то поиск вершин на этом пути продолжается. В противном случае поиск вершин на этом пути откладывается, а продолжается поиск вершин на путях, цена которых меньше данного. Когда на каком-либо пути будет достигнута целевая вершина, то поиск на путях цена которых выше цены этого пути вообще прекращается. Все пути, имеющие одинаковую минимальную цену путей, ведущих в целевую вершину, являются решением задачи. + +На Рис Б. схематически показана карта участка дорог, ведущих из Иваново в Москву. Каждая из дорог, ведущих из одного пункта в другой, снабжена числовой оценкой цены пути. На Рис. А показана последовательность монотонного поиска в ширину. Каждая из вершин помечена ценой пути, ведущего в эту вершину. + +(07-18) + +\subsection{Поиск в глубину} +При поиске в глубину, начиная с корневой вершины (корневая вершина находится на уровне 1), рассматриваются все инцидентные ей вершины уровня 2, начиная слева направо. Если удается найти среди них все целевые вершины, то на этом поиск прекращается. Если среди них не удается найти все целевые вершины, а максимальная глубина дерева еще не достигнута, то берется самая левая вершина из числа рассмотренных уровня 2, и рассматриваются все инцидентные ей вершины уровня 3 слева направо. + +Если после этого все целевые вершины все еще не найдены, то берется самая левая вершина из числа рассмотренных уровня 3. Затем снова рассматриваются все инцидентные ей вершины уровня 3 слева направо и так до тех пор, пока либо не будут найдены все целевые вершины, либо достигнута максимальная глубина дерева, на которой в соответствии с рассматриваемой процедурой просмотрены все вершины, инцидентные самой левой вершине предыдущего уровня, и все целевые все еще не найдены. + +В последнем случае осуществляется подъем по дереву на один уровень вверх, выбор на этом уровне самой левой вершины, инцидентные которой вершины следующего уровня еще не рассмотрены и поиск дальше среди целевых вершин по тому же принципу. И так до тех пор, пока все вершины дерева не будут рассмотрены. На Рис. показана последовательность поиска в глубину для дерева с тремя уровнями и степенью ветвления 2. + +(07-21) + +Требования к объему памяти при поиске в глубину существенно меньше, чем при поиске в ширину. В памяти необходимо хранить все вершины, инцидентные вершинам на пути из корневой вершины к любой другой, соседние вершины которой рассматриваются. Очевидно, что при степени ветвления l и глубине ветвления k, оценка сложности по памяти при поиске в глубину равна $О(l^k)$. Оценка сложности по времени для поиска в глубину остается такой же как и при поиске в ширину, а именно $О(l^k)$. + +Для задач, дерево поиска для которых конечно, а число целей сравнительно невелико, поиск в глубину может оказаться эффективным, так как имеет шанс найти это небольшое число целей без просмотра всех вершин. Для задач, имеющих большую или даже бесконечную глубину дерева, поиск в глубину может оказаться крайне неэффективным, так как будет стремиться все время в глубину, в то время как цель может оказаться близкой к корню дерева, но на том пути, который еще не был просмотрен. + +Поиск же все время уходит вниз и в случае бесконечной глубины дерева может никогда не вернуться назад к просмотру вершин, среди которых находятся целевые. Вследствие этого следует избегать использования поиска в глубину для решения задач с большой или бесконечной глубиной дерева. Поиск в глубину не полон, в случае бесконечного дерева, и не оптимален. + +\textbf{Ограниченный поиск в глубину} является частным случаем поиска в глубину. +При этом поиске используется ограничение на глубину поиска. Например, при поиске маршрута из Иваново в Москву, при наличии информации о числе населенных пунктов, которые могут встретиться на этом пути, глубину поиска можно ограничить числом этих населенных пунктов. + +При ограниченном поиске в глубину, как только достигается уровень, совпадающий с этим числом, происходит возврат назад также как это делается при обычном поиске в глубину. Ограниченный поиск в глубину полный, если ограничение на глубину поиска выбрано таким образом, чтобы обеспечить просмотр всех вершин дерева. Оценки сложности по времени и памяти при ограниченном поиске в глубину те же, что и при обычном поиске в глубину. + +\subsection{Итеративный поиск в глубину} +При ограниченном поиске в глубину сложность поиска зависит от выбора ограничения. Например, при поиске маршрута можно использовать не число всех населенных пунктов в районе поиска подходящего маршрута, а максимальное число населенных пунктов, которые могут встретиться на каждом из возможных маршрутов. Это число, называемое обычно \textbf{радиусом поиска}. Знание радиуса поиска приводит к более эффективному ограниченному поиску в глубину. Однако в большинстве задач радиус поиска не известен до тех пор, пока задача не будет решена. Итеративный поиск в глубину использует стратегию, основанную на итеративном применении ограниченного поиска в глубину сначала для радиуса поиска, равного 0, затем 1, после этого 2 и т.д. Итерации итеративного поиска для бинарного дерева иллюстрирует Рис. справа. + +(07-26) + +Итеративный поиск в глубину может показаться очень неэффективным, поскольку некоторые вершины просматриваются многократно. Однако для многих задач подавляющая доля вершин находится на низком уровне. Напомним, что оценка сложности по времени при ограниченном поиске в глубину вычисляется по формуле + +\[О(lk) = 1 + l + l^2+ .... + l^{k-2}+ l^{k-1}+ l^k\] + +Для l = 10, k = 5 будем иметь $О(l^k) = 111111$. При итерактивном поиске в глубину вершины 1-го уровня просматриваются k + 1 раз, второго k и т.д. Таким образом, оценка сложности по времени при итеративном поиске в глубину вычисляется по формуле + +\[ О(l^k) = (k+1)l + (k)l + (k-1)l^2+ ... +3 l^{k-2} + 2 l^{k-1} + 1 l^k \] + +Для l = 10, k = 5 будем иметь $О(l^k) = 123456$ + +По сравнению с оценкой сложности по времени для ограниченного поиска в глубину сложность по времени для итеративного поиска в глубину возросла только на 11\%. Из формулы, приведенной выше видно, что чем выше степень ветвления, тем ниже доля сложности, получающейся за счет повторного просмотра вершин. Для случая, когда l = 2, сложность по времени итерационного поиска в глубину только в два раза превосходит сложность по времени простого поиска в глубину. Это означает, что оценка сложности по времени итерационного поиска в глубину по-прежнему равна $О(l^k)$, а сложность по памяти - $О(lk)$. Итеративный поиск в глубину достаточно хорошо себя зарекомендовал для задач с большим пространством поиска и неизвестной его глубиной. + +\subsection{Двунаправленный поиск} +Идея двунаправленного поиска основана на использовании сразу двух стратегий +\begin{enumerate} +\item прямого поиска от корневой вершины +\item обратного от целевой вершины. +\end{enumerate} +Процесс поиска прекращается, когда оба этих процесса встретятся на середине глубины. Если считать, что степень ветвления при прямом и обратном поиске одинакова, то оценка сложности по времени двунаправленного поиска будет $О(2l^{k/2}) = О(l^{k/2})$. Эта оценка существенно лучше, чем аналогичная для рассмотренных стратегий поиска при больших k. В таблицу ниже сведены характеристики шести рассмотренных стратегий, где l - степень ветвления, k - глубина поиска, d - максимальная глубина дерева поиска, r ограничение на глубину поиска. + +(07-30) + +\subsection{Направленный поиск} +Все стратегии слепого поиска обладают экспоненциальными оценками сложности по времени поиска, а некоторые и по памяти, и, вследствие этого, пригодны для решения сравнительно небольших задач. В стратегиях слепого поиска знания, используемые при выборе очередной вершины, определяют только общий порядок выбора и никак не учитывают качество выбора, например, по сложности поиска целевой вершины. В стратегиях направленного поиска знания, используемые для выбора очередной вершины, более глубокие и используют специальные функции, называемые критериями. Если для каждой вершины b, участвующей в поиске, критерий может быть вычислен, а множество всех вершин упорядочивается по этому критерию, то выбор очередной вершины производится в соответствии со значением этого критерия. + +Чем лучше значение критерия (например, выше или ниже), тем предпочтительней выбор. Иными словами из множества альтернативных вершин выбирается та, для которой критерий имеет наилучшее значение. Стратегии выбора подобного типа называются стратегиями выбора по наилучшему критерию. Критерии обычно выбираются таким образом, чтобы оптимизировать сложность поиска, найти оптимальное решение или достичь того и другого. + +\subsection{Поиск по критерию близости цели} +Критерием близости к цели обычно является числовая функция $h(b) \geq 0$, вычисляемая для вершины b и характеризующая близость этой вершины к целевой. При использовании критерия близости к цели, начиная с корневой вершины, просматриваются все соседние ей вершины, выбирается та, для которой h(b) минимальна, и все повторяется вновь для выбранной вершины. И так до тех пор, пока не будет достигнута целевая вершина, для которой h(b) = 0, т.е. выбирается та вершина, которая ближе всего находится к цели. Вид критерия близости к цели зависит от среды (является проблемно зависимым). Чтобы получить достаточно полное представление об этом критерии, вернемся к задаче поиска маршрута из Иваново в Москву. Критерием выбора в этом случае будет минимальное расстояние по прямой (кратчайшее расстояние) от вершины (населенного пункта) до Москвы. + +Естественно, чтобы значение критерия могло быть вычислено, необходимо иметь карту или какой-либо другой источник информации, содержащий сведения о кратчайших расстояниях от населенных пунктов до Москвы. На Рис. ниже показана последовательность поиска по критерию близости к цели для примера с поиском маршрута из Иваново в Москву, использованного при рассмотрении монотонного поиска в ширину. + +(07-35) + +Поиск по критерию близости к цели является поиском в глубину, но с выбором на каждом шаге единственной вершины, от которой начинается следующий шаг. Недостатки этой стратегии те же, что и для слепого поиска в глубину, а именно, она неоптимальная и неполная, поскольку может случиться, что поиск пойдет по бесконечному пути и никогда не вернется назад. Оценка сложности по времени этой стратеги поиска равна $О(l^d)$, где d - максимальная глубина пространства поиска. При поиске по критерию близости к цели приходится хранить все вершины, рассматриваемые при поиске. Поэтому оценка сложности по памяти для этой стратегии та же, что и оценка сложности по времени. Если критерий близости к цели выбран достаточно удачно, то сложность поиска может быть существенно уменьшена. + +\subsection{Поиск по критерию цены пути (A* - поиск)} +Обозначим +\begin{itemize} +\item [] g(b) - критерий цены пути из корневой вершины в вершину b, +\item [] h(b) - уже рассмотренный критерий близости к цели. +\end{itemize} +Пусть оба критерия имеют одну и ту же размерность. Функцию $f(b) = g(b) + h(b)$ будем считать интегральным критерием цены пути из корневой вершины в целевую. Рассмотрим стратегию поиска на основе этого критерия и покажем, что она будет полна и оптимальна. + +Введем небольшие ограничения на критерий h(b). Идея этого ограничения состоит в том, чтобы выбирать критерий h(b), таким образом, чтобы не переоценивать близость к цели, т.е. всегда выбирать значение h(b) больше, чем оно есть на самом деле. Критерий h(b), выбираемый таким образом, называется \textbf{допустимым}. Стратегия поиска, использующая критерий f(b) и допустимый критерий h(b) известна как \textbf{А*- поиск}\footnote{https://ru.wikipedia.org/wiki/A*}. Критерий близости к цели h(b), использованный в примере с поиском маршрута из Иваново в Москву, является типичным примером допустимого критерия, поскольку не может быть пути из одного населенного пункта в другой короче, чем кратчайший путь. На рис. справа показаны первые четыре шага поиска пути из Иваново в Москву с использованием критерия f(b) в А*- поиске. + +(07-39) + +В результате этого поиска, в отличие от поиска только по критерию близости к цели, рассмотренном в предыдущем разделе, выбран путь к Москве не через Юрьев-Польский, а через Владимир, хотя Юрьев-Польский ближе к Москве, чем Владимир. Такой выбор объясняется тем, что цена пути g(b) от Иваново до Юрьева-Польского выше, чем до Владимира вследствие очень плохой дороги. + +(07-40) + +Выбор маршрута можно проследить по рисунку. На любом пути от корневой вершины значение критерия f(b) нигде не уменьшается при переходе к рассмотрению очередной вершины. Это не случайность и справедливо почти для всех допустимых критериев h(b) близости к цели. Критерии f(b), для которых имеет место подобное свойство, называются монотонными. Если монотонность нарушается, то путем незначительной коррекции это нарушение может быть устранено. + +(07-41) + +Рассмотрим, например, пару вершин b, b', где b предшественник, а b' - последователь. Предположим, что g(b) = 3, h(b) = 4. Тогда f(b) = 7, т.е. цена пути через вершину b самое меньшее равна 7. Предположим также, что g(b') = 4 h(b') = 2, т.е. f(b') = 6 . Ясно, что в этом случае критерий f(b) не является монотонным. К счастью, благодаря тому, что любой путь через b' является также путем через b, цена пути f(b') = 6 является бессмысленной. + +Поэтому каждый раз, как рассматривается какая-либо вершина b' и оказывается, что ее цена пути f(b') < f(b), мы полагаем, что f(b') = f(b), т.е. f(b') = max (f(b), f(b')). Таким способом немонотонность может быть всегда устранена, и критерий f(b) никогда не будет уменьшаться вдоль одного и того же пути при условии, что h(b) допустимое. Если же f(b) никогда не уменьшается вдоль одного и того же пути, начинающегося от корневой вершины, то на пространство состояний можно наложить контуры, каждый из которых охватывает множество вершин b, для которых значение критерия f(b) меньше определенной величины c. + +Процесс поиска можно представить как переход от просмотра еще не просмотренных вершин какого-либо внутреннего контура, для всех вершин b1 которого имеет место $f(b1) \leq c1$, к просмотру вершин некоторого внешнего контура, для всех вершин b2 которого имеет место $f(b2) \leq c2$ и c1 < c2 . Это продолжается до тех пор, пока внутри очередного контура не окажется целевая вершина с h(b) = 0. При удачном выборе критерия f(b), контуры как бы растягиваются в сторону целевой вершины, фокусируясь вокруг оптимального пути. + +Обозначим c* цену оптимального пути. Тогда можно утверждать следующее +\begin{itemize} +\item А*- поиск просматривает вершины с $f(b) \leq c*$. +\item А*- поиск осуществляет направленный просмотр вершин, стремясь к просмотру вершин контура, для которых имеет место f(b) = c*. +\end{itemize} + +Решение, получаемое с помощью А*- поиска, является оптимальным, поскольку находится вершина с максимальным значением f(b), а следовательно и максимальным g(b), поскольку h(b) = 0. А*- поиск является также полным, поскольку увеличивая постепенно значение критерия f(b) мы должны, в конце концов, найти путь к целевой вершине. Заметим также, что для данного критерия f(b) не существует никакой другой процедуры поиска, которая давала бы более оптимальные решения, чем А*- поиск. + +Все эти утверждения требуют более строгих доказательств, которые здесь не приводятся. Оценки сложности по времени и памяти для А*- поиска аналогичны оценкам для поиска по критерию близости цели. На идее А*-поиска построено много других методов поиска, учитывающих особенности конкретной среды, влияющих на выбор критериев, и различные ограничения, например по доступным ресурсам (времени выполнения и доступной памяти). + +\subsection{Оптимизирующий итеративный поиск} +Во многих задачах поиск целевого состояния (состояний) в пространстве состояний ставится как задача нахождения такого состояния (состояний), которые в определенном смысле наилучшие (оптимальные). При этом не имеет особого значения цена пути нахождения цели, если эта цель может быть достигнута за приемлемые затраты времени и памяти. Идея оптимизирующего итеративного поиска станет понятной, если полагать что состояния - это точки на поверхности некоторого горного ландшафта. Чем выше точка находится над уровнем моря, тем лучше (оптимальней) состояние, которое она представляет. Точки, соответствующие пикам являются оптимальными точками. + +Задачей оптимизирующего итеративного поиска является такой порядок просмотра точек, или иначе такое движение по поверхности ландшафта, чтобы в конце концов достичь (найти) оптимальные точки. Имеется большое разнообразие стратегий оптимизирующего итеративного поиска. Например, к их числу относиться простой градиентный поиск. + +Идея простого градиентного поиска чрезвычайно проста: +\begin{itemize} +\item начиная с некоторого начального состояния, двигаться в направлении подъема вверх, +\item дерево поиска не хранить, а сохранять только последнее найденное состояние b и оценку его качества L(b). +\item если попадется несколько состояний с одинаковой оценкой качества, выбирать одно из них. +\end{itemize} +Простой градиентный поиск в чистом виде обладает тремя известными недостатками: +\begin{itemize} +\item Если вершин несколько, то поднявшись на одну из них, процесс поиска остановится, полагая, что цель достигнута, хотя достигнутая вершина является всего лишь локальным оптимумом и далека от наилучшей. +\item Если ландшафт имеет плато, то процесс поиска по нему становится случайным. +\item Если ландшафт имеет гребни (хребты) со слабым наклоном, то легко достигнув гребня, процесс поиска может очень долго идти по гребню, пока достигнет оптимальной вершины. +\end{itemize} +После остановки процесса градиентного поиска начинается следующая итерация с другого начального состояния. Найденное оптимальное состояние сохраняется до тех пор, пока не будет найдено лучшее. Этот итеративный процесс поиска продолжается конечное число раз или пока не будет найдено устраивающее решение. Ясно, что если провести достаточное число подобных итераций, то оптимальное решение, в конце концов, будет найдено. + +Успех градиентного поиска сильно зависит от вида пространства состояний. Если число локальных минимумов невелико, то оптимальное решение будет найдено сравнительно быстро. Стратегии градиентного поиска могут отличаться способом выбора очередной вершины в процессе подъема на вершину, выбором очередной вершины для новой итерации и т.д. + +\section{Линейная временная модальная логика} +\label{section:modal} +Основные формы представления знаний - это графы. +\begin{itemize} +\item \textbf{Динамическая среда}. Среда является динамической, если ее состояния изменяются во времени. Актуальная задача – это анализ этих изменений. Не требуется знания ни точного времени перехода в те или иные состояния, ни самих этих состояний. Требуется установление истинностного значения (И или Л) той или иной формулы, выражающей определенные отношения между объектами динамической среды и не явно зависящей от состояний среды, изменяющихся во времени. +\item \textbf{Модальность}. На естественном языке для выражения этих отношений обычно используются слова типа «допустимо», «необходимо», «возможно» и т.п., выражающих определенную степень уверенности наступления каких-либо событий во времени или пространстве, но без указания точного времени или места. Возможность делать в логике высказывания, содержащие выразительные средства, характеризующие подобную степень уверенности или «силу» высказывания называется модальностью. Исчисления, в которых вводятся специальные символы или слова (модальные операторы), с помощью которых это делается, называются модальными исчислениями. +\end{itemize} +Линейная временная модальная логика основана на логике предикатов первого порядка. Называется линейной модальной логикой. Слово «временное» употребляется здесь в связи с тем, что изменение подразумеваемых состояний происходит во времени. Слово «линейное» означает, что время течет линейно, нет параллелизма. Состояния тоже изменяются линейно в этом времени. Всегда анализируем единственный возможный путь. +\subsection{Переход от логики предикатов к модальной логике} +Переход от логики предикатов к модальной логике не такой резкий, как переход от логики исчисления высказываний к логике предикатов. При этом выбор переменных, определяющих состояние, произволен и зависит от субъективной точки зрения. Переменные, определяющие состояние, являются более важными, чем все остальные. Формулы модальной логики не зависят явно от состояний и тем самым от переменных, его определяющих. Временная модальная логика предполагает наличие базисного отношения достижимости между состояниями: R(s, s'), которое определяет возможность перехода из одного состояния s в другое s'. Это отношение имеет место, если ситуация s' достижима из состоянии s. + +(08-06) +Линейная модальная логика предполагает, что между состояниями можно установить отношение достижимости: +R(s, s,), если состояние (день, место) s, следует за состоянием s. +Обычно считается, что отношение R(s, s) всегда имеет место. +Главная идея обозначений, принятых в модальной логике, состоит в стремлении избежать использования состояний и отношения достижимости. +Для этого в линейной временной логике вводится два основных модальных оператора, описывающих свойства достижимости состояний: +оператор необходимости $\bullet$, +оператор возможности ◊. +возможны и другие модальные операторы + +(08-07) +w некоторая формула модальной логики. +w и ◊w также формулы модальной логики. +Значение формул w, w и ◊w неявно зависит от некоторго текущего состояния s. +Формула w считается истинной в состоянии s, если формула w истинна на всех состояниях достижимых из состоянии s, включая собственно ситуацию s. +Формула ◊w считается истинной в состоянии s, если формула w истинна хотя бы в одном состоянии, достижимом из состоянии s. +Обозначим w(s) значение формулы w в состоянии s. +Тогда правила вывода истинных значений модальных формул w(s) и ◊w(s) можно записать следующим образом. + +Модальная формула записывается с помощью пропозициональных символов, предикатных символов (включая равенство), функциональных символов, констант, переменных, классических операторов (связок) и кванторов, модальных операторов. Формула без модальных операторов, являющаяся по существу формулой логики предикатов первого порядка, называется иногда статической. +Модальная формула, называемая иногда динамической, содержит статические подформулы, к которым и модальные операторы. Истинное значение модальной формулы в некотором состоянии может быть найдено с помощью повторяющегося использования указанных выше правил для модальных операторов и вычисления статических формул в каждом состоянии. + +(08-09) +Формула ◊(w) истинна в состоянии s, если существует хотя бы одно состояние s', достижимое из состояния s, в которой истинна формула w. Другими словами истинность формулы ◊(w) означает, что существует состояние s', достижимое из состояния s, такое, что в состоянии s' и во всех достижимых из него состояниях истинна формула w. Формула (◊w) истинна в состоянии s, если во всех состояниях s', достижимых из состояния s, истинна формула ◊ w. Другими словами истинность формулы (◊w) означает, что для всех состояний s', достижимых из состоянии s, можно найти хотя бы одно достижимое из s’ состояние, в котором истинна формула ◊w. + +(08-11) +Формула (w ⊃  w) истинна, если для всех состояний s', достижимых из s, истинна формула w ⊃  w.. Истинность формулы w ⊃  w в ситуации s' означает, истинность формулы w во всех ситуациях достижимых из ситуации s'. +Таким образом, истинность формулы  (w ⊃ w) означает, что формула w становится всегда истинной в любой ситуации s', достижимой из s и остается истинной для всех состояний, достижимых из s'. +Модальная логика построена на базе логики предикатов. +Для нее справедливы понятия, используемые в последней: общезначимость, выводимость и др. В частности формулы +¬w ⊃ ¬◊w, +w ≡ w +общезначимы. +Формула +(w1 ⊃ w2) ⊃ (w1 ⊃ w2) +также общезначима. +Это означает (на основе правила модус поненс), что истинность формулы (w1 ⊃ w2) всегда влечет истинность формулы  w1 ⊃  w2. + +\subsection{Модальные исчисления} +(08-13) +Задавая различные ограничения на отношение достижимости R, можно получать различные модальные исчисления, не переходя к моделям среды. +Полагаем, что отношение R всегда рефлексивно и транзитивно ( sRs ,(s1Rs2 ∧ s2Rs3) ⊃ s1Rs3 )). Вследствие этого общезначимы все следующие формулы: + w ⊃ w +◊◊w ⊃ ◊w +Это означает, что рассматриваемая нами линейная временная модальная логика имеет дело с последовательностями состояний s0, s1,..., причем sj достижимо из si, если и только, если i ≤ j, а s0 есть единственное начальное состояние. + +Язык временной модальной логики использует множество базовых символов, состоящих из индивидных (объектных) переменных и констант, пропозициональных, функциональных и предикатных символов. +Множество всех символов может разбиваться на два подмножества: глобальных и локальных символов. +Глобальные символы имеют одну и ту же область интерпретации на всем универсуме. +Локальные символы разбиваются на группы, каждая из которых имеет свою, отличную от других групп область интерпретации. +Символы разбиваются также на виды. Каждому виду соответствует своя область интрпретации. +Например, для натуральных чисел используются общеупотребимые символы: +{0,1,2,3,4,5,6,7,8,9,+,-,...,≤,≥...}. + +(08-15, 16) + +\subsection{Динамические системы} + Транспортные системы + Медицинские системы + Электронный бизнес + Телефонные сети + Протоколы + Сетевые экраны + + используются методы поиска + +Имитационное моделирование +Тестирование +Дедуктивный анализ +Верификация модели + +(08-19) +Всегда, когда в некотором текущем состоянии осуществляется восприятие пакета p, над которым совершается действие !accept , то не должно быть достижимого из этого состояния другого состояния, в которое процесс переходит в результате восприятия того же пакета p, над которым совершается действие !drop +(08-20) +Eсли в некотором текущем состоянии возможно восприятие пакета p, над которым совершается действие !accept , и в достижимом из этого состояния другом состоянии, в которое процесс переходит в результате восприятия того же пакета p , совершается действие !drop + +p1 = udp 192.168.1.1, +p2 = tcp 10.1.1.0, +p3= udp 192.168.1.1, +p4= tcp 10.1.1.26, +p5= tcp 10.1.1.64. + +\begin{lstlisting}[language=C,style=CCodeStyle] + domains + f =f(symbol, integer, integer, integer, integer, symbol ) + list = f* + + predicates + nondeterm transition(symbol, list, symbol) + nondeterm accessible(symbol, list, symbol) + clauses + transition(b1, [f(udp,192,168,1,1, accept)], b2 ). + transition(b2, [f(tcp,10,1,1,0, accept)], b3). + transition(b3, [f (udp,192,168,1,1,drop)], b4). + transition(b4, [f(tcp,10,1,1,26, accept)], b5). + transition(b5, [f(tcp,10,1,1,64, dropall)], b6). + transition(b1, [],b2). + transition(b2, [],b3). + transition(b3, [],b4). + transition(b4, [],b5). + transition(b5, [],b6). + + accessible(B1, [X], B2) :- transition(B1, [X], B2). + accessible(B1, [X|Rest], B2) :- transition(B1, X, B3), accessible(B3, Rest, B2). + goal + accessible(B1, [f(udp,X,Y,V,W, accept)], B2), accessible(B1, [f(udp,X,Y,V,W, drop)], B3), B2<>B3. +\end{lstlisting} + +в линейной временной модальной логике нет квантов. если есть разветвления (параллелизм) это логика деревьев вычислений computation tree logic). позволяет описывать множественные варианты развития событий в одном графе. + +альтернативная временная логика - это обобщение логики деревьев. поведение множества агентов подчиняется правилу, что формула гаммы всегда должна быть истинна. в этой логике можно формулировать утверждения типа «агенты множества взаимодействуют в соответствии с формулой гамма или поведение агентов удовлетворяет формуле гамма». + +\section{Прямой и обратный вывод(09)} +Какие бы рассуждения ни использовались, нужно делать выводы. +Наиболее распространенными являются следующие типы выводов: +прямой, +обратный, +комбинированный. +До сих пор при рассмотрении дедуктивно-рассуждающих агентов использовался прямой вывод. + +Начальные знания (аксиомы) помещаются в базу знаний. +Для всех целевых формул подбираются правила вывода, условия которых может быть образовано из формул, хранящихся в базе знаний с использованием, если это необходимо, унификации. +По правилам вывода получаются истинные формулы (теоремы), являющиеся унифицированным следствием правил вывода. +Если эти формулы (теоремы) совпадают с целевыми формулами, то процесс вывода завершается. +В противном случае теоремы добавляются в базу знаний и осуществляется переход к п. 2. + +Начальные знания (аксиомы) помещаются в базу знаний. +Подбираются правило вывода, следствием которого являются целевые формулы, а условие может быть образовано из формул базы знаний с использованием, если это необходимо, унификации. +Унифицированные формулы, входящие в условия правил вывода, принимаются за новые целевые формулы (обычно называемые подцелевыми формулами). +Если все подцелевые формулы оказываются истинными, то начальные целевые формулы выведены и процесс вывода завершается. +В противном случае выведенные истинные подцелевые формулы добавляются в базу знаний, подцелевые формулы, истинность которых не доказана, принимаются за новые целевые формулы и осуществляется переход к п. 2. + +\subsection{Хорновские формулы} +Хорновские формулы – это импликативные формулы, левая часть (посылка) которых является конъюнкцией атомов, а правая (заключение) является либо атомом, либо пустым символом, т.е. справа ничего нет. При унификации соблюдаются следующие ограничения: +Вместо переменной в x, y может подставляться переменная. Такая подстановка называется переименованием переменной или переименованием переменной. +Вместо переменной может подставляться константа. Такая подстановка называется конкретизацией переменной. +Вместо переменной может подставляться функция. Такая подстановка называется заменой переменной + +(09-07, 08) + +Вывод на основе использования правила модус поненс, унификации и хорновских формул использует только один тип правила. +Поэтому нет необходимости осуществлять выбор подходящего правила вывода. +Это типизирует процедуры прямого и обратного вывода, превращая их в итеративную процедуру выполнения однотипных шагов. + +(09-10, 11, 12) + +на (x,y) ∧ свободен (x) ∧ переместить(x,Стол) ⊃ на(x,Стол) +на (x,y) ∧ свободен (x) ∧ переместить(x,Стол) ⊃ свободен (y) +на (x,y) ∧ свободен (x) ∧ переместить(x,Стол) ⊃ свободен (x) + +на (x, y) ∧ свободен (x) ∧ свободен(z) ∧ переместить(x,z)⊃ на(x,z) +на (x,y) ∧ свободен (x) ∧ свободен(z) ∧ переместить(x,z)⊃ свободен (y) +на (x,y) ∧ свободен (x) ∧ свободен(z) ∧ переместить(x,z)⊃ свободен (x) +\subsection{Среда кубиков. Прямой вывод. (14-19)} +Имеем истинные формулы +на (A, C) , свободен (A) , на (х, у) ∧ свободен (х) ⊃ пeреместить (x,Стол) + +Унифицируем их +на (A, C) , свободен (A) , на (A, C) ∧ свободен (A) ⊃ пeреместить (A,Стол) + +Применяем обобщенное правило модус поненс +на (A, C) , свободен (A) ,на (A, C) ∧ свободен (A) ⊃ пeреместить (A,Стол) + пeреместить (A,Стол) +Аналогично +на (D, B) , свободен (D), на (D, B) ∧ свободен (D) ⊃ пeреместить (D,Стол) +пeреместить (D,Стол) +на (A,С) , свободен (A) , переместить(A, Стол), на (A,С) ∧ свободен (A) ∧ переместить(A, Стол)⊃ на(A, Стол) +на(A, Стол) + +на (A,С), свободен (A) , переместить(A, Стол), на (A,С)∧ свободен (A) ∧ переместить(A, Стол)⊃ свободен (С) + свободен (С) + +на (D,B) , свободен (D) , переместить(D, Стол), на (D,B) ∧ свободен (D) ∧ переместить(D, Стол)⊃ на(D, Стол) +на(D, Стол) + +на (D,B) , свободен (D) , переместить(D, Стол), на (D,B) ∧ свободен (D) ∧ переместить(D, Стол)⊃ свободен (B) +свободен (B) + +(14-20-23) +(14-24-28) + +\section{Практично-рассуждающие агенты (10)} +Практичное рассуждение – это рассуждение (вывод), направленное на действия – процесс выделения того, что надо сделать: «Практическое рассуждение является процессом взвешивания конкурирующих соображений за и против, где наиболее существенные соображения агента предоставляются в виде его желаний, ценностей, наблюдений и убеждений» (Bratman, 1990). + +Практичное рассуждение отличается о логического. Например, вывод о смертности Сократа на основе знания о том что все люди смертны, а Сократ – человек, является логическим рассуждением. Процесс же принятия решения о выборе автобуса вместо трамвая является практичным, поскольку направлен на непосредственное выполнение действия. + +Практичное рассуждение состоит из двух основных этапов: +\begin{enumerate} +\item обдумывание и взвешивание: Формирование цели, которую хотелось бы достичь; +\item достижение и окончание: формирование плана достижения цели. +\end{enumerate} + +Пример: обдумывание и взвешивание, достижение и окончание карьерных устремлений. + +Применяется принцип BDI: +\begin{itemize} +\item [] Beliefs – убеждения +\item [] Desires – желания +\item [] Intentions – намерения +\end{itemize} +Результат обдумывания и взвешивания BDI-агентов – это намерение. + +\subsection{Принципы формирования и взвешивания агентом при формировании намерения} +\begin{itemize} +\item Наличие ресурсов для реализации намерения. Если я хочу реализовать намерение $\phi$, то я должен предусмотреть необходимые ресурсы для достижения этого намерения $\phi$. +\item Отсеивание других намерений, которые являются конфликтными. Если я хочу реализовать намерение $\phi$, то я не должен иметь намерений $\psi$ таких, что $\phi$ и $\psi$ взаимно исключают друг друга. +\item Отслеживание успехов в реализации своих намерений и склонность повторять попытки их реализации в случае неудач. Если первая попытка агента реализовать намерение $\phi$ потерпела неудачу, то при тех же предпосылках, он будет делать попытку реализации намерения $\phi$ с помощью альтернативного плана. +\item Убежденность реализуемости намерений. Я убежден, что есть по крайней мере один путь реализации моего намерения. +\item Неверие, что намерения могут быть нереализуемы. Для меня неразумно (нерационально) иметь намерение $\phi$, если я убежден, что $\phi$ нереализуемо. +\item Предположение, что при определенных обстоятельствах намерения могут быть изменены. Не нормально, будучи рациональным, полагать, что я не могу изменить своих намерений. Намерения могут не сбываться. Более того, бессмысленно верить в реализацию намерения $\phi$, если я убежден, что это намерение неосуществимо. +\item Незнание всех побочных эффектов намерений. Если я верю в $\phi \supset \psi$ и верю в $\phi$, то это не означает, что я обязательно верю также в $\psi$. (Из истинности $\phi$ и $\phi \supset \psi$ не обязательно следует истинность $\psi$, т.е. modus ponens в этом случае не применим)
 + +Эта проблема известна как, побочный эффект (side effect) или комплексная сделка (package deal). Я могу верить, что поход к дантисту предполагает боль, но мое намерение пойти к дантисту не означает, что я намерен подвергаться боли. +\end{itemize} + +\subsection{Намерения и желания} +Намерения намного сильней, чем желания: +«Мое желание играть в баскетбол после обеда – это не более чем просто возможность потенциального влияния на мое поведение во второй половине дня. Оно может вступать в конфликт с моими другими желаниями до тех пор, пока какое-либо одно из них не победит. Но как только, у меня появится намерение играть после обеда в баскетбол, ситуация изменяется: я перестаю взвешивать за и против. Когда проходит обед, я перехожу к выполнению своих намерений» (Bratman, 1990). + +Достижение и окончание в ИИ больше известно как планирование. +Планировщик агента – это система, которая имеет на входе: +\begin{itemize} +\item цель, намерение или задачу, +\item текущее состояние среды (убеждения агента), +\item действия, доступные агенту. +\end{itemize} +Планирующий алгоритм вырабатывает план достижения цели. По существу, это автоматизация программирования. + +\textbf{Планирующие агенты} +С ранних 1970 ИИ-сообщество усиленно интересовалось созданием интеллектуальных агентов. Планирование – это автоматизированное программирование: создание последовательности действий, ведущих к достижению некоторой цели. В рамках символического ИИ долго предполагалось, что некоторая форма ИИ планирующей системы будет центральной для интеллектуального агента. Основываясь на ранних работах Fikes \& Nilsson (1971) было предложено множество планирующих алгоритмов и теория планирования была хорошо развита. + +Так, планировщик формирует \textit{план достижения цели} на основе трёх начальных факторов: +\begin{enumerate} +\item цель, намерение, задача +\item убеждения, соответствующие текущему состоянию среды +\item возможные действия. +\end{enumerate} + +\textbf{Пример:} +Мир блоков содержит +\begin{enumerate} +\item захват робота, +\item 3 блока (A, B и C) одинакового размера, +\item поверхность стола. +\end{enumerate} + +Предикаты: +\code{On(x, y)} кубик x лежит на кубике y +\code{OnTable(x)} кубик x лежит на столе +\code{Clear(x)} на кубике x ничего не лежит +\code{Holding(x)} захват держит кубик x + +Начальное состояние среды блоков: +\begin{verbatim} +Clear(A) +On(A, B) +OnTable(B) +OnTable(C) +\end{verbatim} + +Используем принцип замкнутости среды (closed world assumption): Все, что не объявлено истинным, ложно. Цель: $OnTable(A) \land OnTable(B) \land OnTable(C)$. + +Действия представляются на основе использования метода, развитого в планировщике STRIPS (Fikes и Nilsson, 1971). Каждое действие имеет: +\begin{itemize} +\item имя, которое может иметь аргументы, +\item список предусловий: факты, которые должны стать истинными в результате выполнения действия, +\item удаляемый список: список фактов, которые перестают быть истинными после выполнения действия, +\item добавляемый список: список фактов, которые становятся истинными после выполнения действия. +\end{itemize} + +Пример 1: действие stack совершается, когда захват робота помещает кубик x, который он держит, на кубик y. Stack(x, y) +\begin{itemize} +\item предусловие Clear(y) $\land$ Holding(x) +\item удаляемый список Clear(y) $\land$ Holding(x) +\item добавляемый список ArmEmpty $\land$ On(x, y) +\end{itemize} + +Пример 2: Действие unstack совершается, когда захват робота захватывает кубик x, который находится наверху кубика y. UnStack(x, y) +\begin{itemize} +\item предусловие On(x, y) $\land$ Clear(x) $\land$ ArmEmpty +\item удаляемый список On(x, y) $\land$ ArmEmpty +\item добавляемый список Holding(x) $\land$ Clear(y) +\end{itemize} + +Пример 3: Действие pickup совершается, когда захват робота захватывает кубик x со стола. Pickup(x) +\begin{itemize} +\item предусловие Clear(x) $\land$ OnTable(x) $\land$ ArmEmpty +\item удаляемый список OnTable(x) $\land$ ArmEmpty +\item добавляемый список Holding(x) +\end{itemize} + +Пример 4: Действие putdown совершается, когда захват робота помещает кубик x на стол. Putdown(x) +\begin{itemize} +\item предусловие Holding(x) +\item удаляемый список Holding(x) +\item добавляемый список Clear(x) $\land$ OnTable(x) $\land$ ArmEmpty +\end{itemize} + +План - это последовательность (список) действий, в которых переменные замещены константами. Представляется в виде дерева, разрастающегося от изначального состояния и схлопывающееся к конечному результату действия. В оригинале планировщик STRIPS использовал для управления построением плана стек целей. Планировщик имел базу данных и стек в который цели и подцели заносились последовательно. +\begin{enumerate} +\item Помещение цели в стек целей +\item Анализ цели Цель1, помещение в стек ее подцелей: +\item Анализ подцели Подцели1-2, и т.д. +\end{enumerate} + +\subsection{Формализация процесса поиска плана 10-24 - 27} +Множество действий $A_c = \{\alpha_1, ..., \alpha_n \}$. Описатель действия $\alpha \in A_c: \{ P_\alpha, D_\alpha, A_\alpha \}$ + +$P_\alpha$ - множество формул, задающих предусловие действия, +$D_\alpha$ - множество фактов, задающих добавляемый список. +$A_\alpha$ - множество фактов, задающих удаляемый список, + +Для простоты будем полагать, что предусловие, удаляемый и добавляемый списки содержат только атомы без связок и переменных. Задача планирования над списком действий определяется тройкой: +\[ \{ \Delta, O, \gamma \} \] + +$\Delta$ - убеждения агента о начальном состоянии среды, +$O = \{ < P_\alpha, D_\alpha, A_\alpha > | \alpha \in A_c \}$ - индексированное множество описателей действий, +$\gamma$ - множество формул, задающих целевое намерение. +Планом π является последовательность действий + +По отношению к задаче планирования план определяет последовательность из n +1 состояний среды + +где +и + +Говорят, что линейный приемлем (допустим) для задачи , если и только предусловие каждого действия выполняется в предшествующем состоянии среды, т. е. если + +План корректен для задачи , если он +приемлем, +, т.е. цель достижима в конечном состоянии среды, генерируемым планом. + + +Задача, которая должна быть решена планировщиком, может быть сформулирована следующим образом: +Имея задачу планирования $\{ \Delta, O, \gamma \}$, найти корректный план для рещшения этой задачи +Если он не найден, то объявить, что он не существует. + +Достижение и окончание представляется функцией + plan : Bel x Des x Int → Plan, +где Plan - множество корректных планов. + +\subsection{Реализация практично рассуждающего агента} +Псевдокод простейшего цикла работы практично рассуждающего агента: + while true + наблюдать за средой: воспринимать Per; + обновлять убеждения среды: believes : Bel x Per → Bel; + вырабатывать желания: desires : Bel x Int → Des; + обдумывать намерения для достижения цели: intentions : Bel x Des x Int → Int; + выводить план, соответствующий намерениям: plan : Bel x Des x Int → Plan; + выполнять план +end while +




 +Проблема: Обдумывание и достижение требуют времени, т.е. не происходят мгновенно. +Предположим, что агент начал обдумывание во время t0, достижение во время t1, и выполнение плана во время t2. Тогда время на обдумывание есть +tобд = t1 – t0, +а время на достижение есть +tдост = t2 – t1 +Обдумывание является оптимальным в том случае, если выбирается некоторое намерение наилучшее для агента (максимизирующее ожидаемую полезность) +Если агент выбирает намерение во время t1 , то оно оптимально, если t1 = t0.
До тех пор, пока tобд ничтожно мало, то риск того, что намерение уже не оптимально к тому времени, как агент остановил внимание на нем, минимален. +И это вычислительно рационально. +Обдумывание – это только половина проблемы: необходимо еще определить как реализовать намерение. + +Таким образом, агент ведет себя оптимально в следующих случаях : +Когда обдумывание и достижение занимают незначительное время. +Или когда среда гарантированно статична настолько, что за время обдумывания и достижения в ней ничего не меняется. +Или когда намерение гарантированно остается оптимальным до времени t2 (времени, когда агент находит последовательность действий для реализации намерения). + +(10-34) + +\subsection{Обдумывание} +Как агент обдумывает? +\begin{itemize} +\item начинает с попытки понять, реализация каких желаний (возможностей) ему доступна, +\item осуществляет выбор среди них и решает следовать им. +\end{itemize} + +Выбранные желания (возможности) становятся намерениями. +Функция обдумывания может быть декомпозирована на две компоненты: +генерация желаний (возможностей), когда агент порождает множество возможных альтернатив, используя функцию options, которая берет текущие убеждения и намерения и возвращает множество желаний или возможностей (desires) +фильтрация, когда агент осуществляет выбор среди альтернативных желаний (возможностей) и решает осуществить их.
Для того, чтобы осуществить выбор среди альтернативных возможностей, используется функция filter. + +(10-37) + +\subsection{Стратегии осуществления (достижения) намерений} +Следующие стратегии осуществления намерений обсуждаются в литературе, посвященной рациональным агентам: +Слепая стратегия
Агент сохраняет намерение до тех пор, пока он верит, что оно осуществимо. Слепую стратегию иногда называют фанатичным осуществлением. +Целенаправленное осуществление
 Агент сохраняет намерение до тех пор, пока он верит, что оно осуществимо и не верит, что его осуществить невозможно. +Объективное осуществление
Агент сохраняет намерение до тех пор, пока он все еще убежден в своих желаниях (возможностях). +В процессе выполнения стратегий осуществления намерений агент имеет как механизм окончания, осуществления намерений, так и механизм (means) перепланирования намерений. +Если план оказался плохим, то он может быть перепланирован. + +(10-40) + +До проверки плана не останавливаться и не сомневаться в его соответствии намерению. +При проверке плана определять его успешность, возможность осуществления и корректность. 
(Целенаправленное осуществление) + +(10-42) + +Агент пересматривает свои намерения сразу как только: +\begin{itemize} +\item он полностью выполнил план по осуществлению его текущих намерений; или +\item он верит, что он осуществил свои текущие намерения; или +\item он верит, что его текущие намерения больше недостижимы. +\end{itemize} +Все это ведет к пересмотру намерений агента. Пересмотр возможен после выполнения каждого действия. + +(10-44) + +Пересмотр намерений дорог! 
Дилемма: +агент не останавливается для пересмотра намерений слишком часто, а пытается достичь их пока не стало ясно, что они не могут быть осуществлены или когда уже нет стимулов для их осуществления; +агент, который постоянно пересматривает намерения может потратить неприемлемо много времени на осуществление намерений и имеет риск никогда их не осуществить. +Решение: внедрить явно компонент мета-уровневого управления (meta-level control ), для принятия решения о пересмотре. + +(10-46) + +\section{Представление знаний в информационных системах (11)} +Языки представления знаний, отличные от языка логики предикатов первого порядка, в основе которых лежат категории и отношения между ними, были разработаны, руководствуясь убеждением, что логика предикатов неудобна для представления знаний в системах искусственного интеллекта. Эта точка зрения была основана главным образом на когнитивных экспериментах, проведенных с людьми, и желании иметь формализмы, которые близки к представлениям в головном мозге человека. +Наиболее известными из этих формализмов, являются +\begin{itemize} +\item семантические сети, +\item фреймы, +\item концептуальные графы, +\item дескриптивные логики, +\end{itemize} +\subsection{Семантические сети} +Семантические сети берут начало в работе Quillian за 1967 год как некоторый графический формализм, основанный на использовании помеченных ориентированных графов, использующих различные виды дуг и вершин. Вершины представляют категории или объекты, а дуги отношения между ними. В последующие годы было разработано много различных семантических сетей, использующих основополагающую идею Quillian. Различные семантические сети различаются: +\begin{itemize} +\item вершинами категорий, +\item вершинами объектов, +\item дугами отношений между вершинами категорий, +\item дугами отношений между вершинами категорий и вершинами объектов, +\item дугами отношений между вершинами объектов, +\item дугами свойств категорий, +\item дугами свойств объектов. +\end{itemize} +Дуги семантических сетей задают, как правило, следующие бинарные отношения: +\begin{itemize} +\item наследования подкатегорией, вершина которой соединена дугой , направленной к вершине какой-либо категории, свойств категории. +\item несимметричные отношения между объектами, вершины которых соединены дугой, +\item несимметричные отношения между категориями, вершины которых соединены дугой, +\item свойства категорий как несимметричного отношения между категорией и свойством, в вершину которой ведет дуга от вершины категории. +\end{itemize} + +(11-06) + +Семнтическая сеть - это знания. Вывод – обход по дугам, чтобы установить наличие или отсутствие тех или иных отношений. Возможно построить семантическую сеть, указав на ней исключения. + +(11-09) + +По такому графу можно сделать вывод о принадлежности объекта какому-то множеству. Доказательство наличия свойств объектов можно осуществить через логику предикатов первого порядка. (за 2021 отсутствует слайд 11-11,5) +К достоинствам можно отнести +\begin{itemize} +\item близость структуры сети, представляющей систему знаний, семантической структуре фраз на естественном языке; +\item универсальность, достигаемая за счет выбора соответствующего набора отношений; +\item наглядность системы знаний, представленной графически; +\item соответствие современным представлениям об организации долговременной памяти человека. +\end{itemize} +Недостатки семантических сетей: +\begin{itemize} +\item Только простые отношения могут быть представлены +\item Квантификацию и интенсиональные знания трудно представить + \begin{itemize} + \item Некоторые птицы летают + \item Все птицы поют некоторые песни + \item Некоторые птицы поют все песни + \item Михаил думает, что уверенность Жени в том, что Борису понравится их новый дом, ошибочна + \end{itemize} +\item сетевая модель не дает (точнее, не содержит) ясного представления о структуре предметной области, поэтому формирование и модификация такой модели затруднительна; +\item сетевые модели представляют собой пассивные структуры, для обработки которых необходим специальный аппарат формального вывода; +\item проблема поиска решения в семантической сети сводится к задаче поиска фрагмента сети, соответствующего подсети, отражающей поставленный запрос. Это, в свою очередь, обуславливает сложность поиска решения в семантических сетях; +\item представление, использование и модификация знаний при описании систем реального уровня сложности оказывается трудоемкой процедурой, особенно при наличии множественных отношений между ее понятиями. +\end{itemize} + +\subsection{Фреймы} +Фреймы введены в 1981 год Минским (Minsky) как альтернатива логико-ориентированными подходам, которые он полагал не вполне адекватными для моделирования человеческого мышления. Фреймы используют запись знаний (данных) как совокупность записей, позволяющих представлять знания, касающиеся ситуаций и объектов, включают возможность умолчаний, множественных перспектив и аналогий. Часто фреймы и семантические сети рассматривают как одно семейство формализмов. Однако в типичных семантических сетях описание свойств ограничено примитивными атомарными свойствами, в то время как во фреймах это могут быть сложные концепты. Основная цель создания фреймов: +\begin{itemize} +\item собрать все знания, относящиеся к конкретной ситуации (например, вхождение в ресторан) в один объект, вместо того, чтобы распределять все это по различным аксиомам, +\item иными словами подобная ситуация (объект) должна быть в одном фрейме, +\item фрейм содержит слоты, совокупность которых содержит информацию об одной ситуации. +\item Более структурированы, чем семантические сети +\item Вершины заменены информационными группами +\item Фрейм – это слот и его содержимое (наполнитель) + \begin{itemize} + \item Слот – это свойство + \item Содержимое – это значение + \end{itemize} +\item Имеется возможность создавать абстрактные классы сущностей или их экземпляры (образцы) +\end{itemize} + +(11-18,19) + +Отношения на фреймах +\begin{itemize} +\item наследование подкатегорией, вершина которой соединена дугой , направленной к вершине какой-либо категории, свойств последней. +\item несимметричные отношения между объектами, вершины которых соединены дугой, +\item несимметричные отношения между категориями, вершины которых соединены дугой, +\item свойства категорий как несимметричного отношения между категорией и свойством, в вершину которой ведет дуга от вершины категории. +\end{itemize} +(11-21) +Frame: Course +MemberSlot: enrolls +ValueClass: Student +Cardinality.Min: 2 +Cardinality.Max: 30 + +MemberSlot: taught\_by +ValueClass: Professor +Cardinality.Min: 1 +Cardinality.Max: 1 + +Frame: Graduate +SuperClasses: Course +MemberSlot: enrolls +ValueClass: GradStudent +Cardinality.Max: 20 + +Frame: BasCourse +SuperClasses: Course +MemberSlot: taught\_by +ValueClass: Professor + +Frame: Student +MemberSlot: degree +ValueClass: String +Cardinality.Min: 1 +Cardinality.Max: 1 + +Frame: Undergraduate +SuperClasses: Student + +\subsection{Концептуальные графы} +Универсальный сетевой язык для представления смысла. Впервые предложены в работе Джона Сова (John Sowa), 1984. Ресурсы: http://www.jfsowa.com/cg/ или http://conceptualgraphs.org/ + +Являются развитием формализма экзистенциальных графов и графической логики (Ч. Пирс); +Обладают выразительностью естественного языка и вычислительными возможностями символической логики; +Предназначены для реализации различных сетевых способов представления семантики; + +\textbf{Концептуальный граф (conceptual graph)} — это конечный связный двудольный граф; +Используются узлы двух видов: первые представляют понятия, а вторые — концептуальные отношения (conceptual relation); +Метки дуг на графах не используются; +\begin{itemize} +\item Для отражения взаимосвязи между понятиями используются вершины, представляющие концептуальные отношения; +\item Чтобы различать вершины понятий и отношений используется графическое обозначение двух видов: прямоугольники — для вершин–понятий и эллипсы — для вершин отношений +\end{itemize} +Предложение «A cat chased mouse»: +\begin{itemize} +\item Четыре прямоугольника соответствуют концептам (понятиям): кот, преследовать, мышь и факт преследования, имеющий неявный тип «ситуация» («situation»); +\item Эллипсы соответствуют отношениям: «агент» («agent»), «объект» («object») и «время действия» («past»); +\item Последнее отношение присоединяется к графу–контексту, т.е. графу, который содержит вложенный в него подграф; +\end{itemize} +Представление концептуального графа в текстовой форме: +\begin{verbatim} +(PAST) -> [[CAT] <- (AGENT) <- [CHASE] -> (OBJECT) -> [MOUSE]] +\end{verbatim} + +В отличие от дуг, соответствующих бинарным отношениям, вершины, представляющие концептуальные отношения, могут быть связаны с любым конечным количеством вершин–понятий. Аналогично какое-либо понятие может быть связано множеством отношений. Пример: «Миша сообщил Жене новость по электронной почте». Глагол «сообщить» связан с другими понятиями с помощью четырех концептуальных отношений: «агент» («agent»), «объект» («object»), «получатель» («recipient») и «средство» («mean»). +\begin{verbatim} + [электронная почта] <- (mean) + ^ + | +[person: Миша] <- (agent) <- [сообщить] -> (object) + | | + v v + [person: Женя] <- (recipient) [новость] +\end{verbatim} + +В нотации концептуальных графов вводятся явные обозначения отношений класс–элемент, класс–подкласс. Любое понятие рассматривается как экземпляр конкретного типа. +Обозначение: Вершина «Женя» имеет тип «person». +\begin{verbatim} + | + v +[person: Женя] <- (recipient) +\end{verbatim} +Тот факт, что один тип является подклассом другого типа принято обозначать символом $\leq$: person $\leq$ homo sapiens $\leq$ being + +\textbf{Решётка (иерархия) наследования} Совокупность всех типов образует решетку множественного наследования, в которой каждый тип может иметь множество родителей и детей.Чтобы решетка типов была единой иерархией, в концептуальные графы включают два специальных типа: универсальный тип (universal type), являющийся суперклассом для всех классов, и абсурдный тип (absurd type), являющийся подклассом для всех типов. Универсальный тип принято обозначать символом $\top$, а абсурдный тип — символом $\bot$. + +\textbf{Обобщённый маркер «*»} Для обозначения любого или неспецифицированного экземпляра используется обобщенный маркер «*». Метки понятий «person: *» и «person» являются эквивалентными и указывают на произвольный объект типа person. В дополнение к обобщенному маркеру «*» допускается использование переменных, например «person: *X». Для более сложных манипуляций с неспецифицированными экземплярами классов используются лямбда выражения. Пример: «Котенок ловит лапой свой хвост». Неизвестно, о каком конкретно котенке идет речь. Переменная *X позволяет указать, что лапа и хвост принадлежат одному и тому же котенку. + +\textbf{Индексный маркер «\#»} Для указания конкретного экземпляра класса, не используя при этом имени объекта служат индексные маркеры «\#», позволяющие отделить экземпляры от своих имен. Для указания имени объекта можно использовать отношение «name». Это позволяет, с одной стороны, указать для одного объекта несколько имен, а с другой стороны — обозначать различные объекты могут одним и тем же именем. Пример: «Рыжую лошадь звали женским именем Елена». Речь идет о свойстве имени какой-то конкретной лошади «быть женским». Отношение «gender» («род») указывает на свойство имени, а отношение «color» («цвет») — на свойство конкретной лошади. + +Канонические правила формирования +\begin{itemize} +\item Копирование (copy) — позволяет получить точную копию какого—либо графа. +\item Упрощение (detach) — позволяет исключить дублирующиеся отношения. Дублирование отношений часто возникает в результате операции объединения. +\item Ограничение (restrict) — позволяет заменить вершины понятий графа другими вершинами, представляющими их специализацию, или заменить метку типа на метку подтипа. +\item Объединение (join) — позволяет интегрировать два графа в один, если одна из вершин первого графа, представляющая какое-либо понятие, идентична одной из вершин второго графа. +\end{itemize} + +Пример специализации и обобщения концептуальных графов +Два исходных предложения «Manager hired a person» («Менеджер нанял на работу человека») и «Employee hired at data (13/12/06)» («Работник принят на работу 13/12/06»). Типы концептов в данном примере образуют следующую иерархию классов «manager $\leq$ employee $\leq$ person»: тип «person» является более общим (т.е. суперклассом) по отношению к «employee» и «manager», тип «manager» является подклассом типа «employee». +\begin{verbatim} +[manager]->(agent)->[hire]->(object)-> [person] + [data] -> (at) ->[hire]->(object)->[employee] +\end{verbatim} +Оба исходных графа содержат вершину «hire». Применяя правило объединения к этим двум графам, по вершине «hire» получим новый граф: +\begin{verbatim} +[manager]->(agent)->[hire]->(object)-> [person] + > \ + [data] -> (at) / > (object)->[employee] +\end{verbatim} +На основании отношения класс–подкласс между концептами person и employee можно применить правило ограничения и заменить метку вершины «person» на метку «employee»: +\begin{verbatim} +[manager]->(agent)->[hire]->(object)->[employee] + > \ + [data] -> (at) / > (object)->[employee] +\end{verbatim} +Полученный граф содержит две вершины «employee», которые могут быть объединены в одну, т.к. указывают на один и тот же концепт. Операция упрощения позволяет устранить дублирование отношения «object» между концептами «hire» и «employee». +\begin{verbatim} +[manager]->(agent)->[hire]->(object)->[employee] + ^ + | + [data] -> (at) +\end{verbatim} +Часто возникает необходимость для определения отношений между высказываниями или высказыванием и концептом. Например, предложение «Tom believes that Marry like him» («Том верит, что он нравится Мэри») устанавливает отношение между концептом «believe» и высказыванием «Marry like Tom». В концептуальных графах вводится специальный тип высказывание (proposition), объектом ссылки которого является множество концептуальных графов (являющихся подграфами данного графа), обозначаемое прямоугольниками, содержащими подграф. + +\subsection{Структура продукции} +Термин «продукция» принадлежит американскому логику Эмилю Леону Посту. В понимании Поста в качестве продукции выступала только та ее часть, которая сейчас называется ядром (А $\to$ В, ЕСЛИ А ТО В). В общем виде под продукцией понимается выражение следующего вида: +\[(i); Q; Р; А \to В; N.\] +Здесь i - имя (идентификатор) продукции, с помощью которого данная продукция выделяется из всего множества продукций. В качестве имени может выступать некоторая лексема, отражающая суть данной продукции (например, «покупка книги» или «набор кода замка»), или порядковый номер продукции в их множестве, хранящемся в памяти системы. + +Q характеризует сферу (область) применения продукции. Разделение знаний на отдельные сферы позволяет экономить время при поиске решения задачи. Например, часть продукций описывает процесс приготовления пищи, а вторая – выбора маршрута путешествия и т. п. Основным элементом продукции является ее ядро: $А \to В$. Интерпретация ядра продукции может быть различной и зависит от того, что стоит слева и справа от знака знака $\to$. Обычное прочтение ядра продукции выглядит так: ЕСЛИ A ТО B. Более сложные конструкции ядра допускают в правой части альтернативный выбор, например, ЕСЛИ А ТО B1, ИНАЧЕ B2. Условие А называется антецедентом (условием), действие В – консенквентом (следствием). + +Если А ложно, то об истинности В ничего сказать нельзя, т.е. из лжи может следовать все, что угодно (для импликации принято, что следует истина). Возможны и другие интерпретации ядра продукции, например A описывает некоторое условие, необходимое для того, чтобы можно было совершить действие В. + +Р есть условие применимости ядра продукции. Обычно Р представляет собой логическое выражение. Когда Р принимает значение «истина», ядро продукции активизируется. Если Р ложно, то ядро продукции не может быть использовано. Например, если в продукции «НАЛИЧИЕ ДЕНЕГ; ЕСЛИ ХОЧЕШЬ КУПИТЬ ВЕЩЬ X, ТО ЗАПЛАТИ В КАССУ ЕЕ СТОИМОСТЬ И ОТДАЙ ЧЕК ПРОДАВЦУ» условие применимости ядра продукции ложно, т.е. денег нет, то применить ядро продукции невозможно. + +N описывает постусловия продукции. Они активизируются только в том случае, если ядро продукции реализовалось. Постусловия продукции описывают действия и процедуры, которые необходимо выполнить после реализации В. Например, после покупки некоторой вещи в магазине необходимо в описи товаров, имеющихся в этом магазине, уменьшить количество вещей такого типа на единицу. Выполнение N может происходить не сразу после реализации ядра продукции. + +Прямой вывод называется также выводом, управляемым данными, или нисходящим. В таких системах поиск идет от исходных данных (фактов) к заключениям. T.е. проверяются условия А, включающие известные факты, и активизируются те продукции, для которых А истинно. После этого в рабочую память заносятся промежуточные заключения В’, которые в дальнейшем выступают как дополнительные факты для А’ и так до тех пор, пока не будет получено итоговое заключение В. Обратный вывод называется также выводом, управляемым целями, или восходящим. В таких системах выдвигается некоторая гипотеза В, а затем идет поиск промежуточных фактов A’, подтверждающих эту гипотезу. После этого в рабочую память заносятся промежуточные факты А’, которые в дальнейшем выступают как промежуточные гипотезы (заключения) В’. Если принятая гипотеза В приводит к известным фактам А, то она считается итоговым заключением. +Существуют также системы с двунаправленными выводами. + +(11-43, 44, 45, 46, 47) + +За +\begin{itemize} +\item Естественность и прозрачность +\item Легкость постановки задачи +\item Модульность +\item Легкость внесения изменений +\end{itemize} +Против +\begin{itemize} +\item Нет возможности представлять отношения между модулями знаний +\item Представление знаний иногда слишком громоздкое +\item Жесткий синтаксис +\end{itemize} + +Достоинства +\begin{enumerate} +\item Подавляющая часть человеческих знаний может быть записана в виде продукций. +\item Простота создания и понимания отдельных правил. +\item Простота пополнения и модификации базы знаний (набора продукций). +\item Простота механизма логического вывода. +\item Разбиение системы продукций на сферы (декомпозиция) позволяет эффективно использовать ресурсы и сократить время поиска решения. +\item Возможность реализации немонотонного логического вывода и обработки противоречивых фактов. +\item Возможность параллельной и асинхронной обработки правил. +\end{enumerate} + +Недостатки +\begin{enumerate} +\item Отсутствует теоретическое обоснование построения продукционных систем. В основном при их построении используются эвристические приемы. +\item Следствие из недостатка 1. При большом числе продукций процедура проверки непротиворечивости правил и корректности работы системы становится крайне сложной. Именно поэтому число продукций, с которыми работают реальные информационные системы, не превышает тысячи. +\item Следствие из недостатка 2. Возможность легкого внесения серьезных искажений в базу знаний, приводящих к неправильному функционированию системы (если в системе нет развитых средств проверки целостности базы знаний). +\end{enumerate} + + +\newpage +\section{Языки опиисаний онтологий(+12)} +OWL - ontology web language «Онтология – это спецификация концептуализации» (Tom Gruber, Stanford). Абстракция – это упрощенный взгляд на мир, выраженный в соответствующем формальном языке с хорошо определенной семантикой. Общая онтология для множества агентов позволяет им взаимодействовать в определенной области знаний без необходимости выходить на уровень глобальной теории. Описан W3C, хотя первые попытки были произведены DARPA. подразделяется на несколько диалектов OWL full, OWL DL обеспечивает полноту, но использование ограничено, отражает связь с дескриптивной логикой, OWL Lite - наименьшие дескриптивные способности, но может быть промежуточным звеном при переходе к онтологиям. + +Слабой стороной является то, что нельзя однозначно избежать добавления противоречивых сведений в онтологию. ОВЛ это прототип объектно-ориентированного программирования, представляет классы и свойства как ХМЛ. Для удобства и выразительности описания моделей сред часто вводятся особые, заранее предопределенные, непересекающиеся ни с какими другими категории объектов. Чаще всего объекты этих категорий являются вымышленными. Обычно эти особые категории объектов называются сортовыми категориями или сортами. + +В определённом контексте класс может выступать в роли экземпляра. + +База знаний состоит из конструкторов для построения сложных концептов, ролей из атомарных концептов и ролей. +Tbox: вводит используемую терминологию (terminology), т.е. словарь заданной области знаний. Словарь состоит из концептов, обозначающих множества индивидов, и ролей, обозначающих бинарные отношения между индивидами +Abox: содержит высказывания (assertions) в терминах введенного в Tbox словаря. Дескриптивная логика имеет модельно-теоретическую семантику. + +Основная идея модельно-теоретической семантики состоит в том, что смысл различных частей утверждения задается интерпретацией I на модели M, состоящей из множества объектов или индивидов. +Так, интерпретация логики предикатов первого порядка задаётся отображением термов в множества объектов или индивидов, а предикатов - в истинностные значения «истина» и «ложь». + +\subsection{Конструкторы} +Атомарный концепт P – это множество всех объектов x, которые обладают свойством P (на которых одноместный предикат P(x) истинен) +Концептуальная конъюнкция P ⨅ Q – это множество всех пар объектов x, y , удовлетворяющих свойствам P и Q. +Концептуальная дизъюнкция P ⨆ Q – это множество всех пар объектов x, y , удовлетворяющих свойствам P или Q. +Концептуальное отрицание ¬P - это множество всех объектов х, которые не обладают свойством P (на которых предикат P(x) ложен). +Атомарная роль R.Q – это множество всех объектов x множества Q которые обладают свойством R (выполняют роль R , т.е. на которых двуместный предикат R(x,Q) истинен). +Экзистенциональная квантификация атомарной роли ∃R.Q –подмножество объектов мощностью не менее 1 из числа тех, кто выполняет роль R и принадлежит множеству Q . +Пример: ∃имеетДетей.Женщины - подмножество женщин из числа тех, что имеют детей и принадлежат множеству Женщины . +Количественно ограничивающая квантификация атомарной роли ∀R.Q - множество всех объектов, принадлежащих множеству Q и выполняющих роль R. +Пример: ∀ имеетДетей.Женщины - множество всех женщин множества Женщины, имеющих детей. + +Определение концептов в Tbox с помощью конструкторов +Женщина ≡ Личность ⨅ Женский пол +допускается только одно определение концепта, определения ацикличны (не могут определять сами себя непосредственно или опосредованно). +Женский пол, Мужской пол, Личность, Женщина - атомарные концепты. +Личность ⨅ ¬ Женский пол - те, кто не женского пола +Женский пол ⨆ Мужской пол - те, кто женского или мужского пола + +∀имеетДетей .Люди ⨅ ∃имеетДетей.Женщины из всех людей категории Люди , имеющих детей, существует по крайней мере один человек, являющийся женщиной. +(≥3имеетДетей) ⨅ (≤ 2имеетДочерей) из трех и более имеющих детей не менее двух имеет дочерей +Женщины ⨅ ≤ 2(имеетДетей ⨅ имеетДочерей) - все женщины, имеющие не более двух детей, имеют самое большее двух дочерей + +Далее вводится содержимое ABox. +это интерпретация обычной информации, например, предложений в понятиях ТБоксов. +(12-16) +Базовый принцип вывода в дескриптивной логике – это категоризация, записываемая как + С ⊑ D +Категоризация основана на проверке принадлежности категории C (видовая категория) к категории D (родовая категория). +Пример, +Женщина ⊑ Мать + +Другой принцип при выводе – выполнимость, т.е. проверка того, что концептуальное выражение не описывает пустой концепт. + +Фактически концептуальная выполнимость- это специальный случай категоризации, означающей проверку того, что родовой концепт не пуст. +\subsection{Стратегии вывода} +Несмотря на наличие модельно-теоретической семантики для DL, долгое время вывод основывался на графовом представлении концептуальных выражений в виде семантических сетей, где концепты – это вершины графа, а дуги - это роли. +Идея категоризации сводилась к трансформации двух входных концептов в помеченный граф и проверке встраиваемости его в граф концептуальных выражений (структурная категоризация). +Такая стратегия вывода оказалась значимой, но неполной. В терминах семантики это означает, что при ответе «да» все корректно, а ответ «нет» может быть некорректным. +Иными словами структурная категоризация оказалась слабей модельно-теоретической категоризации ЛППП. +От структурной категоризации отказались, была развита полная стратегия категоризации (табло метод), базирующаяся на модельно-теоретической категоризации DL как подмножества ЛППП. (Schmidt-Schauß and Smolka [1991]) +В статье “The Tractability of Subsumption in Frame-Based Description Languages” Brachman and Levesque [1984] обратили внимание на связь между выразительностью и сложностью вывода в языке. +Они показали, что для языка, включающего пересечение концептов, простую форму экзистенциональной квантификации, количественно ограничивающую квантификацию, можно построить вывод полиноминальной сложности, в то время как добавление ролевых ограничений делает вывод NP-полным. +Позднее этот вопрос зависимости сложности от выразительности был досконально изучен. + +\subsection{табло метод} +Результат истинный если не выводима ложность. +Вершины дерева называются секвентами. +Само дерево секвентов называется табло. +Ветвь дерева (табло) называется закрытой, если в этой ветви в левой части секвента формула истинна, в правой части секвента эта же формула ложна. +Ветвь дерева (табло) называется открытой, если в секвенте этой ветви слева появляется истинная формула, а справа – ложная, эти формулы различны, и при этих значениях формул вся левая часть секвента часть истинна, а правая - ложна. +В последнем случае открытой ветви конечный секвент представляет контр пример. + +(12-21) +p ∧ (q ∨ r) ⊨ (p ∧ q) ∨ r. Предполагаем, что при истинной формуле p ∧ (q ∨ r) формула (p ∧ q) ∨ r является ложной. + +Истинность конъюнкции p ∧ (q ∨ r) в левой части означает истинность p и (q ∨ r) + + +Ложность дизъюнкции (p ∧ q ) ∨ r в правой части означает ложность (p ∧ q ) и r + + +Истинность p и (q ∨ r) в левой части означает истинность p и q или p и r в левой части. Из истинности формулы r в левой части не может следовать ложность r в правой части, т.е. из истинности p и r не выводима ложность (p ∧ q ) и r. Это записываем как p, r • p ∧ q, r и прекращаем соответствующую ветвь дерева + +Ложность формул (p ∧ q ) и r в правой части означает ложность формул p и r, а также q и r. Из истинности формулы p в левой части не может следовать ложность p, а из истинности формулы r в левой части не может следовать ложность r в правой части. Таким образом, имеем p, q • p , r ; p, q • q, r . Все ветви дерева завершились противоречиями. Следовательно наше предположение о ложности формулы ошибочно и p ∧ (q ∨ r) ⊨ (p ∧ q) ∨ r + +(12-23) Ветвь с конечным секвентом r ⨀ p открыта и представляет контр-пример, поскольку при истинности r и ложности p имеем контр-пример +Для ((p ∧ q) ∨ r) ⊨ (p ∧ (q ∨ r)), + поскольку +формула (p ∧ q) ∨ r истинна при истинной r, а +формула p ∧ (q ∨ r) ложна при ложной p. + +\section{Основы $\pi$ исчислений(13)} +\subsection{История формализации исчислений} +Исследования в области формализации вычислений были начаты в 20-х годах американскими математиками (машина Тьюринга, $\lambda$-исчисление, принцип фон Неймана построения ЭВМ, $\lambda$-исчисление Алонзо Черча). + +$\lambda$-исчисление базируется на так называемой денотационной семантике, пытаясь аналитически описать сами исследуемые функции. Такая семантика более характерна для функционального подхода к программированию. Изначально $\lambda$-исчисление создавалось Черчем для формализации понятия алгоритма и исследования предложенных им же частично-рекурсивных функций. + +\[\lambda m.n\] +Означает функцию m с параметрами n. + +Хорошо известен тезис Черча, в котором утверждается, что любая вычислимая функция эквивалентна некоторой частично-рекурсивной функции. Черч обнаружил некоторые проблемы с применением $\lambda$-исчисления и практически перестал им заниматься. + +Через несколько десятков лет обнаружилось, что несмотря на некоторые внутренние проблемы, $\lambda$-исчисление может быть достаточно успешно использовано для вычисления на компьютере описываемых им же функций. Была создана парадигма функционального программирования и язык программирования LISP. Было возобновлено исследование свойств $\lambda$-исчисления, которое помогло ответить на многие вопросы, связанные с практическим программированием. + +В середине 70-х годов в Кембридже были начаты исследования вопроса о возможности применения $\lambda$-исчисления для описания взаимодействующих процессов. Вопросом описания взаимодействующих процессов стали заниматься многие английские ученые, и к началу 80-х годов появились три теории, претендовавшие на то, чтобы называться "алгеброй процессов”: + +\begin{itemize} +\item Communicating Sequential Processes (CSP), разработанная Хоаром, +\item Algebra of Communicating Processes (ACP), предложенная Бергстра и Клоппом (которые и предложили термин "алгебра процессов"), +\item Calculus of Communicating Systems (CCS), предложенная Милнером. +\end{itemize} + +В данной лекции представляем основы $\pi$-исчисления - формальной теории, являющейся расширением алгебры CCS и основанных на работах Милнера. Данный подход аналогичен в своей методологии $\lambda$-исчислению и может быть успешно применен для описания и более глубокого понимания параллельных процессов + +\subsection{Процессы и каналы} +Имеем два процесса $P$ и $Q$. Процесс $Q$ принимает данные от процесса $P$ по каналу $x$, соединяющему процессы $P$ и $Q$. Канал может быть входным $x$ и выходным $\bar{x}$. Процесс $P$ имеет выходной канал $\bar{x}$ и готов передать данные с именем $z$ по выходному каналу с именем: +\[P \equiv \bar{x}z.P'\] + +Процесс $Q$ имеет входной канал $x$ готов принять данные c именем $y$ по входному каналу с именем $x$: +\[Q \equiv x(y).Q'\] + +Если процесс $Q$ готов передавать данные с именем $w$ по выходному каналу $y$ какому-либо процессу +\[R \equiv y(z).R'\] + +по его входному каналу $y$, но этот входной канал не соединен с выходным каналом $\bar{y}$ процесса $Q$, то имя входного канала $y$ может быть передано процессу $Q$ каким либо процессом $P$ по каналу $x$, чтобы осуществить это соединение. Возможность такой передачи записывается следующим образом +\[Q \equiv x(z).\bar{z}w.Q'\] + +Передачу процессу $Q$ имени канала $y$ на место канала $z$ может осуществить любой процесс $P$, имеющий выходной канал $x$. Передача процессу $Q$ имени входного канала $y$ процесса $R$ процессом $P$, имеющим выходной канал $x$, записывается следующим образом +\[(vx)(P|Q|R) \equiv (vx)(\bar{x}y.P'|x(z).\bar{z}w.Q'|y(z).R')\] + +Здесь запись $P|Q|R$ означает, что процессы $P$, $Q$, $R$ выполняются параллельно, а запись $(vx)(P|Q|R)$ означает, что канал $x$ может использоваться только процессами $P$, $Q$, $R$. + +\subsection{Редукция при передаче имени канала} +Процесс передачи имени канала моделируются с помощью редукции выражения +\[(vx)(P|Q|R) \equiv (vx)(\bar{x}y.P'|x(z).\bar{z}w.Q'|y(z).R')\] +\def\svgwidth{100mm} +\input{pics/02-iskr-00-red1.pdf_tex} + + +Редукция - это процесс преобразования выражения с помощью применения правил вывода. Рассмотрим редукцию указанного выше выражения. Вначале происходит передача по каналу $х$ имени канала $y$, получается +\[(vx)(\bar{x}y.P'|x(z).\bar{z}w.Q'|y(z).R') \to (vx)(P'|\bar{y}w.Q'|y(z).R')\] +\def\svgwidth{100mm} +\input{pics/02-iskr-00-red2.pdf_tex} + +В процессе $Q'$ все вхождения $z$ заменяются на $y$, а затем происходит передача $w$ по каналу $у$: +\[(vx)(P'|\bar{y}w.Q'|y(z).R') \to (vx)(P'|Q'|R')\] +\def\svgwidth{100mm} +\input{pics/02-iskr-00-red3.pdf_tex} + +и в $R'$ все вхождения $z$ заменяются на $w$. Целью редукции является приведение процесса к форме, в которой редукция более невозможна. + +(10) + +(11) +Процесс передачи процессом $P$ процессу $Q$ имени, например процесса $R$ моделируется с помощью редукции выражения +\[(vx)(P|Q) \equiv (vx)(\bar{x}R.P'|x(z).Q)\] + +Вначале происходит передача по каналу $х$ имени процесса $R$: +\[(vx)(P|Q) \equiv (vx)(\bar{x}R.P'|x(z).Q) \to (vx)(P'|x(R).Q)\] + +В процесс $Q'$ добавляется имя $R$: +\[(vx)(P'|x(R).Q) \to (vx)(P'|Q')\] + +\subsection{Процессы} + (12) + Определим теперь $\pi$-исчисление более формально. +π-исчисление включает 2 множества имен: +Множество имен переменных +N = {х, у,...} +(строчные латинские символы с индексами или без индексов); +Множество имен процессов +K = {Р, Q,...} +(прописные латинские символы с индексами или без индексов). + +(13) +$P::=0$ пустой процесс (окончание исчисления) +$\nu z P$ значит процесс $P$ может использовать переменную $z$ + +0 - пустой процесс, не выполняет никаких действий. +Р + Q - сумма процессов, представляет два процесса Р и Q, из которых выполняется всегда только один. +Выполнение только одного из них регулируется префиксом (см. ниже). + +\subsection{Префикс $\pi$.P} +(15) +P –процесс. +π - один из префиксов, означающих следующее: + - процесс P готов осуществить вывод значения х в выходной канал . +у(х) - процесс P готов осуществить чтение значения x из канала у и замену всех вхождений переменной х в процессе Р на считанное значение x. +τ - процесс P готов к выполнению без взаимодействия с внешним миром. Внутри Р взаимодействия могут происходить. + +(16) +Композиция, репликация, ограничение, сравнение +P ⎜Q, - композиция Р и Q. Композиция означает, что процессы Р и Q выполняются параллельно. +!Р - репликация. Репликация означает повторение выполнения процесса Р любое количество раз. +(νх)Р или (νх)Р – ограничение. Ограничение означает, что только процесс Р может взаимодействовать с внешним миром по каналу х. +ϕР – сравнение. Сравнение означает, что при истинности равенства ϕ выполняется процесс Р, в противном случае выполняется пустой процесс 0. + +(17) + P(x1,x2,... ,хп) - параметризация. + Параметризация означает, что процесс имеет параметры x1,x2,... ,хп, являющиеся именами портов или переменных, которые при использовании процесса могут инстанциироваться (конкретизироваться), т.е. вместо имен параметров x1,x2,... ,хп,, при использовании процесса P подставляются имена параметров y1,y2,... ,yп. +Параметризация процесса используется также при задании его в виде уравнения +P(x1,x2,... ,хп) <определение процесса> + +(18) Правила помеченных переходов +Каждое процессное выражение, может переходить(преобразовываться) в другое процессное выражение с помощью следующих правил перехода (преобразования). + +(19) + +MISM1: Если в процессном выражении существует переход т.е. P def= α.P’+M и [|ϕ|]=true, + где [*ϕ*]=true означает истинность формулы ϕ после подстановки констант в ее левую и правую части (равенство левой константы правой константе), то ϕPQ α → P’ + +MISM2: Если в процессном выражении существует переход, т.е. + Q def= α.Q’+N и [|ϕ|]=false, + где [|ϕ|]=false означает ложность формулы ϕ после подстановки констант в ее левую и правую части (неравенство левой константы правой константе), то ϕPQ α → Q’ + +(20-27) + +\section{Спецификация в языке $\pi$-исчисления и проверка ее корректности (14)} + + +\appendix +\setcounter{secnumdepth}{0} +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Alph{subsection}} + +\subsection{Семинар 1 (2022-02-15)} +Аспекты логического программирования на примере решения прикладных задач. Можно заменить на машинное обучение (взять нейросеть, обучить, и будем получать близкие к человеческим решениям). Но в этом случае мы не получим обоснование решения. Машины логического вывода предоставляют не только решение, но и обоснование (путь, принятные промежуточные решения), по которому это решение было получено. + +Программа на языке Prolog - это обычный текст (например, законов) формализованный в виде правил. Исходные данные (например, совершённое преступление) формализуются в виде фактов, программе задаётся теорема (вопрос виновен или нет). Программа строит дерево логического вывода, позволяющее проследить путь от начальных фактов до финального решения. Все выводы язык делает на основе строгой логики. + +Языки программирования делятся на: +\begin{multicols}{2} + \textbf{процедурные} - описание алгоритма по шагам. C++, Python, Java, JS, Assembler, C\#. Незначительно отличаются друг от друга, являются языками общего назначения, в принципе на любом можно решить любую задачу. Некоторые являются мультипарадигменными, то есть включают в себя декларативные возможности, но работают не так эффективно в части решения задач декларативного програмирования. + + \columnbreak + + \textbf{декларативные} - описание требований, предъявляемых к решению, сам алгоритм не описывается. Их может быть даже больше, чем процедурных, но все узкоспециальные. Впрочем, б\'{о}льшая часть из них являются расширениями или плагинами к Prolog. +\end{multicols} + +Примеры декларативных языков: +\begin{itemize} + \item Prolog (общий, широкопрофильный язык), + \item AgentSpeak (для мультиагентных систем), + \item PDDL (planning domain definition language, фактически для решения квестов, есть предикаты для действий, условий, итд), + \item CLP (constraint logic programming, расширение пролога для комбинаторного перебора), + \item CHR (constraint handling rules, используя правила машина вывода пытается добавить новые правила на основе введённых, логистика, расписания, синтаксический разбор текстов), + \item OWL (создание онтологий), + \item SPARQL (запросы к онтологиям). +\end{itemize} + +Декларативные языки удобны, когда мы либо вообще не знаем алгоритм решения, или он в принципе известен, но на его реализацию слишком мало времени, для прототипирования. \textbf{Prolog} - относительно широкая область применения. Будем его изучать, поскольку он является основой для изучения других декларативных языков. Будем работать с \textbf{SWI Prolog}. + +Предикат - это минимальная единица. Функция, возвращающая булево значение. Описывается в секции \code{predicates}. Предикаты несут смысловую нагрузку и при описании обязательно указываем типы принимаемых параметров. В примере (\hrf{text:sample-one}) - символические константы: человек и вид спорта. + +Аксиомы (факты и правила). Факт - это одиночный предикат с конкретными значениями, возвращающий истину. Факты заканчиваются точкой. Правила состоят из двух частей, разделённых двоеточием и минусом (\code{:-}). Правило означает, что если справа все предикаты истинны то слева тоже будет истина (логическое следование справа налево). Могут быть указаны через запятую. Правила позволяют выводить новые факты. Если параметр написан с маленькой буквы - это константа, если с большой - переменная. Аксиомы записываются в секции \code{clauses}. + +Теоремы (секция \code{goal}). Программа пытается доказать целевую формулу. Если решение удалось доказать возвращается истина, если не удалось ложь. + +Если в формуле два предиката записаны через запятую, то это логическое И. Если через точку-с-запятой, то это логическое ИЛИ. + +В языке Prolog есть возможность производить вычисления и возвращать результат как параметр предикатов (\hrf{text:sample-three}). + +\setword{\textbf{Пример №1}}{text:sample-one} +\begin{lstlisting}[language=Prolog] + predicates + likes(symbol, symbol) + clauses + likes(elen, tennis). + likes(john, football). + likes(tom, baseball). + likes(mark, tennis). + likes(mark, football). + likes(bill, Activity):-likes(tom, Activity). + goal + likes(bill, baseball). +\end{lstlisting} + +Выполнение программы всегда начинается с целевой формулы и просматриваются \textbf{clauses}. Смотрим факты. Смотрим правила. Прежде, чем использовать правило, его надо преобразовать под нашу формулу (чтобы совпадали правило и теорема). Так \code{likes(bill, Activity):-likes(tom, Activity)} преобразуется в \code{likes(bill, baseball):-likes(tom, baseball)}. + +Строится дерево: +\begin{enumerate} +\item \code{likes(bill, baseball).} +\item \code{likes(tom, baseball).} +\end{enumerate} + +Получается, что доказав правую часть мы автоматически докажем левую. Второй элемент дерева (нижний, приведённый) доказываем аналогично. И поскольку второй элемент - факт, первый оказывается доказанным. + +\setword{\textbf{Пример №2}}{text:sample-two}: задача чуть сложнее +\begin{lstlisting}[language=Prolog] + predicates + likes(symbol, symbol) + clauses + likes(elen, tennis). + likes(john, football). + likes(tom, baseball). + likes(mark, tennis). + likes(mark, football). + likes(bill, Activity):-likes(tom, Activity). + goal + likes(Person, tennis), likes(Person, football). +\end{lstlisting} + +Решение: +\begin{enumerate} +\item \code{likes(Person, tennis), likes(Person, football).} теорема + \begin{enumerate} + \item \code{likes(Person, tennis).} ищем персон с любовью к теннису + \begin{enumerate} + \item \code{likes(elen, tennis).} елена не доказуема, подставляем других, + \item \code{likes(mark, tennis).} для тенниса нашли марка, доказали теорему + \end{enumerate} + \item \code{likes(Person, football).} + \begin{enumerate} + \item \code{likes(mark, football).} марк удачно подошёл ещё и под футбол + \item \code{likes(john, football).} джона даже проверять не нужно + \end{enumerate} + \end{enumerate} +\end{enumerate} + +\setword{\textbf{Пример №3}}{text:sample-three}: функция инкрементирования числа +\begin{lstlisting}[language=Prolog] + predicates + increment(integer, integer) + clauses + increment(X, Y) :- Y is X+1. + goal + X = 1, increment(X, Y) +\end{lstlisting} +Решение будет найдено по следующему алгоритму: +\begin{enumerate} +\item число 1 присваиваем в \code{X} +\item передаём значение \code{X} в предикат как в подпрограмму +\item выполняется вычисление правой части и присваивание к \code{Y}. +\item \code{Y} возвращается и равен двум. +\item если не используем оператор \code{is} то выражение справа будет рассматриваться как строка. +\end{enumerate} + +Отсюда неверная реализация: +\begin{lstlisting}[language=Prolog] + predicates + increment(integer) + clauses + increment(X) :- Х is X+1. + goal + X = 1, increment(X) +\end{lstlisting} +По сути, мы говорим \code{1 = 2}, и ответом будет «нет решений». Все переменные подставляются один раз для каждого шага, это делается для ускорения обратимости вычислений. + +\setword{\textbf{Пример №4}}{text:sample-four}: функция минимума из двух чисел +\begin{lstlisting}[language=Prolog] + predicates + min(integer, integer, integer) + clauses + min(X, Y, Z) :- X + a. % <@\lh{dkgreen}{факт}@> +\end{lstlisting} +где вся конструкция - это \code{r} (rule), левая часть \code{h(r)} head-of-rule, правая часть \code{B(r)} body-of-rule. Порядок написания предикатов не важен, предикаты могут быть записаны с отрицанием. Предикаты без отрицания \code{B(r)+}, предикаты с отрицанием \code{B(r)-}. Если все \code{B(r)+} становятся истинными, а все \code{B(r)-} становятся ложными, то h(r) становится истинным. + +Не все правила могут быть задействованы при исчислении. Система отталкивается от программы, а не от запроса. При запуске машина пытается вывести вообще все факты, и только потом смотрит, что написано в запросе и если находит, то выводит. Если есть противоречия в правилах - программа не будет работать. + +Вводится понятие обозначения для программы. Пусть $X$ - это множество фактов, которые полагаются истинными (некоторая база знаний). Тогда $Y = T_PX$ - это множество фактов, выведенных в результате применения программы $P$ к исходному множеству фактов $X$. То есть программа генерирует новые знания на основе существующих. Программа может дать два вида результатов: +\begin{enumerate} +\item Модель программы - это множество фактов $X$, которое является замкнутым, относительно этой программы $P$. Замкнутость означает, что если применить программу ко множеству $X$, то результатом будет это самое множество. + \[X = T_PX.\] + Это даёт понимание, что факты в программе описаны полностью и непротиворечиво. +\item Устойчивая модель программы - это множество фактов $X$, которое выводится из программы $P$ в предположени о замкнутости мира. УМ не полностью совпадает с МП. + \[ T_PX = \{h(r), r\in P: B(r)^+ \subseteq X, B(r)^-\cap X = \oslash.\] + То есть некоторое множество фактов, и новый факт генерируется если все его ложные предикаты в правиле ложны, а истинные истинны. +\end{enumerate} + +Позитивная программа - это та, в правилах которой нет отрицаний. Процедура описания устойчивой модели для позитивной программы (ответа, который получается при выполнении программы): + +\begin{equation*} + \begin{gathered} + \text{Пусть:}\\ + T_PX = \{h(r), r\in P: B(r)^+ \subseteq X \} \\ + X := \oslash \\ + \text{Пока:}\\ + X \neq T_PX\\ + X := T_PX + \end{gathered} +\end{equation*} + +Стартуем от пустого множества, далее к $X$ применяем программу, в $X$ попадают факты. Проверяем, на совпадение с исходным множеством, если не совпадает - снова применяем программу. Если новых не добавилось - прогамма завершает работу. + +\textbf{Пример 1:} +\begin{equation*} + \begin{gathered} + P \begin{cases} + a.\\ + b :- a. + \end{cases}\\ + X_0 = \oslash; T_PX_0 = \{a\}; \\ + \to X_1 =\{a\}; T_PX_1 = \{a, b\}; \\ + \to X_2 = \{a, b\}; T_PX_2 = \{a, b\} + \end{gathered} +\end{equation*} +На втором шаге получена устойчивая модель. + +\textbf{Пример 2:} +\begin{equation*} + \begin{gathered} + P \begin{cases} + a.\\ + b :- a.\\ + c :- d. + \end{cases}\\ + X_0 = \oslash; T_PX_0 = \{a\}; \\ + \to X_1 =\{a\}; T_PX_1 = \{a, b\}; \\ + \to X_2 = \{a, b\}; T_PX_2 = \{a, b\} + \end{gathered} +\end{equation*} +Становится ясно, что третье правило не используется. УМ совпадает с УМ из первого примера. + +\textbf{Пример 3, рекурсия:} +\begin{equation*} + \begin{gathered} + P \begin{cases} + a.\\ + b :- a, c.\\ + c :- b. + \end{cases}\\ + X_0 = \oslash; T_PX_0 = \{a\}; \\ + \to X_1 =\{a\}; T_PX_1 = \{a\}; + \end{gathered} +\end{equation*} +Проблема рекурсии решилась, поскольку неизвестно, как вычислять b и c. + +\textbf{Пример 4, рекурсия с отрицанием:} +\begin{equation*} + \begin{gathered} + P \begin{cases} + a.\\ + b :- a, \text{not c}.\\ + c :- b. + \end{cases}\\ + X_0 = \oslash; T_PX_0 = \{a\}; \\ + \to X_1 =\{a\}; T_PX_1 = \{a, b\}; \\ + \to X_2 = \{a, b\}; T_Px_2 = \{a, b, c\}; \\ + \to X_3 = \{a, b, c\}; T_pX_3 = \{a, c\}; \\ + \to X_4 = \{a, c\}; T_PX_4 = \{a\}. \text{Программа зацикливается} + \end{gathered} +\end{equation*} + +Для программ с отрицанием мы не можем сказать, есть ли в принципе ответ. Для программ с отрицанием вводят специальный объект - редукция $P^X$ программы $P$. Относительно множества $X$ получается из программы $P$ следующими манипуляциями: +\begin{itemize} +\item [] Если $r\in P$ и $B(r)^- \cap X \neq \oslash$, то r отбрасывается; +\item [] Если $r\in P$ и $B(r)^- \cap X = \oslash$, то r включаем, но без отрицательных элементов; +\end{itemize} + +Редуцированное множество полностью положительное. Процедура отыскания УМ для программы $P$ общего вида: используется редукция и исходное предположение. Положим, что УМ - это некоторое множество фактов $Y$. +\begin{equation*} + \begin{gathered} + \text{Пусть:}\\ + T_{P^y}X = \{h(r), r \in P^y: B(r)^+ \subseteq X \}\\ + X:= \oslash\\ + \text{Пока:}\\ + X \neq T_{P^y}X \\ + X:= T_{P^y}X\\ + \text{Если}\\ + X=Y, \text{Возвращаем Y в качестве результата, иначе провал} + \end{gathered} +\end{equation*} + +\textbf{Пример исчисления с применением редуцирования:} +\begin{equation*} + \begin{gathered} + P \begin{cases} + a.\\ + b :- a, \text{not c}.\\ + c :- b. + \end{cases}\\ + Y = \oslash, X_0 = \oslash; \\ + P^y \begin{cases} + a.\\ + b:-a.\\ + c:-b. + \end{cases}\\ + T_{P^y}X_0 = \{a\} = X_1; \\ + \to T_{P^y}X_1 = \{a, b\} = X_2; \\ + \to T_{P^y}X_2 = \{a, b, c\} = X_3; \\ + \to T_{P^y}X_3 = \{a, b, c\}; \text{Не решение, истинность b подразумевает ложность c} + \end{gathered} +\end{equation*} + +Сделаем другие предположения об изначальной истинности: +\begin{equation*} + \begin{gathered} + y=\{a\} \text{Не решение}\\ + y=\{a, b, c\} \text{Не решение}\\ + y=\begin{cases} + a.\\ + c:-b. + \end{cases}\\ + X_0 = \oslash; \\ + T_PX_0 = \{a\}=X_1\\ + T_PX_1 = \{a\}\\ + y=\{a, b\} \text{Не решение}\\ + y=\{a, c\} \text{Не решение} + \end{gathered} +\end{equation*} +Нет устойчивой модели. + +\textbf{Лабораторная работа №3} +есть текст о группе людей; есть характеристики людей и действия; есть подсказки - связи между свойствами людей; нужно вычислить какие характеристики связаны с какими людьми; задача написать программу на АСП, чтобы получить такое решение. + +разбор делаем по англ тексту. по каждой характеристике используем свой цвет. по сути упрощается создание предикатов. все характеристики у всех людей разные. выделить в тексте дополнительные вспомогательные условия. бывают тонкости в части неявного указания пола, например. + +правила +\begin{enumerate} +\item факт - простой как в прологе +\item характеристики бывают числами, чтобы учитывать порядок +\item обычные правила «если-то» +\item во всех правилах надо будет назначить людям характеристики, чтобы это сделать используется выбирающее правило. позволяют для данного объекта добавить нужное кол-во фактов. =1 гарантирует, что для одного человека будет назначена только одна тема лекции и только одна. такое присвоение надо дополнительно проверять и это делается с помощью глобальных ограничений +\item глобальное ограничение - без левой части. ждут пока программа не выведет все возможные правила. пишем условия, которые запрещены в программе - это уничтожающее правило. если удалось обратить правило в истину - происходит перегенерация правил, потому что этот набор не будет решением. В наших вариантах должно быть только одно решение +\item директивы отображения результата show +\end{enumerate} + +Позволяет работать с программами с неполностью заданным условием. делаем предположение, что есть правильное решение, преобразуем к отсутствию отрицательных элементов, +Пример 1: есть программа. +\begin{equation*} + \begin{gathered} + p=\begin{cases} + p:-p.\\ + q:-not p. + \end{cases} + \end{gathered} +\end{equation*} +X - это предположение об устойчивой модели. То есть можество фактов, выводимых из программы в предположении о замкнутости мира. +$P^X$ - это позитивная программа, полученная из исходной программы с предположением X. +$Cn(P^X)$ - это множество фактов, которые удалось вывести. +Если $X = Cn(P^X)$, то X - устойчивая модель програмы P. +В ответе максимум, что может быть - это два предиката. упрощение - это убирание отрицательных компонентов + +\begin{table}[H] + \centering + \begin{tabular}{||c|c|c|c||} + \hline + $X$ & $P^X$ & $Cn(P^X)$ & Примечание \\ [0.5ex] + \hline\hline + $\oslash$ & p :- p. q. & $\{ q \}$ & не решение \\ + $\{ p \}$ & p :- p. & $\oslash$ & не решение \\ + $\{ q \}$ & p :- p. q. & $\{ q \}$ & УМ \\ + $\{ pq \}$ & p :- p & $\oslash$ & не решение \\ + \hline + \end{tabular} + \caption{Выведение устойчивой модели в примере} + \label{table:example} +\end{table} + +Пример 2: есть программа. +\begin{equation*} + \begin{gathered} + p = \begin{cases} + p:-not q.\\ + q:-not p. + \end{cases} + \end{gathered} +\end{equation*} + +\begin{table}[H] + \centering + \begin{tabular}{||c|c|c|c||} + \hline + $X$ & $P^X$ & $Cn(P^X)$ & Примечание \\ [0.5ex] + \hline\hline + $\oslash$ & p. q. & $\{ p q \}$ & не решение \\ + $\{ p \}$ & p. & $\{ p \}$ & УМ \\ + $\{ q \}$ & q. & $\{ q \}$ & УМ \\ + $\{ pq \}$ & $\oslash$ & $\oslash$ & не решение \\ + \hline + \end{tabular} + \caption{Выведение устойчивой модели в примере} + \label{table:example2} +\end{table} + +В этом примере есть косвенная рекурсия. Если проследить цикл, то он проходит через два отрицания, а двойное отрицание уничтожается. + +Пример 3. +p:- not p. +\begin{table}[h!] + \centering + \begin{tabular}{||c|c|c|c||} + \hline + $X$ & $P^X$ & $Cn(P^X)$ & Примечание \\ [0.5ex] + \hline\hline + $\oslash$ & p. & p. & не решение \\ + $\{ p \}$ & $\oslash$ & $\oslash$ & не решение \\ + \hline + \end{tabular} + \caption{Выведение устойчивой модели в примере} + \label{table:example2} +\end{table} + +В этой программе вообще нет устойчивой модели, то есть программа противоречива. + +\subsection{Семинар 4 (2022-03-29)} +Обработка переменных. +\begin{equation*} + \begin{gathered} + p = \begin{cases} + r(a, b).\\ + r(b, c).\\ + t(X,Y):- r(X, T). + \end{cases} + \end{gathered} +\end{equation*} +$T = \{a,b,c\}$ описали универсум. далее происходит подстановка (граундинг). Переменной назначается конкретное значение. То есть подставляются все возможные комбинации из универсума T. +\begin{equation*} + \begin{gathered} + p = \begin{cases} + r(a, b).\\ + r(b, c).\\ + t(a,b):- r(a, b). t(a,c):- r(a, c). t(b,c):- r(b, c).\\ + t(b,a):- r(b, a). t(c,a):- r(c, a). t(c,b):- r(c, b).\\ + t(a,a):- r(a, a). t(b,b):- r(b, b). t(c,c):- r(c, c). + \end{cases} + \end{gathered} +\end{equation*} +можно избавиться от параметров и назвать правила с подставленными значениями к простым предикатам, и вернёмся к примеру 1. Так сразобают только t(a,b) и t(b,c). для остальных не сработают правые части. УМ программы станет $\{ r(a,b), r(b,c), t(a,b), t(b,c) \}$ + +Правило является безопасным (требования безопасности нужны, чтобы возможно было выполнить граундинг) если все его переменные встречаются в позитивных предикатах в теле правила. +\begin{enumerate} +\item p(a). - безопасно +\item p(X). - есть переменная, значит небезопасно +\item p(X):- q(X). - безопасно +\item p(X):- not q(X). - небезопасно +\item p(X):- q(X), X!=a. - безопасно. +\item p(X):- t(X), not q(X). - безопасно, главное, что есть в позитивном предикате +\item p(X,Y) :- X ==Y. - явных отрицаний нет, но есть сравнение, непонятно откуда брать значения. небезопасно. +\item p(X,Y) :- t(X), q(Y), X==Y. - безопасно потому что сопоставили предикатам. +\end{enumerate} +Программа безопасна, если все правила безопасна. программа может быть выполнена, только если она безопасна. Часто можно заменить отрицания на сравнения. + +Также в ASP есть необычные правила, например, глобальные ограничения. Это запреты, которые ставятся на устойчивую модель. это правила без левой части: +\begin{enumerate} +\item \verb|:- a,b|, то есть мы хотим, чтобы не было выведено одновременно и а и б. +\item \verb|:- not c|, то есть мы хотим, чтобы обязательно было выведено с. +\end{enumerate} +Глобальные ограничения применяются после получения УМ. + +Этапы выполнения программы ASP +\begin{enumerate} +\item Подстановка переменных +\item получение УМ +\item проверка УМ на удовлетворение глобальным ограничениям +\end{enumerate} + +\subsubsection{Классическое отрицание} +у системы АСП есть специфика работы с отрицаниями в отличие от пролога. Пролог использует предположение о замкнутости мира - что не может быть выведено из программы считается ложным. запрос к программе на прологе предполагает ответы Да и Нет. В прологе можно использовать отрицания, например \verb|not a|, отрицание, как провал поиска или отрицание по умолчанию, оно выполняется, если пролог не может вывести предикат а из нашей программы. + +ASP расширяет возможности логического программирования и уходит от требования замкнутости мира. Сложно описать вообще все вохможные случаи. всегда останется неописанная часть. Программа на языке АСП может получить три варианта - Да, нет, неизвестно. это берётся за счёт поддержки двух типов отрицаний: +\begin{enumerate} +\item \verb|not a| - как провал поиска, как в прологе; +\item \verb|-a| - классическое отрицание (требует явного указания на ложность предиката или явное задание ложности предиката а); + \begin{table}[h!] + \centering + \begin{tabular}{||c|c|c||} + \hline + Удалость вывести & Не удалось вывести & Ответ программы \\ [0.5ex] + \hline + a & -a & a = истинно \\ + -a & a & a = ложно \\ + & a, -a & a неизвестно \\ + a, -a & & противоречние, нет модели \\ + \hline + \end{tabular} + \end{table} +\end{enumerate} +Классический пример - жд переезд в сельской местности без шлагбаума. его можно записать так +\begin{verbatim} +cross:- not train. %можно ехать, если нет приезжающего поезда +\end{verbatim} +такая запись означает, что мы не смогли вывести предикат трейн. если неполные знания, например, забыли посмотреть по сторонам, мы поедем через переезд. вопрос слишком ответственный, поэтому лучше записать как +\begin{verbatim} +cross:- - train. %можно ехать, если явно проверено +\end{verbatim} + +Пример2 устройство на работу. +\begin{equation*} + \begin{gathered} + p = \begin{cases} + employed(jack, stanford).\\ + employed(jane, prinston).\\ + hasIncome(X):-employed(X,Y). + \end{cases} + \end{gathered} +\end{equation*} +В вывод сразу пойдут правила, но добавятся два предиката выведенные из правила. Можно описать замкнутость мира как явное отрицание -employed(X,Y) :- not employed(X,Y). если это добавить, к УМ добавится два факта - джек не в принстоне, джей не в стенфорде. То есть мы сразу разрешаем выводить отрицания, если нет позитивного предиката. + +Пример3 поиск определения листовых вершин в ориентированном графе. +\begin{itemize} +\item terminal(X) - вершина X - терминальная, только входящие рёбра. +\item arc(X,Y) - наличие ребра между вершинами X и Y. +\end{itemize} + +\begin{verbatim} +-terminal(X) :- arc(X, Y). +terminal(X) :- not -terminal(X). % не смогли вывести ложность +\end{verbatim} + +ЛР4 CASP (constraint ASP). - CLP + ASP. работает со множествами значений переменных. не требует явной подстановки всех переменных. позволяет избавиться от этапа граундинга, спасает от комбинаторного взрыва. позволяет получить обоснование для решения. + +\subsection{Семинар 5 (2022-04-12)} +РК. +Во всех вариантах задание это текст логической программы. + +\textbf{Пример 1.} +\begin{verbatim}F +0. coffee <- +1. lemon <- tea +0. sugar <- coffee +0. milk <- coffee, sugar +2. tea <- lemon +3. tea <- diet +\end{verbatim} +дана позитивная программа. следствие справа налево. это набор предикатов. если нет правой части это факт. Нужно для этой программы найти модели и устойчивые модели. УМ получается из предположения о замкнутости мира. Получить УМ можно по правилам логического вывода пролога. Простая модель это набор фактов, которые не противоречат программе (то есть нет требований о замкнутости мира). + +Начать нужно с УМ. +\begin{enumerate} +\item Кофе - это факт. Он точно выводится из программы +\item из этого факта мы можем вывести Сахар и, соответственно, Молоко. +\end{enumerate} +УМ найдена. \code{{coffee, sugar, milk}} + +Обычные модели. их может быть несколько. она является надмножеством УМ. База программы +\begin{verbatim} +A(P) = {c, s, m, t, l, d} +Candidates: +{c s m }, +{c s m t l d}, +{c s m t l }, +{c s m t d}, -1 +{c s m t }, -1 +{c s m l d}, -2 +{c s m l }, -2 +{c s m d}, -3 +\end{verbatim} +Далее действуем методом исключения. УМ не противоречит. Проверяем по правилам. + +Логический вывод (рассуждения) на примерах подходит когда надо подбирать много комбинаций. Строим дерево рассуждений. Выбираем факт наугад, опираясь на УМ. Например, Чай +\begin{verbatim} +Чай +1 да +1.1. есть лимон +1.1.1 есть диета или нет диеты +2 нет +2.1. нет лимона нет диеты +\end{verbatim} + +\textbf{Пример 2.} +\begin{verbatim} +diet <- ~sugar +coffee <- ~tea +lemon <- tea +sugar <- coffee +milk <- coffee, sugar +tea <- lemon +tea <- diet +\end{verbatim} +Дана логическая программа с отрицаниями. нужно найти модели и УМ. Отличие в том, что может быть несколько УМ. Лучше найти все модели и из них выбрать устойчивые. +\begin{enumerate} +\item {c s m t l d}, +\end{enumerate} +\begin{verbatim} +Сахар ++ +++ предположим Ч + + Л+ + предположим Кофе + + М+ {}, {d} + - {d}, {m}, {dm} + - М+ Л- Д- +- Д+ Ч+ Л+ К-. {}, {m}, +\end{verbatim} +УМ это точно обычная модель. По ветке {s, t, l} получим 4 варианта {s, t, l}, {s, t, l, d}, {s, t, l, m}, {s, t, l, d, m}. УМ минимальна. делаем редукцию. исходная программа требует истинности сахара и чая. То есть STL не устойчивая модель, потому что мы не можем прям точно сказать о наличии сахара или чая. Если идём по ветке +С-Ч то -Чай делает фактом кофе. И получаем УМ = CSM. и по ветке С- УМ будет DTL. + +\textbf{Пример 3.} +Позитивная программа с переменными +\begin{verbatim} +next(0, 1) +next(1, 0) +even(0) +even(Y) <- next(X, Y), odd(X) +odd(Y) <- next(X, Y) even(X) +\end{verbatim} +выписываем все константы (универсум) T = {0, 1}. Составляем базу - выписываем предикаты +next/2, even/1, odd/1 +Выписываем базу программы. Берём все предикаты и подставляем туда все аргументы +\begin{verbatim} +next(0, 0), next(0, 1), next(1, 0), next(1, 1) +even(1), even(0) +odd(1), odd(0) +\end{verbatim} +Осуществляем граундинг. Факты совпали, поэтому переписываем +\begin{verbatim} +next(0, 0), next(1, 0), even(0) + +even(0) <- next(0, 0), odd(0) +even(0) <- next(1, 0), odd(1) +even(1) <- next(0, 1), odd(0) +even(1) <- next(1, 1), odd(1) + +odd(0) <- next(0, 0), even(0) +odd(0) <- next(0, 1), even(1) +odd(1) <- next(1, 0), even(0)+ +odd(1) <- next(1, 1), even(1) +\end{verbatim} +Из подставленных выводим дополнительные факты. +УМ = next(0, 0), next(1, 0), even(0), odd(1). + +\textbf{Пример 4.} +Логическая программа с переменными и отрицаниями. +\begin{verbatim} +next(0, 1) +next(1, 0) +even(Y) <- not odd(X) +odd(Y) <- next(X, Y) even(X) +\end{verbatim} +T = {0, 1}. Граундинг +\begin{verbatim} +next(0, 0), next(1, 0) +even(0) <- not odd(0) +even(1) <- not odd(1) +odd(0) <- next(0, 0), even(0) - +odd(1) <- next(0, 1), even(0) +odd(0) <- next(1, 0), even(1) +odd(1) <- next(1, 1), even(1) - +\end{verbatim} +N = {next(0, 1), next(1, 0)} +УМ = N + {even(0), odd(1)}, N + {odd(1), even(0)}. + + + +\subsection{Семинар 6 (2022-05-06)} +РК2. +дана логическая программа с отрицаниями и переменными +P= +select(X) <- element(S,X), $\neg$ nselect(X). +nselect(X) <- element(S,X), $\neg$ select(X). +<- set(S), element(S,X1),select(X1), element (S,X2), select(X2), X1 $\neq$ X2 +hit(S) <- element(S,X), select(X), +<- set(S), $\neg$ hit(S) + +I= +set(1..3) +element(1,a) +element(2,b) +element(2,c) +element(3,b) +nselect(a) + +правила без левой части это глобальные запреты + +1. построить граф общих и позитивных зависимостей и топологический порядок, +2. для полученного топологического порядка определить множество атомов для каждого правила, +3. подставить значения переменных. + +1. граф общих зависимостей. +1.1. нумеруем правила. +1.2. зависимое = предикат 1 содержится в теле 2. направленный граф с выходом из предиката. сильно связанные компоненты - это вершины такие, что можно попасть из вершины в другие, обычно двусторонние связи +1.3. выделить сильно связанные вершины +1.4. описать граф $G_p$=(P, {все рёбра через запятую}). +1.5. граф позитивных зависимостей $G_p+$. такой же граф, но рёбра - это связи без отрицаний. в нашем примере всего две связи +1.6. топологический порядок. найти сильно связанные компоненты, выстраиваем в последовательность так, чтобы если есть связи, то та из которой стрелка выходит, должна стоять раньше. в нашем примере {r1,r2},{r3},{r4},{r5}. сдвоенные связанные вершины разбиваются по графу позитивных зависимостей. $L_p$ = {r1},{r2},{r3},{r4},{r5}. +2. атомы - это проблемные предикаты. $R_{r_1}$. проблемный - это отрицательный предикат, который выводится из правила, которое находится позже в топологическом порядке, или из самого себя. т.е. при обработке следующего можно использовать всё что получено в предыдущих. р1 плохо р2 и р5 хорошо. +$R_{R_1} = {nselect(X)}. R_{r_2}=...=R_{r_5}=\oslash$ +3. подстановка переменных +нужно множество истинных и потенциально истинных фактов. начинаем с инициализации +Истинные факты F = I. +потенциально истинные факты D = I. +3.1. рассматриваем в топологическом порядке: +r1 +$s(a) <- e (1,a), \neg ns(a)$ +$s(b) <- e (2,b), \neg ns(b)$ +$s(c) <- e (2,c), \neg ns(c)$ +$s(b) <- e (3,b), \neg ns(b)$ +применяем упрощение (удаляем заведомо истинные или ложные) первое правило сокращаем потому что есть факт ns(a). есть также проблемный предикат, поэтому не вычёркиваем отрицания. элемент не выводится, поэтому это гарантированно истинные предикаты. вычёркиваем. второе полностью совпало с 4м, но это не вычёркиваем. получили по первому правилу +$s(b) <- \neg ns(b)$ +$s(c) <- \neg ns(c)$ +$s(b) <- \neg ns(b)$ +3.2. обновляем множества F и D. +могут быть выведены s(b) и s(c). F=I, D=IV{s(b), s(c)}. +3.3. шаг 2 обрабатываем правило r2 +$ns(a) <- e(1,a), \neg s(a)$ +$ns(b) <- e(2,b), \neg s(b)$ +$ns(c) <- e(2,c), \neg s(c)$ +$ns(b) <- e(3,b), \neg s(b)$ +ns(a) есть во множестве фактов, поэтому его вычёркиваем. элементы также упрощаются. +3.4. шаг3 снова обновляем множества +F=I, D=IV{s(b), s(c), ns(b), ns(c)}. +3.5. r3 +S X1 X2 +1 a a +2 b b +2 b c +2 c b +2 c c +3 b b +далее по правилу $X1 \neq X2$ остаются только +set(2), e(2,b), s(b), e(2,c), s(c) +set(2), e(2,c), s(c), e(2,b), s(b) +сеты в фактах вычеркнули всё кроме селектов. это запреты, поэтому множества не меняются +3.5. r4 +h(1) <- e (1,a), s(a) +h(2) <- e (2,b), s(b) +h(2) <- e (2,c), s(c) +h(3) <- e (3,b), s(b) +во множестве потенциальных предикатов нет s(a) поэтому зачёркиваем. остались +h(2) <- s(b) +h(2) <- s(c) +h(3) <- s(b) +F=I, D=IV{s(b), s(c), ns(b), ns(c), h(2), h(3)} +3.6. r5 +$set(1), \neg h(1)$ +$set(2), \neg h(2)$ +$set(3), \neg h(3)$ + +h(1) нет в потенциальном, поэтому вычеркнули. сеты тоже вычеркнули потому что они во множестве фактов. то что мы вычеркнули и левую и правую часть эквивалентно false<-. для нас не критично, потому что нам не надо решать программу, но это значит, что любое решение в программе будет ложно. +\subsection{Семинар 7 (2022-05-24)} +\begin{verbatim} +РК3 +другой алгоритм решения задачи первого РК. + +логическая программа с отрицанием +p= +a <- b,f b <-c, \neg e c <- a,b +a <- \neg c, \neg e b <- \neg d c <- e +d <- \neg e e <- \neg d f <- a, \neg g + +Задача: найти все УМ. +1. граф позитивных зависимостей G_+(P). это все факты в программе +G_+(P) = {a,b,c,d,e,f,g} +рисуем граф. взяли факт, рисуем стрелки от правой части в программе, если у правой части нет отрицания и рисуем направленное ребро в факт. факты без рёбер тоже рисуем. перечисляем рёбра +E=(a,c), (a,f), (b,c), (b,a), (c,b), (e,c), (f,a) +2. циклы в графе - описать все множества, формирующие циклическую связь +loops(P) = {{b,c}, {a,f}, {a,b,c}, {a,b,c,f}} +3. формулы циклов нам нужно хотя бы одно правило, запускающее цикл. Если в решении встретилось b или c то должно сработать хотя бы какое-то вспомогательное правило. перебираем по очереди циклы. если сработало хотя бы одно из вспомогательных то цикл нам интересен +LF(P) = {b \lor c -> \neg d \lor e, a \lor f -> \neg c \land \neg e, a \lor b \lor c -> (\neg c \land \neg e) \lor \neg d \lor e, a \lor b \lor c \lor f -> (\neg c \land \neg e) \lor \neg d \lor e} +4. составить вспомогательную программу ``замыкание Кларка''. включает в себя все решения из исходной программы и некоторые дополнительные условия. +выписываем все факты? прописываем тела правил через или +CF(P) = +a <-> (b \land f) \lor (\neg c \land \neg e) +b <-> (c \land \neg e) \lor \neg d +c <-> (a \land b) \lor e +d <-> \neg e +e <-> \neg d +f <-> a \land \neg g +g <-> false +если у правила нет правой части то true +5. модели для CF(P). начинать следует с коротких правил +\neg g. + e + \neg d + b c + fa \neg f \neg a + \neg e + d + bc \neg b \neg c + af af + +M(CF) = {{a,b,c,e,f}, {b,c,e}, {a,b,c,d,f}, {a,d,f}} +6. отбор УМ для исходной программы (должны удовлетворять формулам циклов). если слева в цикле ложь не надо проверять, если слева истина то справа обязательно должна истина. если одна формула цикла нарушилась - модель не подходит +SM(CF) = {{b,c,e}, {a,d,f}} +7. проверка решений для потенциальной модели из программы выкидываем все отрицания. +Y={b,c,e} -> +P^y = +a<-bf +b<- +e<- +c<-a,b +c<-e +f<-a +Cn(P^y) = {b e c}вывод совпал с исходным предположением о решении +Y={a,d,f} +P^y = +a<-b,f +a<- +d<- +b<-c +c<-a,b +c<-e +f<-a +Cn(P^y) = {a,d,f} тоже УМ + +\end{verbatim} +\end{document} + diff --git a/02-ipsm-lab-01-report.tex b/02-ipsm-lab-01-report.tex new file mode 100644 index 0000000..3ae50b5 --- /dev/null +++ b/02-ipsm-lab-01-report.tex @@ -0,0 +1,166 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +%\setcounter{secnumdepth}{0} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{1}{Имитационное моделирование архитектурных решений}{Моделирование информационных процессов и систем}{а}{Кадырбаева А.Р.} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель работы} +Целью работы является ознакомление с современными средствами имитационного моделирования архитектурных решений. + +\textit{В связи с возникшими проблемами с установкой среды, указанной в методических материалах было выдано другое задание, с применением альтернативного инструментария.} + +\subsection{Задача} +Промоделировать работу билетных касс. В кассы есть единая очередь, которую обслуживают две основные кассы. Если основные кассы не справляются с потоком покупателей, то открывается третья касса. Поток покупателей меняется в зависимости от времени суток и становится больше в выходные дни. Расписание потока покупателей приведено ниже. +\textbf{Рабочие дни:} +\begin{itemize} +\item [] 8:00–13:00 — десять человек в час; +\item [] 13:00–16:00 — пятнадцать человек в час; +\item [] 16:00–22:00 — двадцать человек в час. +\end{itemize} +\textbf{Выходные дни:} +\begin{itemize} +\item [] 9:00–12:00 — двадцать человек в час; +\item [] 12:00–21:00 — сорок человек в час. +\end{itemize} +Покупатели, время ожидания покупки у которых превысило час, уходят из касс, не купив билета. Время обслуживания одного покупателя в кассах меняется случайным образом от 2 до 15 минут и в среднем составляет 5 минут. Предусмотреть в модели учет купивших и некупивших билеты. +\subsection{Задача для самостоятельного решения} +\begin{enumerate} +\item Выявите узкие места в модели и предложите решение. +\item Творческий проект. Создайте модель массового обслуживания. Принимаются собственные инициативы. Если таковых нет, то обратитесь к преподавателю. +\end{enumerate} + +\subsection{Этапы решения} +\begin{enumerate} +\item Задание логики работы модели: + \begin{enumerate}[label=\asbuk*),ref=\asbuk*] + \item создание модели; + \item моделирование прихода покупателей; + \item моделирование очереди покупателей; + \item моделирование процесса покупки; + \item моделирование ухода покупателей из касс. + \end{enumerate} +\item Уточнение расписаний: + \begin{enumerate}[label=\asbuk*),ref=\asbuk*] + \item задание расписания прихода покупателей; + \item задание расписания работы кассиров; + \item задание расписания перерывов в работе кассиров; + \item привязка расписания покупателей; + \item привязка расписания работы кассиров; + \item привязка расписания перерывов в работе кассиров. + \end{enumerate} +\item Создание резервной кассы и ухода клиентов, чье ожидание покупки превысило час: + \begin{enumerate}[label=\asbuk*),ref=\asbuk*] + \item моделирование резервной кассы и ресурсов; + \item организация ограничения времени ожидания в кассах; + \item проверка работоспособности модели, добавление часов; + \item организация ухода покупателей, не купивших билет. + \end{enumerate} +\item Добавление динамических графиков в модель: + \begin{enumerate}[label=\asbuk*),ref=\asbuk*] + \item создание наборов данных по проданным и непроданным билетам; + \item создание круговой диаграммы по покупателям; + \item создание временн\'{о}го графика; + \item проверка работоспособности модели. + \end{enumerate} +\end{enumerate} +\section{Результаты проведенных опытов и проеланной работы} +\subsection{Создание модели} +\begin{figure}[H] + \centering + \includegraphics[width=16cm]{01-model-draft.png} + \caption{Черновик созданной модели} + \label{pic:model-draft} +\end{figure} + +В среде моделирования была создана модель билетных касс (рис. \hrf{pic:model-draft}) с указанием единиц модельного времени - минутами. Из библиотеки моделирования процессов в рабочей области были созданы: +\begin{itemize} +\item Источник заявок (Source-\code{customer}) - блок моделирует появление заявок в модели. В нашем случае покупатели — это заявки. Начальное значение интенсивности заявок было установлено в 10 заявок в час (первый параметр из задания). +\item Очередь покупателей (Queue-\code{queue}) - блок имитирует накопление заявок в модели, фактически моделирует очередь. Был отмечен пункт «Максимальная вместимость», поскольку в задании ничего не сказано об ограничениях длины очереди. +\item Выбор кассы (SelectOutput) - блок осуществляет выбор очереди, поскольку покупатель может пройти на любую из (например, двух) касс. Пусть покупатель идет во вторую кассу, увидев, что в первой кассе собралось более трех человек. Если величина, возвращенная функцией \code{size()} объекта \code{booking1}, будет больше 3, то значит, что в эту кассу покупатель не пойдет \code{booking1.size() < 4}. +\item Ресурсы для обработки заявок (ResourcePool-\code{booking\_clerk}) - блок не связывается ни с каким блоком в модели, так как через него не должны проходить заявки. Поскольку кассиры могут передвигаться от кассы к кассе, тип ресурса был задан как «Движущийся», с указанием скорости в 2 км/ч. Также было указано количество кассиров: 2. +\item Модель обслуживания (Service-\code{booking1,2}) - блок Service, который включает в себя логику работы: захват ресурсов, удержание заявки и ресурсов, освобождение ресурсов. Блокам была задана вместимость собственных очередей 2 и время задержки (задается функцией треугольного распределения со средним значением 5 минут, минимальным значением 2 минуты и максимальным значением 15 минут \code{triangular(2, 5, 15)}). В «Набор ресурсов» модели обслуживания добавлен созданный ресурс \code{booking\_clerk}. Так в первой и во второй кассах будут работать указанные в ресурсах 2 кассира. +\item Уход покупателя (Sink-\code{exit}) - блок, завершающий исполнение заявки, соединён с выходами обеих касс. +\end{itemize} +В результате запуска моделирования поведения чернового варианта модели были получены значения, показанные на рис. \hrf{pic:model-launch}. Модель с ненастроенным расписанием показывает, что в результате обслуживания 303 покупателей кассиры в среднем были заняты 57\% времени, причём вторая касса использовалась только для 14 покупателей ($4,6(2046)\%$). +\begin{figure}[H] + \centering + \includegraphics[width=16cm]{01-model-launch.png} + \caption{Черновик созданной модели} + \label{pic:model-launch} +\end{figure} +\subsection{Уточнение расписаний} +К созданной модели были добавлены следующие компоненты: +\begin{itemize} + \item Расписание прихода покупателей (\code{schedule\_customer}) - тип расписания «Интенсивность», дискретизация задана в часах, расписание составлено на неделю, поскольку в задании было сказано, что интенсивность меняется по будням и выходным дням, полное расписание представлено на рис. \hrf{pic:schedule-customer}; + \begin{figure}[H] + \centering + \begin{subfigure}[b]{0.45\textwidth} + \centering + \includegraphics[width=\textwidth]{01-schedule-customer.png} + \caption{Расписание интенсивности покупателей} + \label{pic:schedule-customer} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.45\textwidth} + \centering + \includegraphics[width=\textwidth]{01-schedule-clerks-timeout.png} + \caption{Расписание перерывов работы кассиров} + \label{pic:sched-clerk-to} + \end{subfigure} + \caption{Расписания в модели} + \label{pic:schedules} + \end{figure} + \item Расписание работы кассиров - установлено в значения 8:00 - 22:00, расписание перерывов в работе кассиров представлено на рис. \hrf{pic:sched-clerk-to}. + \item Объект \code{customer} был изменён так, чтобы прибытие осуществлялось не согласно интенсивности, а по расписанию интенсивности; + \item Объект \code{booking\_clerk} был изменён так, чтобы количество задавалось не константно, а по расписанию, также в раздел «Смены» было добавлено расписание перерывов; +\end{itemize} +\subsection{Создание резервной кассы и ухода клиентов, чье ожидание покупки превысило час} +Для моделирования резервной кассы был использован аналогичный основным кассам блок service. Время обработки было задано чуть меньше, чем в основных кассах (\code{triangular(1, 3, 15)}). К резервной кассе был привязан дополнительный ресурс \code{reserved\_clerk}. Выход резервной кассы ведёт к объекту \code{exit}. + +Согласно условиям задачи тайм-ауты в первой и второй кассе равны 30 минутам, а в третьей кассе — 20 минут. Выходы OutTimeout объектов \code{booking1} и \code{booking2} ведут на вход объекта \code{booking3}. Таким образом, покупатели, чье время ожидания в первой и второй кассах превысило 30 минут, идут в резервную кассу. Уход покупателей, не купивших билет, моделируется так же, как и уход покупателей, купивших билет, но в вхыод \code{without\_ticket}. + +\section{Анализ полученных результатов и выводы} +Для сбора данных по количеству проданных билетов во время работы модели используется объект Набор данных. Поскольку нас интересует динамика продаж билетов, то по оси Х зададим модельное время. По оси Y будем сохранять количество покупателей, прошедших через выход (\code{exit.count()}). Данные в наборе обновляются каждые три минуты. Для сбора данных по количеству потерянных билетов \code{without\_ticket.count()} (считаем минимальные потери, то есть каждый ушедший покупатель мог купить один билет). Для удобства визуализации были созданы диаграммы (графики) и круговая диаграмма продаж и упущенных покупателей. На круговой диаграмме, видно конечный результат моделирования - финальное количество купленных билетов и упущенных покупателей. + +В результате запуска модели были получены значения, представленные на рис. \hrf{pic:model-final}. +\begin{figure}[H] + \centering + \includegraphics[width=15cm]{01-model-final.png} + \caption{Результат запуска модели} + \label{pic:model-final} +\end{figure} + +Симуляция идеальных условий для проектирования системы или изменений системы, выявление «узких мест» и возможность рассмотреть разные стороны работы системы. AnyLogic позволяет сымитировать действия системы с достаточной степенью детализации и гибкости, поэтому полученные сведения могут считаться достоверными и подвергаться дальнейшему анализу. + +\section{Контрольные вопросы} +\begin{itemize} +\item \textbf{Выявите узкие места в модели и предложите решение.} + \begin{enumerate} + \item Очевидно, что система не удовлетворяет никаким реалистичным требованиям продаж, поскольку количество упущенных покупателей превышает количество проданных в $\approx 3$ раза. Одним из самых простых решений может быть открытие третьей кассы на постоянной основе. + \item Модель не учитывает, что пользователи, стоящие в общей очереди, скорее всего, не будут в ней стоять после завершения работы касс, поэтому общую очередь следует обнулять в 22:01 каждого дня. + \item Расписания, представленные на рис. \hrf{pic:schedules} в модели менять не целесообразно, поскольку рабочий день и статистика посещений касс вряд ли изменятся по желанию системного аналитика. В связи с чем необходимо изменить логику работы модели. А именно - условие перехода от одной кассы к другой. Так, если каждый покупатель будет отправляться на кассу, которая содержит меньше людей, это позволит более равномерно распределить общий поток. + \end{enumerate} +\item \textbf{Творческий проект. Создайте модель массового обслуживания.} + В индивидуальном задании реализована модель обслуживания интернет-магазина. В интернет-магазин с некоторой интенсивностью приходят заказы, несколько человек с разной скоростью могут обрабатывать заказы и отправлять их на доставку. Доставка осуществляется командой курьеров, по понятной причине, работающей медленнее, но у них больший по длительности рабочий день и скорость перемещения. В результате моделирования (рис. \hrf{pic:model-indi}) стало очевидно, что было потеряно $\approx8\%$ заказов. Также поверхностный анализ показывает, что более загруженное работой подразделение - это курьеры ($68\%$ против $21\%$ у сотрудников, обрабатывающих заказы). Более детально рассмотрев полученную статистику, можно увидеть, что отказы из-за задержек происходят в системе \textbf{только} на этапе доставки, то есть сотрудников склада целесообразно переквалифицировать в сотрудников доставки для снижения показателя потерь. + \begin{figure}[h] + \centering + \includegraphics[height=15cm, angle=90]{01-modify-final.png} + \caption{Моделирование работы интернет-магазина} + \label{pic:model-indi} + \end{figure} +\end{itemize} + +\end{document} diff --git a/02-ipsm-lab-02-report.tex b/02-ipsm-lab-02-report.tex new file mode 100644 index 0000000..13a1e76 --- /dev/null +++ b/02-ipsm-lab-02-report.tex @@ -0,0 +1,150 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +%\setcounter{secnumdepth}{0} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% номер, тема, предмет, ?а, кто +\makeReportTitle{лаботаторной}{2}{Создание и использование метамоделей}{Моделирование информационных процессов и систем}{а}{Кадырбаева А.Р.} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель работы} +Ознакомление с методами и средствами model-driven development, создания и использования метамоделей, автоматической генерации кода. +Задание: необходимо ознакомиться с основами работы с метамоделями с использованием Ecore, а также освоить применение инструментов Eclipse EMF. + +\section{Выполнение} +Для выполнения работы было установлено программное обеспечение Eclipse Modeling Tools\footnote{прямая ссылка на страницу загрузок: https://www.eclipse.org/downloads/packages/}. +\begin{enumerate} +\item Создан новый проект с именем webpage и классами, указанными на рис. \hrf{pic:first-model} + \begin{figure}[H] + \centering + \includegraphics[height=8cm]{02-frist-model.png} + \caption{Диаграмма классов с отношениями} + \label{pic:first-model} + \end{figure} +\item Для верхнего уровня модели был задан адрес артефакта \code{com.vogella.emf.webpage.model}. +\item Был сгенерирован код на языке Java для описанной модели. +\item Созданы ещё два проекта: \code{webpage.edit} и \code{webpage.editor}. На основе модели в рамках запущенного \code{Webpage.editor} были созданы демонстрационные экземпляры сущностей \code{Web} и \code{Webpage} (рис. \hrf{pic:instance-first-model}). + \begin{figure}[H] + \centering + \includegraphics[height=8cm]{02-instance-first-model} + \caption{Экземпляр приложения по модели} + \label{pic:instance-first-model} + \end{figure} +\item В методических указаниях не очевидно, какой именно проект нужно создать и в какую часть манифеста добавить зависимость, пункт пропущен. +\item Была создана переопределённая функция \code{toString();} При переопределении была отмечена особеность, что сохранить многострочное тело функции в модели недостаточно (в файле \code{genmodel} сохраняется только первая строка), необходимо добавить тело функции полностью непосредственно в свойства функции в файле \code{genmodel}. +\item Был создан тестовый метод ввода некоторого целого числа. +\item Были проработаны механизмы наследования классов. +\end{enumerate} + +\section{Индивидуальное задание} +Индивидуальным заданием к лабораторной работе было описание небольшого проекта в приложении для моделирования и создание классов на языке Java по заданному описанию. Было выбрано приложение-расширение для обмена сообщениями в информационных системах. + +Для обмена сообщениями в системе необходимо хранить: +\begin{itemize} +\item Объект сообщения; +\item Данные сообщения; +\item Тип данных сообщения; +\item Метаданные сообщения; +\item Пользователя; +\item Роль пользователя; +\end{itemize} + +В Eclipse Modeling Framework была создана модель данных, показанная на рис. \hrf{pic:indi-model} +\begin{figure}[H] + \centering + \includegraphics[width=12cm]{02-mailing.png} + \caption{Упрощённая модель данных приложения для обмена сообщениями} + \label{pic:indi-model} +\end{figure} + +Поскольку все сообщения сохраняются в БД и сразу доступны всем пользователям, то необходимо определить разделение прав доступа к сообщениям (видимость только отправителю и получателю), что сделано привязкой сообщения к пользователю. Также пользователь может начать писать сообщение, но не отправить его, удалить сообщение или отправить в корзину/избранное/папку. Для всех манипуляций с сообщением создан класс метаинформации о сообщении, содержащий флажки (булевы значения), говорящие о разных состояниях объекта сообщения. Содержание сообщения может быть разнообразным, поэтому принято решение хранить все данные в максимально простом типе: обычный массив байтов, который может быть представлен как текст, изображение, ссылка на сущность в приложении, другое сообщение, пользователя, и так далее. Пользователи в данном варианте приложения могут иметь несколько ролей: самая простая - это просто отправка и получение сообщений, модератор - пользователь, имеющий право изменять метаинформацию чужих сообщений, администратор - пользователь, имеющий право удалять чужие сообщения. Никакие пользователи не могут редактировать сообщения для сохранения достоверности. Все сообщения удаляются с применением технологии soft-delete, которая не удаляет объект из БД, а только помечает его, как удалённый. Сгенерированные структуры представлены на рис. \hrf{pic:descriptors}. + +\begin{figure}[H] + \centering + \begin{subfigure}[b]{0.4\textwidth} + \centering + \includegraphics[width=\textwidth]{02-mailing-ecore.png} + \caption{Ecore} + \label{pic:ecore} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.4\textwidth} + \centering + \includegraphics[width=\textwidth]{02-mailing-genmodel.png} + \caption{Genmodel} + \label{pic:genmodel} + \end{subfigure} + \caption{Сгенерированные файлы метамоделей} + \label{pic:descriptors} +\end{figure} + +Полные листинги сгенерированных классов представлены в приложениях \hrf{appendix:interface}, \hrf{appendix:implement}, \hrf{appendix:util}. + +\section{Контрольные вопросы} +\subsection{Можно ли установить пустую строку в качестве значения по умолчанию? Как это сделать? Как удалить пустое значение?} +Это возможно. Чтобы установить пустую строку в качестве значения по умолчанию, необходимо выполнить следующие действия: +\begin{enumerate} +\item выбрать атрибут; +\item в свойствах выбрать поле значения «Литерал значения по умолчанию»; +\item оставить значение пустым. +\end{enumerate} + +Чтобы удалить это пустое значение, необходимо нажать «Восстановить значение по умолчанию» на панели инструментов. + +\subsection{Что такое модель данных?} +Модель данных - это совокупность модели и метамодели, описывающих структуру и связи классов и объектов в приложении, составляющих абстрактное представление доступа к данным, с которым взаимодействует пользователь. + +\subsection{Какие методы генерации классов существуют? Опишите их.} +Классы на языках программирования можно описывать несколькими способами: +\begin{itemize} +\item вручную по мере описания проекта и возникновения необходимости; +\item вручную согласно заранее описанной модели системы; +\item автоматизированно приложением codegen на основе описанной модели системы; +\item автоматизированно на основе метаданных ORM или реляционной БД; +\item автоматизированно одновременно с моделью БД (liquibase); +\item автоматизированно на основе описанной модели с помощью приложений для моделирования. +\end{itemize} + +\newpage +\appendix +%\setcounter{secnumdepth}{0} +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Alph{subsection}} + +\subsection{Листинги интерфейсов} +\label{appendix:interface} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MailingFactory.java]{build/src-gen/mailing/MailingFactory.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MailingPackage.java]{build/src-gen/mailing/MailingPackage.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=Message.java]{build/src-gen/mailing/Message.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MessageContent.java]{build/src-gen/mailing/MessageContent.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MessageContentType.java]{build/src-gen/mailing/MessageContentType.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MessageMeta.java]{build/src-gen/mailing/MessageMeta.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=User.java]{build/src-gen/mailing/User.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=UserRole.java]{build/src-gen/mailing/UserRole.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=UserRolesEnum.java]{build/src-gen/mailing/UserRolesEnum.java} +\subsection{Листинги реализаций} +\label{appendix:implement} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MailingFactoryImpl.java]{build/src-gen/mailing/impl/MailingFactoryImpl.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MailingPackageImpl.java]{build/src-gen/mailing/impl/MailingPackageImpl.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MessageContentImpl.java]{build/src-gen/mailing/impl/MessageContentImpl.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MessageImpl.java]{build/src-gen/mailing/impl/MessageImpl.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MessageMetaImpl.java]{build/src-gen/mailing/impl/MessageMetaImpl.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=UserImpl.java]{build/src-gen/mailing/impl/UserImpl.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=UserRoleImpl.java]{build/src-gen/mailing/impl/UserRoleImpl.java} +\subsection{Листинги утилитарных классов} +\label{appendix:util} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MailingAdapterFactory.java]{build/src-gen/mailing/util/MailingAdapterFactory.java} +% \lstinputlisting[language=Java, style=JCodeStyle, caption=MailingSwitch.java]{build/src-gen/mailing/util/MailingSwitch.java} + +\end{document} diff --git a/02-ipsm-lab-03-report.tex b/02-ipsm-lab-03-report.tex new file mode 100644 index 0000000..b36508b --- /dev/null +++ b/02-ipsm-lab-03-report.tex @@ -0,0 +1,86 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\usepackage{tikz-uml} +\usepackage{pgfopts} +\usepackage{pgfkeys} + +\usetikzlibrary{positioning, math} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% ... работе, номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{3}{Анализ поведения систем и их компонентов}{Методы исследования и моделирования информационных процессов и систем}{а}{А.Р. Кадырбаева} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель} +Ознакомление студентов с методами и средствами анализа поведения систем и их компонентов, выраженного при помощи диаграмм UML. +\section{Задание} +В данной лабораторной работе необходимо ознакомиться с основами стандарта fUML, расширяющего возможности UML, а также освоить применение основанных на использовании этого стандарта программных средств, позволяющих производить анализ диаграмм UML. В таблице \hrf{table:task} представлено индивидуальное задание. +\begin{table}[H] + \centering + \begin{tabular}{|c|p{100mm}|p{30mm}|} + \hline + Вариант & Задание & Количество вопросов для верификации \\ [0.5ex] + \hline + 11 & Работа копирайтера. Определяем поведение состояний «Выполнение работы», «Оплата работы», «Поиск работы», «Заключение контракта», «Невозможность оплаты заказа», «Невозможность выполнения заказа» & 5 \\ [1ex] + \hline + \end{tabular} + \caption{Задание по варианту} + \label{table:task} +\end{table} +\section{Выполнение работы} +\begin{figure}[h] + \centering + \begin{tikzpicture}[yscale=-1] + \umlstateinitial[x=-4, y=-6, name=initial] + \umlbasicstate[x=-3, name=search, entry=мораль-, exit=мораль+]{Поиск работы} + \umlbasicstate[x=6, y=-3, name=failExec, entry=мораль-, exit=опыт+]{\shortstack{Невозможно\\выполнение}} + \umlbasicstate[x=-3, y=5, name=contract, exit=опыт+, entry=мораль+]{Контракт} + \umlbasicstate[x=-3, y=10, name=exec, exit=опыт+, entry=мораль+]{\shortstack{Выполнение\\работ}} + \umlbasicstate[x=6, y=10, name=pay, exit=мораль+, entry=мораль+]{Оплата работы} + \umlbasicstate[x=-3, y=15, name=failAward, exit=опыт+, entry=мораль-]{\shortstack{Невозможна\\оплата}} + + \umltrans[]{initial}{search} + \umlVHtrans[pos=1.5, arg=Недостаток компетенций]{search}{failExec} + \umlVHtrans[arg=Возврат к поиску]{failExec}{search} + \umltrans[pos=0.5, arg=Найдена работа по силам]{search}{contract} + \umltrans[pos=0.5, arg=Приступаем к работе]{contract}{exec} + \umltrans[pos=0.5, arg=Нормальный процесс]{exec}{pay} + \umlVHtrans[arm1=-30mm, pos=1, arg=Попробовать с тем же работодателем]{pay}{contract} + \umlVHtrans[arm1=-20mm, arg=Выйти на рынок]{pay}{search} + \umltrans[pos=0.5, arg=Форс-мажор]{exec}{failAward} + \umlHVHtrans[arm1=-20mm]{failAward}{search} + \umlHVHtrans[arm1=-40mm, pos=0.7, arg=Неудача]{contract}{search} + \end{tikzpicture} + \caption{Диаграмма конечного автомата по заданию} + \label{pic:fsm} +\end{figure} + +По заданию необходимо описать диаграмму состояний агента - копирайтера, осуществляющего свою трудовую деятельность. У агента, согласно задания, возможно шесть состояний: +\begin{enumerate} +\item Поиск работы - состояние, в котором агент осуществляет непосредственный просмотр вакансий; +\item Невозможно выполнение - состояние, в котором агент осуществляет повышение квалификации. В него можно попасть только в результате неудачного поиска (недостаточно компетенций), из него можно выйти только в состояние поиска работы; +\item Контракт - заключение контракта с работодателем, сюда можно попасть только после поиска работы или после успешной оплаты предыдущей работы. Выход из состояния возможен в состояние выполнения работ или если стороны не смогли договориться; +\item Выполнение работы - единственное состояние, которое возможно после заключения контракта. В общем случае, в результате выполнения работы происходит переход в состояние оплаты, а в случае возникновения форс-мажорных ситуаций в состояние невозможности оплаты; +\item Оплата работы - состояние в котором возможно оказаться только в результате выполнения работ. Из этого состояния возможно попытаться заключить с работодателем новый контракт или начать новый поиск работы; +\item Невозможна оплата - состояние, возникающее только в силу форс-мажорных ситуаций и может вести только к инициированию нового поиска работы. +\end{enumerate} + +Диаграмма конечного автомата по заданию представлена на рисунке \hrf{pic:fsm}. + +\section{Выводы} +Диаграммы конечных автоматов UML можно использовать для моделирования поведения класса, подсистемы, пакета или системы целиком. Диаграммы состояний предоставляют наглядный способ моделирования взаимодействия или коммуникации, которые происходят внутри внешних объектов и системы. Эти диаграммы используются для моделирования систем, основанных на событиях. Состояние объекта контролируется и изменяется с помощью события. Диаграммы состояний используются для описания изменения состояний объекта в прикладной системе. + +\end{document} + + + diff --git a/02-iskr-lab-01-report.tex b/02-iskr-lab-01-report.tex new file mode 100644 index 0000000..143dfa9 --- /dev/null +++ b/02-iskr-lab-01-report.tex @@ -0,0 +1,126 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\setcounter{secnumdepth}{0} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{№ 1}{Анализ данных системы видеонаблюдения в Прологе}{Представление знаний в информационных системах}{}{Лычков И.И.} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель} +Цель работы – исследовать возможности языка логического программирования Пролог для анализа ситуаций. +\section{Задание} +\textbf{Задание к лабораторной работе} - Для заданной физической среды предложить предикаты для описания положения и действий людей. + +% придумать описать предикаты +% придумать и описать факты +% можно использовать вижл пролог 5.0 или использовать онлайн отладчик SWI Prolog + +\textbf{Индивидуальное задание по варианту:} Предложить предикаты для описания поведения и действий людей на станции метро, описать их в разделе PREDICATES (придумайте не менее 10 предикатов). Создать предложения (в разделе CLAUSES) для определения: +\begin{enumerate} +\item Списка людей, задержавшихся на станции дольше указанного времени. +\item Количества людей, пребывавших на станции в указанный промежуток времени. +\item Людей, которые находились в центре зала более трёх раз. +\end{enumerate} + +\section{Выполнение работы} +Для моделирования поведения были придуманы следующие предикаты: +\begin{itemize} +\item человек зашёл на станцию +\item человек покинул станцию +\item человек прошёл центр станции +\end{itemize} + +\begin{lstlisting}[language=Prolog, frame=single] +enteredStation(ivan, 70). +enteredStation(petr, 10). +enteredStation(fedor, 15). +enteredStation(max, 15). +enteredStation(serg, 15). +enteredStation(anna, 10). +enteredStation(olga, 25). +enteredStation(irina, 50). + +leftStation(ivan, 100). +leftStation(petr, 150). +leftStation(fedor, 25). +leftStation(max, 100). +leftStation(serg, 30). +leftStation(anna, 50). +leftStation(olga, 35). +leftStation(irina, 70). + +passedCenter(max). +passedCenter(ivan). +passedCenter(petr). +passedCenter(max). +passedCenter(max). +passedCenter(anna). +passedCenter(anna). +passedCenter(olga). +passedCenter(olga). +passedCenter(olga). + +person(max). +person(ivan). +person(petr). +person(anna). +person(olga). + +passedCenter2(X,1):- passedCenter(X). + +getDelay(P,D):- + enteredStation(P,T1), + leftStation(P,T2), + D1 is T2-T1, + D < D1. + +getPersons(P,From,To):- + enteredStation(P,F), + leftStation(P,T), + F >= From, + T =< To. + +getAmount(P, From, To, A):- + findall(P, getPersons(P, From, To), Persons), + length(Persons,A). + +passedCenterMoreThan(P, X):- + person(P), + findall(Y, passedCenter2(P,Y), Persons), + sum_list(Persons,A), + A >= X. + \end{lstlisting} + + Результаты выполнения программы представлены на рис. \hrf{pic:results}. + \begin{figure}[h] + \centering + \includegraphics[width=12cm]{01rpt-result.png} + \caption{Снимок экрана с результатами выполнения программы} + \label{pic:results} + \end{figure} + + +\section{Контрольные вопросы} +Что такое предикат? +Из каких разделов состоит программа на Прологе? +Что такое факты и правила? +В чем заключается унификация и конкретизация при доказательстве целевой формулы? +Что называется решением для программы на Прологе? +Как строится дерево логического вывода при поиске решений? +Объясните механизм отката при поиске решений. +Как реализовать на Прологе подсчет количества фактов для определенного предиката? + + +\end{document} + diff --git a/02-iskr-lab-02-report.tex b/02-iskr-lab-02-report.tex new file mode 100644 index 0000000..41daa45 --- /dev/null +++ b/02-iskr-lab-02-report.tex @@ -0,0 +1,73 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\setcounter{secnumdepth}{0} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{2}{Логическое программирование в ограничениях}{Представление знаний в информационных системах}{}{Лычков И.И.} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель} +Цель работы – исследовать возможности языка логического программирования Пролог для анализа ситуаций. +\section{Задание} +11 предметов с весами [48, 30, 19, 36, 36, 27, 42, 42, 36, 24, 30] кг соответственно необходимо разложить по корзинам с ограничением по суммарному весу в одной корзине не более 100 кг. В предположении о том, что в наличии имеется достаточно корзин для размещения всех предметов, определите наименьшее количество корзин, которое удовлетворяет указанным требованиям. + +\textbf{Подсказка:} Для перебора значений количества N используемых корзин в диапазоне StartN..StopN используйте предикат \code{between(StartN, StopN, N)}. + +\textbf{Правильное решение:} Минимально нужно 4 корзины. Раскладка предметов по корзинам: +\begin{lstlisting}[language=Prolog] +[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]. +[0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0]. +[0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0]. +[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]. +\end{lstlisting} + + +\section{Выполнение работы} +Результат работы программы представлен на снимке экрана рис. \hrf{pic:result}. +\begin{lstlisting}[language=Prolog,style=CCodeStyle] +:- use_module(library(clpfd)). + +mylength(Length, List):- + length(List, Length). + +scalar(List, L):- + scalar_product(List, L, #=<, 100). + +uberSum(Column):- + sum(Column, #=, 1). + +buckets(AllBuckets) :- + Items = [48,30,19,36,36,27,42,42,36,24,30], + between(1, 11, Count), + length(AllBuckets, Count), maplist(mylength(11), AllBuckets), + maplist(scalar(Items), AllBuckets), + append(AllBuckets, V), V ins 0..1, + transpose(AllBuckets, Column), + maplist(uberSum(), Column), + label(V). + \end{lstlisting} + + \begin{figure}[h] + \centering + \includegraphics[height=4cm]{1.png} + \caption{Результат выполнения программы} + \label{pic:result} + \end{figure} + + + + + +\end{document} + diff --git a/02-iskr-lab-03-report.tex b/02-iskr-lab-03-report.tex new file mode 100644 index 0000000..f2856f6 --- /dev/null +++ b/02-iskr-lab-03-report.tex @@ -0,0 +1,196 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% ... работе, номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{№ 3}{Программирование наборов решений}{Представление знаний в информационных системах}{}{Лычков И.И.} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель работы} +Получение практических навыков разработки логических программ на языке ASP программирования наборов решений. +\section{Условие логической задачи} +\subsection{Перевод} +У Ван Ли, торговца китайским антиквариатом и артефактами, недавно был отличный месяц, когда он продал четырем покупателям со всего мира — Финляндии, Италии, Японии и Соединенных Штатов, — которые были в состоянии очень хорошо заплатить. Четыре проданных предмета представляли собой редкие нефритовые фигурки (пряжка для ремня, дракон, кузнечик и лошадь), каждая из которых была вырезана из нефрита разных цветов (темно-зеленого, светло-зеленого, красного и белого). Каждая фигурка относится к разным китайским династиям (Цзин, Мин, Сун и Тан). Сможете ли вы подобрать для каждой статуэтки свой цвет и династию, а также указать родную страну каждого покупателя? + +\begin{enumerate} +\item Редкий белый дракон (которого американка не купила) не происходил из династии Сун. +\item Изысканная пряжка для ремня (не имеющая оттенка зеленого) была создана в 618 году нашей эры для императора династии Тан. +\item Из трёх фигурок одна была куплена финном (это не дракон), одна из династии Цин (которая не досталась покупателю из Японии) и светло-зеленый предмет (который не был лошадью). +\item Американка отказалась как от кузнечика, так и от произведения династии Сун, поскольку ни один из них, по её мнению, не подходил к её домашнему декору. +\end{enumerate} + +Определить: Товар -- Цвет -- Династия -- Страна покупателя + +\subsection{Результат разбора условия задачи} +\begin{itemize} +\item \textcolor{red}{Страны}: Финляндия, Италия, Япония, Соединенные Штаты; +\item \textcolor{blue}{Цвета}: темно-зелёный, светло-зеленый, красный, белый; +\item \textcolor{teal}{Предмет}: пряжка для ремня, дракон, кузнечик, лошадь; +\item \textcolor{green}{Династии}: Цзин, Мин, Сун, Тан. +\end{itemize} +\textcolor{violet}{Фиолетовым цветом} в тексте выделены дополнительные отношения между переменными. + + +\subsection{Исходное} +Wan Li, a dealer in Chinese antiques and artifacts, had an excellent month recently when he made sales to four customers from around the world -- \textcolor{red}{Finland}, \textcolor{red}{Italy}, \textcolor{red}{Japan}, and the \textcolor{red}{United States} -- who were willing and able to pay very good prices. The \textcolor{violet}{four items} were rare jade figurines (\textcolor{teal}{a belt buckle}, \textcolor{teal}{dragon}, \textcolor{teal}{grasshopper}, and \textcolor{teal}{horse}), each carved from a \textcolor{violet}{different color} of jade (\textcolor{blue}{dark green}, \textcolor{blue}{light green}, \textcolor{blue}{red}, and \textcolor{blue}{white}). Each piece dates from a \textcolor{violet}{different Chinese dynasty} (\textcolor{green}{Ching}, \textcolor{green}{Ming}, \textcolor{green}{Sung}, and \textcolor{green}{Tang}). Can you match each figurine with its color and dynasty, and give the home country of each buyer? + +\begin{enumerate} +\item The rare \textcolor{teal}{white dragon} (which the \textcolor{red}{American} \textcolor{violet}{didn't buy}) \textcolor{violet}{didn't come from} the \textcolor{green}{Sung} dynasty. +\item The exquisite \textcolor{teal}{belt buckle} (which \textcolor{violet}{wasn't any} \textcolor{blue}{shade of green}) was created in 618 A.D. for an emperor of the \textcolor{green}{Tang} dynasty. +\item \textcolor{violet}{Three of} the figurines were the one bought by the \textcolor{red}{Finn} (which \textcolor{violet}{wasn't} the \textcolor{teal}{dragon}), the one from the \textcolor{green}{Ching} dynasty (which \textcolor{violet}{didn't go to the buyer} from \textcolor{red}{Japan}), and the \textcolor{blue}{light green} object (which \textcolor{violet}{wasn't} the \textcolor{teal}{horse}). +\item The \textcolor{red}{American} \textcolor{violet}{decided against both} the \textcolor{teal}{grasshopper} and the piece from the \textcolor{green}{Sung} dynasty, neither of which she felt would match her home decor. +\end{enumerate} + +Determine: Item -- Color -- Dynasty -- Country of buyer + +\section{Решение} +\begin{enumerate} +\item Факты: страны, фигурки, цвета и династии. +\small +\begin{verbatim} +country(finland; italy; japan; states). +item(buckle). +item(dragon). +item(grasshopper). +item(horse). +color(dkgreen; ltgreen; red; white). +dynasty(ching; ming; sung; tang). +\end{verbatim} +\normalsize +\item Генерирующие (выбирающие) правила: каждая фигурка может быть одного цвета, принадлежать какой-то одной династии и быть купленной представителем какой-то одной страны +\small +\begin{verbatim} +{check_color(I, C) : color(C)} = 1 :- item(I). +{check_dynasty(I, D) : dynasty(D)} = 1 :- item(I). +{check_country(I, C) : country(C)} = 1 :- item(I). +\end{verbatim} +\normalsize +\item Глобальные ограничения: обязательно должны выполняться требования (описанные в тексте), а также из текста следует, что нет фигурок одинакового цвета, никто не купил две фигурки, от каждого временн\'{о}го периода была представлена только одна фигурка +\small +\begin{verbatim} +:- check_color(I1, C), check_color(I2, C), I1 != I2. +:- check_dynasty(I1, D), check_dynasty(I2, D), I1 != I2. +:- check_country(I1, C), check_country(I2, C), I1 != I2. + +:- not rule1. +:- not rule2. +:- not rule3. +:- not rule4. +\end{verbatim} +\normalsize +\item Вспомогательные предикаты: поскольку правила не могут содержать одновременно и отрицание и переменную, такая логика должна быть выделена в отдельный предикат. +\small +\begin{verbatim} +ofDyn_notJapan(It, Dyn) :- + check_dynasty(It, Dyn), not check_country(It, japan). +ofDyn_notStates(It, Dyn) :- + check_dynasty(It, Dyn), not check_country(It, states). +isGrasshopper_notStates(It) :- + It == grasshopper, not check_country(It, states). +\end{verbatim} +\normalsize +\end{enumerate} + +\section{Листинг разработанной программы} +\begin{lstlisting}[language=Prolog, style=CCodeStyle] +%%writefile program.lp + +% <@\lh{dkgreen}{1. Факты}@> +country(finland; italy; japan; states). % <@\lh{dkgreen}{страны}@> +item(buckle). +item(dragon). +item(grasshopper). +item(horse). % <@\lh{dkgreen}{фигурки}@> +color(dkgreen; ltgreen; red; white). % <@\lh{dkgreen}{цвета}@> +dynasty(ching; ming; sung; tang). % <@\lh{dkgreen}{династии}@> + +% 2. <@\lh{dkgreen}{Генерирующие правила}@> +% <@\lh{dkgreen}{1 цвет у фигурки}@> +{check_color(Item, Color) : color(Color)} = 1 :- item(Item). +% <@\lh{dkgreen}{из 1 династии}@> +{check_dynasty(Item, Dynasty) : dynasty(Dynasty)} = 1 :- item(Item). +% <@\lh{dkgreen}{продано в 1 страну}@> +{check_country(Item, Country) : country(Country)} = 1 :- item(Item). + +ofDyn_notJapan(It, Dyn) :- + check_dynasty(It, Dyn), not check_country(It, japan). +ofDyn_notStates(It, Dyn) :- + check_dynasty(It, Dyn), not check_country(It, states). +isGrasshopper_notStates(It) :- + It == grasshopper, not check_country(It, states). + +% 3. Глобальные ограничения +% <@\lh{dkgreen}{у двух фигурок не может быть один цвет}@> +:- check_color(Item1, Color), check_color(Item2, Color), Item1 != Item2. +% <@\lh{dkgreen}{у двух фигурок не может быть одна династия}@> +:- check_dynasty(Item1, Dynasty), check_dynasty(Item2, Dynasty), Item1 != Item2. +% <@\lh{dkgreen}{у двух фигурок не может быть один покупатель}@> +:- check_country(Item1, Country), check_country(Item2, Country), Item1 != Item2. + +% <@\lh{dkgreen}{Редкий белый дракон (которого американец не купил)}@> +% <@\lh{dkgreen}{не происходил из династии Сун.}@> +:- not rule1. +% <@\lh{dkgreen}{Изысканная пряжка для ремня (не имеющая оттенка зеленого) была}@> +% <@\lh{dkgreen}{создана в 618 году нашей эры для императора династии Тан.}@> +:- not rule2. +% <@\lh{dkgreen}{Из трёх фигурок одна была куплена финном (это не дракон), одна из}@> +% <@\lh{dkgreen}{династии Цин (которая не досталась покупателю из Японии) и}@> +% <@\lh{dkgreen}{светло-зеленый предмет (который не был лошадью).}@> +:- not rule3. +% <@\lh{dkgreen}{Американец отказался как от кузнечика, так и от произведения}@> +% <@\lh{dkgreen}{династии Сун, поскольку ни один из них, по его мнению, не}@> +% <@\lh{dkgreen}{подходил к его домашнему декору.}@> +:- not rule4. + +% 4. <@\lh{dkgreen}{Вспомогательные правила}@> +rule1 :- check_color(dragon, white), not check_country(dragon, states), not check_dynasty(dragon, sung). +rule2 :- check_dynasty(buckle, tang), not check_color(buckle, dkgreen), not check_color(buckle, ltgreen). +rule3 :- check_country(I1, finland), I1 != dragon, ofDyn_notJapan(I2, ching), check_color(I3, ltgreen), I3 != horse, I1 != I2, I1 != I3, I2 != I3. +rule4 :- isGrasshopper_notStates(I1), ofDyn_notStates(I2, sung), I1 != I2. + + +% 5. <@\lh{dkgreen}{Указания по отображению результата}@> +info(It,Col,Dyn,Cntr) :- check_color(It,Col), check_dynasty(It,Dyn), check_country(It,Cntr). +#show info/4. +\end{lstlisting} + +\section{Результаты работы} +\begin{verbatim} +clingo version 5.2.2 +Reading from program.lp +Solving... +Answer: 1 +info(buckle,red,tang,states) +info(dragon,white,ching,italy) +info(grasshopper,ltgreen,ming,japan) +info(horse,dkgreen,sung,finland) +SATISFIABLE + +Models : 1 +Calls : 1 +Time : 0.003s (Solving: 0.0s 1st Model: 0.0s Unsat: 0.0s) +CPU Time : 0.003s +\end{verbatim} + +\section{Интерпретация работы программы} + +Красная нефритовая пряжка для ремня династии Тан была куплена покупательницей из США; + +Дракон из белого нефрита времён династии Цин был куплен покупателем из Италии; + +Кузнечик из светло-зелёного нефрита династии Мин продан покупателю из Японии; + +Лошадь из тёмно-зелёного нефрита династии Сун продан покупателю из Финляндии. + +\end{document} + diff --git a/02-iskr-lab-04-report.tex b/02-iskr-lab-04-report.tex new file mode 100644 index 0000000..e177787 --- /dev/null +++ b/02-iskr-lab-04-report.tex @@ -0,0 +1,215 @@ +\documentclass[a4paper,fontsize=14bp]{article} + +\input{../common-preamble} +\input{../fancy-listings-preamble} +\input{../bmstu-preamble} +\numerationTop + +\begin{document} +\thispagestyle{empty} +\makeBMSTUHeader + +% ... работе, номер, тема, предмет, ?а, кто +\makeReportTitle{лабораторной}{4}{Исчисление дискретных событий}{Представление знаний в информационных системах}{}{И.И. Лычков} +\newpage +\thispagestyle{empty} +\tableofcontents +\newpage +\pagestyle{fancy} +\section{Цель} +Получение практических навыков моделирования дискретно-событийных систем на языке логического программирования. + +\section{Задание} +В качестве исходных данных выдается словесное описание некоторой физической системы, а именно: общие правила её функционирования, состояние системы в начальный момент, список произошедших событий и вопрос относительно состояния одного из объектов системы в определенный момент времени. Также выдаются аксиомы исчисления дискретных событий. Требуется выделить в исходном описании все объекты, события, флюенты, придумать для них идентификаторы в программе, затем представить логику функционирования заданной системы в виде программы на языке ASP программирования наборов решений с помощью аксиом исчисления дискретных событий, отладить работу программы так, чтобы она выдавала ответ на указанный в задании вопрос относительно состояния одного из объектов системы в определенный момент времени. + +\section{Выполнение} +\subsection{Словесное описание системы согласно варианту} +Имеется две аксиомы initiates и terminates. Если агент включает нагреватель воздушного шара, то нагреватель более не будет выключен и будет включен. Мы задаем глобальное ограничение о том, что воздушный шар не может находиться одновременно на двух разных высотах в один момент времени. + +Когда нагреватель включен, высота воздушного шара изменяется по закону: +\[h(t) = h(0) + V*t\] +Когда нагреватель выключен, высота воздушного шара изменяется по закону: +\[h(t) = h(0) - V*t,\] +где V = 1 - скорость воздушного шара (задана константой) + +Высота воздушного шара освобождается от закона инерции по событиям включения и выключения нагревателя. Имеем следующие факты и хронику событий. Воздушный шар изначально находится на нулевой высоте. В момент времени 1 нагреватель включают, а в момент времени 3 нагреватель выключают. Необходимо проверить, что в момент времени 3 высота воздушного шара равна 2V, а в момент времени 4 она равна V. +\subsection{Перечень всех объектов, событий и флюентов с указанием их идентификаторов и смысловой нагрузки} +События и флюенты в программе: +\begin{itemize} +\item \verb|turnOn| - событие включения нагревателя; +\item \verb|turnOff| - событие выключения нагревателя; +\item \verb|heating| - флюент, говорящий о том, что шар нагревается и летит вверх; +\item \verb|falling| - флюент, говорящий о том, что шар охлаждается и падает; +\item \verb|height(X)| - флюент, говорящий о текущей высоте шара. +\end{itemize} + +Имеется две аксиомы initiates и terminates. +\begin{verbatim} +initiates(turnOn, heating, Time) :- times(Time). +terminates(turnOff, heating, Time) :- times(Time). + +initiates(turnOff, falling, Time) :- times(Time). +terminates(turnOn, falling, Time) :- times(Time). +\end{verbatim} + +Мы задаем глобальное ограничение о том, что воздушный шар не может находиться одновременно на двух разных высотах в один момент времени. +\begin{verbatim} +:- holdsAt(height(X1), T), holdsAt(height(X2), T), X1 != X2. +\end{verbatim} + +Имеем две аксиомы типа trajectory, описывающие поведение шара при нагревании и охлаждении: +\begin{verbatim} +trajectory(heating, T1, height(X2), T2) :- + times(T1), times(T2), T1 < T2, + holdsAt(height(X),T1), + X2 = X + 1 * (T2 - T1). + +trajectory(falling, T1, height(X2), T2) :- + times(T1), times(T2), T1 < T2, + holdsAt(height(X),T1), + X2 = X - 1 * (T2 - T1). +\end{verbatim} + +Высота воздушного шара освобождается от закона инерции по событиям включения и выключения нагревателя: +\begin{verbatim} +releases(turnOff, height(X), T) :- holdsAt(height(X), T). +releases(turnOn, height(X), T) :- holdsAt(height(X), T). +\end{verbatim} + +Имеем следующие факты и хронику событий. Воздушный шар изначально находится на нулевой высоте, в момент времени 1 нагреватель включают, а в момент времени 3 нагреватель выключают: +\begin{verbatim} +initiallyP(height(0)). +initiallyN(heating). + +happens(turnOn, 1). +happens(turnOff, 3). +\end{verbatim} + +Необходимо проверить, что в момент времени 3 высота воздушного шара равна 2V, а в момент времени 4 она равна V. +\begin{verbatim} +info(F1, T1, F2, T2) :- + holdsAt(height(F1), T1), holdsAt(height(F2), T2), + F1==2, T1==3, F2 == 1, T2 == 4. +#show info/4. +\end{verbatim} +\subsection{Результат выполнение программы} +Результат выполнения программы представлен на рисунке \hrf{pic:result}. +\begin{figure}[H] + \centering + \includegraphics[height=6cm]{04-lab-result.png} + \caption{Результаты работы программы} + \label{pic:result} +\end{figure} + +На рисунке \hrf{pic:result} видно, что программа нашла одно сочетание флюентов и временных отметок: в момент времени 3 высота воздушного шара равна 2, а в момент времени 4 она равна 1. + +\newpage +\appendix +\setcounter{secnumdepth}{0} +\section*{Приложения} +\addcontentsline{toc}{section}{Приложения} +\renewcommand{\thesubsection}{\Alph{subsection}} + +\setcounter{secnumdepth}{5} +\subsection{Полный листинг приложения по индивидуальному заданию} +\begin{lstlisting}[language=C,style=CCodeStyle] +%* +******************************************************************** +Стандартные аксиомы исчисления дискретных событий. +******************************************************************** +*% + +%% BEC1 - StoppedIn(t1,f,t2) +stoppedIn(T1,Fluent,T2) :- + times(T1), times(T2), T1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pics/02-dip-04-lab-cnn-weight.svg b/pics/02-dip-04-lab-cnn-weight.svg new file mode 100644 index 0000000..684e47f --- /dev/null +++ b/pics/02-dip-04-lab-cnn-weight.svg @@ -0,0 +1,1995 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + 2 + 2 + 0 + 0 + 1 + 2 + 3 + 3 + 2 + 1 + 0 + 0 + 0 + + 3 + 1 + 1 + 3 + 1 + 2 + 2 + 3 + 2 + 0 + 0 + 2 + 2 + 2 + 0 + 0 + 0 + 1 + + + + + 12 + 12 + 17 + + + + diff --git a/pics/02-dip-04-lab-dropout.svg b/pics/02-dip-04-lab-dropout.svg new file mode 100644 index 0000000..c04750e --- /dev/null +++ b/pics/02-dip-04-lab-dropout.svg @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pics/02-dip-04-lab-pack-sample.png b/pics/02-dip-04-lab-pack-sample.png new file mode 100644 index 0000000..07b0c1d Binary files /dev/null and b/pics/02-dip-04-lab-pack-sample.png differ diff --git a/pics/02-dip-04-lab-pic-aug.png b/pics/02-dip-04-lab-pic-aug.png new file mode 100644 index 0000000..36327eb Binary files /dev/null and b/pics/02-dip-04-lab-pic-aug.png differ diff --git a/pics/02-dip-04-lab-pic-src.png b/pics/02-dip-04-lab-pic-src.png new file mode 100644 index 0000000..e69c2af Binary files /dev/null and b/pics/02-dip-04-lab-pic-src.png differ diff --git a/pics/02-dip-lab02-cmyk-rgb.png b/pics/02-dip-lab02-cmyk-rgb.png new file mode 100644 index 0000000..e00b210 Binary files /dev/null and b/pics/02-dip-lab02-cmyk-rgb.png differ diff --git a/pics/02-dip-lab02-icc-profile.png b/pics/02-dip-lab02-icc-profile.png new file mode 100644 index 0000000..243e8af Binary files /dev/null and b/pics/02-dip-lab02-icc-profile.png differ diff --git a/pics/02-dip-lab02-trans-cmyk.png b/pics/02-dip-lab02-trans-cmyk.png new file mode 100644 index 0000000..123ec2b Binary files /dev/null and b/pics/02-dip-lab02-trans-cmyk.png differ diff --git a/pics/02-dip-lab02-trans-rgb.png b/pics/02-dip-lab02-trans-rgb.png new file mode 100644 index 0000000..3b5e0dd Binary files /dev/null and b/pics/02-dip-lab02-trans-rgb.png differ diff --git a/pics/02-dsp-03lab-limiter-explain.svg b/pics/02-dsp-03lab-limiter-explain.svg new file mode 100644 index 0000000..69efa2e --- /dev/null +++ b/pics/02-dsp-03lab-limiter-explain.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + Исходный сигнал + Жёсткое урезание (ограничение с нулевыми алакой и высвобождением) + Ограничитель со средними атакой и высвобождением + Ограничитель с нулевой атакой и средним высвобождением + + Изменение + + Граница + + + + + Мягкое урезание + + diff --git a/pics/02-dsp-03lab-limiter-scheme.svg b/pics/02-dsp-03lab-limiter-scheme.svg new file mode 100644 index 0000000..fcf269b --- /dev/null +++ b/pics/02-dsp-03lab-limiter-scheme.svg @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + x(n) + y(n) + Delay + PEAKAT/RT + 1 + min + AT/RT + + + + + + $\frac{lt}{(\cdot)}$ + + + + + + + + + + + + + + + + diff --git a/pics/02-dsp-03lab-limiter.svg b/pics/02-dsp-03lab-limiter.svg new file mode 100644 index 0000000..ecf34c1 --- /dev/null +++ b/pics/02-dsp-03lab-limiter.svg @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + дБ + дБ + Выходной сигнал + Входной сигнал + Порог + 1:1 + 2:1 + $\infty : 1$ + 0 + 20 + + + + + + + diff --git a/pics/02-frist-model.png b/pics/02-frist-model.png new file mode 100644 index 0000000..aa992d1 Binary files /dev/null and b/pics/02-frist-model.png differ diff --git a/pics/02-instance-first-model.png b/pics/02-instance-first-model.png new file mode 100644 index 0000000..b2ace36 Binary files /dev/null and b/pics/02-instance-first-model.png differ diff --git a/pics/02-iskr-00-0615-fsm.png b/pics/02-iskr-00-0615-fsm.png new file mode 100644 index 0000000..2cabc68 Binary files /dev/null and b/pics/02-iskr-00-0615-fsm.png differ diff --git a/pics/02-iskr-00-0616-fsm.png b/pics/02-iskr-00-0616-fsm.png new file mode 100644 index 0000000..2784b41 Binary files /dev/null and b/pics/02-iskr-00-0616-fsm.png differ diff --git a/pics/02-iskr-00-belong.png b/pics/02-iskr-00-belong.png new file mode 100644 index 0000000..8c45c1d Binary files /dev/null and b/pics/02-iskr-00-belong.png differ diff --git a/pics/02-iskr-00-collapse-fsm1.png b/pics/02-iskr-00-collapse-fsm1.png new file mode 100644 index 0000000..48fa0cf Binary files /dev/null and b/pics/02-iskr-00-collapse-fsm1.png differ diff --git a/pics/02-iskr-00-collapse-fsm11.png b/pics/02-iskr-00-collapse-fsm11.png new file mode 100644 index 0000000..9b9722c Binary files /dev/null and b/pics/02-iskr-00-collapse-fsm11.png differ diff --git a/pics/02-iskr-00-collapse-fsm12.png b/pics/02-iskr-00-collapse-fsm12.png new file mode 100644 index 0000000..b87a2d0 Binary files /dev/null and b/pics/02-iskr-00-collapse-fsm12.png differ diff --git a/pics/02-iskr-00-collapse-fsm2.png b/pics/02-iskr-00-collapse-fsm2.png new file mode 100644 index 0000000..bece309 Binary files /dev/null and b/pics/02-iskr-00-collapse-fsm2.png differ diff --git a/pics/02-iskr-00-collapse-ling.png b/pics/02-iskr-00-collapse-ling.png new file mode 100644 index 0000000..67773a0 Binary files /dev/null and b/pics/02-iskr-00-collapse-ling.png differ diff --git a/pics/02-iskr-00-collapse.png b/pics/02-iskr-00-collapse.png new file mode 100644 index 0000000..475bfaf Binary files /dev/null and b/pics/02-iskr-00-collapse.png differ diff --git a/pics/02-iskr-00-default.png b/pics/02-iskr-00-default.png new file mode 100644 index 0000000..8953778 Binary files /dev/null and b/pics/02-iskr-00-default.png differ diff --git a/pics/02-iskr-00-define.png b/pics/02-iskr-00-define.png new file mode 100644 index 0000000..d5f2d6e Binary files /dev/null and b/pics/02-iskr-00-define.png differ diff --git a/pics/02-iskr-00-final.png b/pics/02-iskr-00-final.png new file mode 100644 index 0000000..71f53d3 Binary files /dev/null and b/pics/02-iskr-00-final.png differ diff --git a/pics/02-iskr-00-perfect.png b/pics/02-iskr-00-perfect.png new file mode 100644 index 0000000..70bf00c Binary files /dev/null and b/pics/02-iskr-00-perfect.png differ diff --git a/pics/02-iskr-00-red1.svg b/pics/02-iskr-00-red1.svg new file mode 100644 index 0000000..00109f0 --- /dev/null +++ b/pics/02-iskr-00-red1.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + $P'$ + $\bar{x}y$ + $x(z).\bar{z}w$ + $Q'$ + R' + $y(z)$ + + + + + + + diff --git a/pics/02-iskr-00-red2.svg b/pics/02-iskr-00-red2.svg new file mode 100644 index 0000000..bab32ee --- /dev/null +++ b/pics/02-iskr-00-red2.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + $P'$ + $Q'$ + $R'$ + $y(z)$ + + + + + + $\bar{y}w$ + + diff --git a/pics/02-iskr-00-red3.svg b/pics/02-iskr-00-red3.svg new file mode 100644 index 0000000..a81bb00 --- /dev/null +++ b/pics/02-iskr-00-red3.svg @@ -0,0 +1,122 @@ + + + + + + + + + + + + $P'$ + $Q'$ + $R'$ + + + + w + + diff --git a/pics/02-iskr-00-uncert-belong.png b/pics/02-iskr-00-uncert-belong.png new file mode 100644 index 0000000..f924f60 Binary files /dev/null and b/pics/02-iskr-00-uncert-belong.png differ diff --git a/pics/02-iskr-00-uncert.png b/pics/02-iskr-00-uncert.png new file mode 100644 index 0000000..750a858 Binary files /dev/null and b/pics/02-iskr-00-uncert.png differ diff --git a/pics/02-mailing-ecore.png b/pics/02-mailing-ecore.png new file mode 100644 index 0000000..9c21fc2 Binary files /dev/null and b/pics/02-mailing-ecore.png differ diff --git a/pics/02-mailing-genmodel.png b/pics/02-mailing-genmodel.png new file mode 100644 index 0000000..0b54c94 Binary files /dev/null and b/pics/02-mailing-genmodel.png differ diff --git a/pics/02-mailing.png b/pics/02-mailing.png new file mode 100644 index 0000000..37a3502 Binary files /dev/null and b/pics/02-mailing.png differ diff --git a/pics/02-modeling-00-vending.svg b/pics/02-modeling-00-vending.svg new file mode 100644 index 0000000..8e185e1 --- /dev/null +++ b/pics/02-modeling-00-vending.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + торговый автомат + + БАНК + + + diff --git a/pics/02-picture.png b/pics/02-picture.png new file mode 100644 index 0000000..81fa39f Binary files /dev/null and b/pics/02-picture.png differ diff --git a/pics/02-picture_canny.png b/pics/02-picture_canny.png new file mode 100644 index 0000000..3bd0bfa Binary files /dev/null and b/pics/02-picture_canny.png differ diff --git a/pics/02-picture_chull.png b/pics/02-picture_chull.png new file mode 100644 index 0000000..8d8442a Binary files /dev/null and b/pics/02-picture_chull.png differ diff --git a/pics/02-picture_gray.png b/pics/02-picture_gray.png new file mode 100644 index 0000000..be25c5f Binary files /dev/null and b/pics/02-picture_gray.png differ diff --git a/pics/02lab-rpt-1.png b/pics/02lab-rpt-1.png new file mode 100644 index 0000000..639973a Binary files /dev/null and b/pics/02lab-rpt-1.png differ diff --git a/pics/04-addition.png b/pics/04-addition.png new file mode 100644 index 0000000..ab80a3f Binary files /dev/null and b/pics/04-addition.png differ diff --git a/pics/04-addition2.png b/pics/04-addition2.png new file mode 100644 index 0000000..b8c8dc9 Binary files /dev/null and b/pics/04-addition2.png differ diff --git a/pics/04-ball-location.png b/pics/04-ball-location.png new file mode 100644 index 0000000..539cfdd Binary files /dev/null and b/pics/04-ball-location.png differ diff --git a/pics/04-follow.png b/pics/04-follow.png new file mode 100644 index 0000000..07258e6 Binary files /dev/null and b/pics/04-follow.png differ diff --git a/pics/04-fpointvals.png b/pics/04-fpointvals.png new file mode 100644 index 0000000..e2afd7c Binary files /dev/null and b/pics/04-fpointvals.png differ diff --git a/pics/04-lab-result.png b/pics/04-lab-result.png new file mode 100644 index 0000000..05c96d3 Binary files /dev/null and b/pics/04-lab-result.png differ diff --git a/pics/05-1967vn044.png b/pics/05-1967vn044.png new file mode 100644 index 0000000..7f90dd8 Binary files /dev/null and b/pics/05-1967vn044.png differ diff --git a/pics/05-col-diag.png b/pics/05-col-diag.png new file mode 100644 index 0000000..1f7ebb1 Binary files /dev/null and b/pics/05-col-diag.png differ diff --git a/pics/05-core.png b/pics/05-core.png new file mode 100644 index 0000000..64ba481 Binary files /dev/null and b/pics/05-core.png differ diff --git a/pics/05-intel.png b/pics/05-intel.png new file mode 100644 index 0000000..c6a953a Binary files /dev/null and b/pics/05-intel.png differ diff --git a/pics/05-mamdani1.png b/pics/05-mamdani1.png new file mode 100644 index 0000000..7f0f327 Binary files /dev/null and b/pics/05-mamdani1.png differ diff --git a/pics/05-mamdani2.png b/pics/05-mamdani2.png new file mode 100644 index 0000000..228bd4a Binary files /dev/null and b/pics/05-mamdani2.png differ diff --git a/pics/05-mamdani3.png b/pics/05-mamdani3.png new file mode 100644 index 0000000..3d7bf8e Binary files /dev/null and b/pics/05-mamdani3.png differ diff --git a/pics/05-mamdani4.png b/pics/05-mamdani4.png new file mode 100644 index 0000000..9c864b1 Binary files /dev/null and b/pics/05-mamdani4.png differ diff --git a/pics/05-triread.png b/pics/05-triread.png new file mode 100644 index 0000000..ad3b0fc Binary files /dev/null and b/pics/05-triread.png differ diff --git a/pics/06-blocks-conn.png b/pics/06-blocks-conn.png new file mode 100644 index 0000000..1571f0a Binary files /dev/null and b/pics/06-blocks-conn.png differ diff --git a/pics/06-macro-dir.png b/pics/06-macro-dir.png new file mode 100644 index 0000000..e7bd5ea Binary files /dev/null and b/pics/06-macro-dir.png differ diff --git a/pics/06-macro-or.png b/pics/06-macro-or.png new file mode 100644 index 0000000..0a74ca7 Binary files /dev/null and b/pics/06-macro-or.png differ diff --git a/pics/06-macro-s.png b/pics/06-macro-s.png new file mode 100644 index 0000000..b3b5e7a Binary files /dev/null and b/pics/06-macro-s.png differ diff --git a/pics/06-obj-dir.png b/pics/06-obj-dir.png new file mode 100644 index 0000000..95b6f9c Binary files /dev/null and b/pics/06-obj-dir.png differ diff --git a/pics/06-obj-orien.png b/pics/06-obj-orien.png new file mode 100644 index 0000000..e64b16c Binary files /dev/null and b/pics/06-obj-orien.png differ diff --git a/pics/06-obj-prop.png b/pics/06-obj-prop.png new file mode 100644 index 0000000..1b1a8e1 Binary files /dev/null and b/pics/06-obj-prop.png differ diff --git a/pics/06-oper-phys.png b/pics/06-oper-phys.png new file mode 100644 index 0000000..a6c895d Binary files /dev/null and b/pics/06-oper-phys.png differ diff --git a/pics/1.PNG b/pics/1.PNG new file mode 100644 index 0000000..b1a42a4 Binary files /dev/null and b/pics/1.PNG differ diff --git a/pics/c_100.jpg b/pics/c_100.jpg new file mode 100644 index 0000000..6066e9b Binary files /dev/null and b/pics/c_100.jpg differ diff --git a/pics/q_100.jpg b/pics/q_100.jpg new file mode 100644 index 0000000..226d77e Binary files /dev/null and b/pics/q_100.jpg differ diff --git a/pics/sem-02-illum.png b/pics/sem-02-illum.png new file mode 100644 index 0000000..b3581dc Binary files /dev/null and b/pics/sem-02-illum.png differ diff --git a/tikz-uml.sty b/tikz-uml.sty new file mode 100644 index 0000000..93a7fed --- /dev/null +++ b/tikz-uml.sty @@ -0,0 +1,4306 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Start of tikz-uml.sty +% +% Some macros for UML Diagrams. +% Home page of project: +% Author: Nicolas Kielbasiewicz +% Style from: +% Fixed by Nicolas Kielbasiewicz (nicolas.kielbasiewicz@ensta-paristech.fr) in dec 2010 to compile with pgf 2.00 + +\NeedsTeXFormat{LaTeX2e}[1995/12/01]% +\ProvidesPackage{tikz-uml}[2011/01/26]% + +\RequirePackage{ifthen}% +\RequirePackage{tikz}% +\RequirePackage{xstring}% +\RequirePackage{calc}% +\RequirePackage{pgfopts}% +\usetikzlibrary{backgrounds,arrows,shapes,fit,shadows,decorations.markings}% + +\def\tikzumlPackageLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, packageLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, packageLayers/.store in=\tikzumlPackageLayersNum}% +\def\tikzumlStateLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, stateLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, stateLayers/.store in=\tikzumlStateLayersNum}% +\def\tikzumlFragmentLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.store in=\tikzumlFragmentLayersNum}% +\def\tikzumlComponentLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, componentLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, componentLayers/.store in=\tikzumlComponentLayersNum}% + +\ProcessPgfOptions{/tikzuml/options}% + +\def\pgfsetlayersArg{background}% +\pgfdeclarelayer{background}% +\newcounter{tikzumlPackageLayers}% +\loop \pgfdeclarelayer{package\thetikzumlPackageLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,package\thetikzumlPackageLayers}% + \ifnum\tikzumlPackageLayersNum>\thetikzumlPackageLayers% + \stepcounter{tikzumlPackageLayers}% +\repeat% +% +\newcounter{tikzumlFragmentLayers}% +\loop \pgfdeclarelayer{fragment\thetikzumlFragmentLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,fragment\thetikzumlFragmentLayers}% + \ifnum\tikzumlFragmentLayersNum>\thetikzumlFragmentLayers% + \stepcounter{tikzumlFragmentLayers}% +\repeat% +% +\newcounter{tikzumlStateLayers}% +\loop \pgfdeclarelayer{state\thetikzumlStateLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,state\thetikzumlStateLayers}% + \ifnum\tikzumlStateLayersNum>\thetikzumlStateLayers% + \stepcounter{tikzumlStateLayers}% +\repeat% +% +\newcounter{tikzumlComponentLayers}% +\loop \pgfdeclarelayer{component\thetikzumlComponentLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,component\thetikzumlComponentLayers}% + \ifnum\tikzumlComponentLayersNum>\thetikzumlComponentLayers% + \stepcounter{tikzumlComponentLayers}% +\repeat% +% +\pgfdeclarelayer{lifelines}% +\pgfdeclarelayer{activity}% +\pgfdeclarelayer{connections}% +\xdef\pgfsetlayersArg{\pgfsetlayersArg,lifelines,activity,connections,main}% +\pgfsetlayers{\pgfsetlayersArg}% + +\pgfkeys{/tikzuml/.cd, text/.initial=black, draw/.initial=black, font/.initial=\small,% + fill class/.initial=yellow!20, fill template/.initial=yellow!2, fill package/.initial=blue!20, fill note/.initial=green!20,% + fill usecase/.initial=blue!20, fill system/.initial=white,% + fill state/.initial=yellow!20,% + fill object/.initial=yellow!20,% + fill call/.initial=white,% + fill fragment/.initial= none,% + fill component/.initial= yellow!20,% + fill assembly connector/.initial= white,% + fill port/.initial=yellow!10,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in tikzuml global, invalid option \keyname}% + }}% +\pgfkeys{/tikzuml/.cd, text/.get=\tikzumltextcolor, draw/.get=\tikzumldrawcolor, font/.get=\tikzumlfont,% + fill class/.get=\tikzumlfillclasscolor, fill template/.get=\tikzumlfilltemplatecolor,% + fill package/.get=\tikzumlfillpackagecolor, fill note/.get=\tikzumlfillnotecolor,% + fill usecase/.get=\tikzumlfillusecasecolor, fill system/.get=\tikzumlfillsystemcolor,% + fill state/.get=\tikzumlfillstatecolor,% + fill object/.get=\tikzumlfillobjectcolor,% + fill call/.get=\tikzumlfillcallcolor,% + fill fragment/.get=\tikzumlfillfragmentcolor,% + fill component/.get=\tikzumlfillcomponentcolor,% + fill assembly connector/.get=\tikzumlfillassemblyconnectorcolor,% + fill port/.get=\tikzumlfillportcolor% +}% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% class diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\pgfkeys{/tikzuml/relation/.cd, attr1/.style args={#1|#2}{arg1=#1, mult1=#2},% + attr2/.style args={#1|#2}{arg2=#1, mult2=#2},% + attr/.style args={#1|#2}{arg=#1, mult=#2},% + recursive/.style args={#1|#2|#3}{angle1=#1, angle2=#2, loopsize=#3},% + anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2},% + recursive direction/.style args={#1 to #2}{recursive direction start=#1, recursive direction end=#2}}% +\pgfkeys{/tikzuml/note/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}% + +\tikzstyle{tikzuml class style}=[rectangle split, rectangle split parts=3, rectangle split part align={center, left, left}, minimum height=2em, node distance=2em]% +\tikzstyle{tikzuml narynode style}=[diamond]% +\tikzstyle{tikzuml template style}=[dashed, inner ysep=0.5em, inner xsep=1ex]% +\tikzstyle{tikzuml control nodes style}=[fill=black, inner sep=1.5pt, circle]% +\tikzstyle{tikzuml inherit style}=[color=\tikzumldrawcolor, -open triangle 45]% +\tikzstyle{tikzuml implements style}=[color=\tikzumldrawcolor, -open triangle 45, dashed]% +\tikzstyle{tikzuml association style}=[color=\tikzumldrawcolor, -]% +\tikzstyle{tikzuml unidirectional association style}=[color=\tikzumldrawcolor, -angle 45]% +\tikzstyle{tikzuml aggregation style}=[color=\tikzumldrawcolor, open diamond-]% +\tikzstyle{tikzuml unidirectional aggregation style}=[color=\tikzumldrawcolor, open diamond-angle 45]% +\tikzstyle{tikzuml composition style}=[color=\tikzumldrawcolor, diamond-]% +\tikzstyle{tikzuml unidirectional composition style}=[color=\tikzumldrawcolor, diamond-angle 45]% +\tikzstyle{tikzuml dependency style}=[color=\tikzumldrawcolor, -angle 45, dashed]% +\tikzstyle{tikzuml import style}=[color=\tikzumldrawcolor, -angle 45, dashed]% + +\pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}% + +\newcounter{tikzumlPackageClassNum}% +\newcounter{tikzumlPackageSubPackageNum}% +\newcounter{tikzumlRelationNum}% +\setcounter{tikzumlRelationNum}{1}% +\newcounter{tikzumlNoteNum}% +\setcounter{tikzumlNoteNum}{1}% + +\newcounter{pos}% +\newcounter{posT}% +\newcounter{posStereo}% + +\newcounter{tikzumlPackageLevel}% +\setcounter{tikzumlPackageLevel}{0}% + +% utility : change default colors +\newcommand{\tikzumlset}[1]{% + \pgfkeys{/tikzuml/.cd,#1}% + \pgfkeys{/tikzuml/.cd, text/.get=\tikzumltextcolor, draw/.get=\tikzumldrawcolor, font/.get=\tikzumlfont,% + fill class/.get=\tikzumlfillclasscolor, fill template/.get=\tikzumlfilltemplatecolor,% + fill package/.get=\tikzumlfillpackagecolor, fill note/.get=\tikzumlfillnotecolor,% + fill usecase/.get=\tikzumlfillusecasecolor, fill system/.get=\tikzumlfillsystemcolor,% + fill state/.get=\tikzumlfillstatecolor,% + fill object/.get=\tikzumlfillobjectcolor,% + fill call/.get=\tikzumlfillcallcolor,% + fill fragment/.get=\tikzumlfillfragmentcolor,% + fill component/.get=\tikzumlfillcomponentcolor,% + fill assembly connector/.get=\tikzumlfillassemblyconnectorcolor,% + fill port/.get=\tikzumlfillportcolor}}% + +% define a point +% arg : node/coordinates of the point +\newcommand{\umlpoint}[1]{% + \begin{pgfonlayer}{connections}% + \node[tikzuml control nodes style] at (#1) {};% + \end{pgfonlayer}% +}% + +\newcommand{\tikzumlskipescape}[3][_]{% +\begingroup% + \def\_{#1}\edef\x{\endgroup% + \def\noexpand\csname #3\endcsname{#2}}\x% +}% + +% define a uml package +% arg : package name +% optional : x, y coordinates of the package +% draw, fill, text colors +\newenvironment{umlpackage}[2][]{% + \ifnum\thetikzumlPackageLevel>0% + \let\tikzumlPackage@nameold\tikzumlPackage@fitname% + \def\tikzumlPackage@name{#2}% + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x% + \let\tikzumlPackage@parentold\tikzumlPackage@parent% + \edef\tikzumlPackage@parent{\tikzumlPackage@parentold @@\tikzumlPackage@nameold}% + \else% + \def\tikzumlPackage@parent{}% + \def\tikzumlPackage@name{#2}% + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x% + \fi% + % + \let\tikzumlPackage@nodeNameold\tikzumlPackage@nodeName% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlPackage@nodeName{\tikzumlPackage@name}}\x% + % + \expandafter\gdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{}% + % + \setcounter{tikzumlPackageClassNum}{0}% + \setcounter{tikzumlPackageSubPackageNum}{0}% + \stepcounter{tikzumlPackageLevel}% + + \pgfkeys{/tikzuml/package/.cd, x/.initial=0, y/.initial=0, x/.default=0, y/.default=0,% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillpackagecolor, text/.initial=\tikzumltextcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlpackage, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/package/.cd, #1}% + \pgfkeys{/tikzuml/package/.cd, x/.get=\xshift, y/.get=\yshift, draw/.get=\tikzumlpackagedraw, fill/.get=\tikzumlpackagefill, text/.get=\tikzumlpackagetext}% + % + \begin{scope}[xshift=\xshift cm, yshift=\yshift cm]% +}{% + \addtocounter{tikzumlPackageLevel}{-1}% + \begin{pgfonlayer}{package\thetikzumlPackageLevel}% + % + % if contains no class, one define a fictive node to enable the fit option + \ifnum\c@tikzumlPackageClassNum=0% + \ifnum\c@tikzumlPackageSubPackageNum=0% + \node[inner sep=1.5ex] (\tikzumlPackage@nodeName-root) at (0,0) {\phantom{\tikzumlPackage@nodeName}};% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{(\tikzumlPackage@nodeName-root)}% + % + \fi% + \fi% + % + \ifnum\c@tikzumlPackageLevel>0% + \def\tikzumlPackageFitTmp{\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname}% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname{\tikzumlPackageFitTmp (\tikzumlPackage@nodeName) (\tikzumlPackage@nodeName-caption)}% + \stepcounter{tikzumlPackageSubPackageNum}% + \fi% + % + \node[draw=\tikzumlpackagedraw, fill=\tikzumlpackagefill, text=\tikzumlpackagetext, font=\tikzumlfont, inner sep=1.5ex, fit = \csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname] (\tikzumlPackage@nodeName) {};% + \node[draw=\tikzumlpackagedraw, fill=\tikzumlpackagefill, text=\tikzumlpackagetext, font=\tikzumlfont, minimum height=1.5em, outer ysep=-0.3, anchor=south west] (\tikzumlPackage@nodeName-caption) at (\tikzumlPackage@nodeName.north west) {\tikzumlPackage@name};% + \end{pgfonlayer}% + \end{scope}% +}% + +% shortcut to define an empty package +\newcommand{\umlemptypackage}[2][]{\begin{umlpackage}[#1]{#2} \end{umlpackage}}% + +% define a uml class (environment) +% arg : name of the class +% optional : x,y coordinates of the class +% width of the class node +% type of class (class, interface, typedef, enum) +% template parameters +% draw, fill, text colors +\newenvironment{umlclassenv}[2][]{% + \pgfkeys{/tikzuml/class/.cd, x/.initial=0, y/.initial=0, width/.initial=10ex, type/.initial=class, template/.initial={}, name/.initial={tikzumlEmpty},% + draw/.initial=\tikzumldrawcolor, fill template/.initial=\tikzumlfilltemplatecolor, fill/.initial=\tikzumlfillclasscolor,% + text/.initial=\tikzumltextcolor, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlclassenv, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/class/.cd,#1}% + \pgfkeys{/tikzuml/class/.cd, x/.get=\umlclassX, y/.get=\umlclassY, width/.get=\umlclassMinimumWidth, type/.get=\umlclassType, template/.get=\umlclassTemplateParam,% + name/.get=\umlclassName,% + draw/.get=\tikzumlclassdraw, fill/.get=\tikzumlclassfill, text/.get=\tikzumlclasstext, fill template/.get=\tikzumlclasstemplate}% + % + \ifthenelse{\equal{\umlclassType}{class}}{% + \def\tikzumlClassType{}% + }{% + \ifthenelse{\equal{\umlclassType}{abstract}}{% + \def\tikzumlClassType{}% + }{% + \def\tikzumlClassType{$<<$\umlclassType$>>$ \\}% + }% + }% + % + \ifthenelse{\equal{\umlclassTemplateParam}{}}{% + \def\tikzumlClassVPadding{}% + \def\tikzumlClassHPadding{}% + }{% + \def\tikzumlClassVPadding{\vspace{0.1em} \\}% + \def\tikzumlClassHPadding{\hspace{0.5ex} $ $}% + }% + % + \def\tikzumlClassName{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x% + % + \ifthenelse{\equal{\umlclassName}{tikzumlEmpty}}{}{% + \def\tikzumlClassNodeName{\umlclassName}% + }% + % + \StrSubstitute{\tikzumlClassNodeName}{:}{@COLON@}[\tikzumlClassNodeName] + % + \ifthenelse{\equal{\umlclassType}{abstract}}{% + \let\tikzumlClassNameOld\tikzumlClassName% + \def\tikzumlClassName{{\it \tikzumlClassNameOld}}% + }{}% + % + \def\tikzumlClassPos{\umlclassX,\umlclassY}% + \def\tikzumlClassAttributes{}% + \def\tikzumlClassOperations{}% + \def\tikzumlClassAbstractClass{}% + \def\tikzumlClassInterface{}% + % +}{% + \node[tikzuml class style, draw=\tikzumlclassdraw, fill=\tikzumlclassfill, text=\tikzumlclasstext, font=\tikzumlfont, minimum width=\umlclassMinimumWidth] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlClassOperations% + \end{tabular}% + };% + % + \ifthenelse{\equal{\umlclassTemplateParam}{}}{}{% + \draw (\tikzumlClassNodeName.north east) node[tikzuml template style, name=\tikzumlClassNodeName-template, draw=\tikzumlclassdraw, fill=\tikzumlclasstemplate, text=\tikzumlclasstext, font=\tikzumlfont] {\umlclassTemplateParam};% + }% + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \ifthenelse{\equal{\umlclassTemplateParam}{}}{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName)}% + }{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}% + }% + \stepcounter{tikzumlPackageClassNum}% + \fi% +}% + +% shortcuts for interface, enum and typedef environments +\newenvironment{umlabstractenv}[2][]{\begin{umlclassenv}[type=abstract,#1]{#2}}{\end{umlclassenv}}% +\newenvironment{umlinterfaceenv}[2][]{\begin{umlclassenv}[type=interface,#1]{#2}}{\end{umlclassenv}}% +\newenvironment{umltypedefenv}[2][]{\begin{umlclassenv}[type=typedef,#1]{#2}}{\end{umlclassenv}}% +\newenvironment{umlenumenv}[2][]{\begin{umlclassenv}[type=enum,#1]{#2}}{\end{umlclassenv}}% + +% define a uml class (command) +% args : name of the class +% attributes of the class +% operations of the class +% optional : x,y coordinates of the class +% width of the class node +% type of class (class, interface, typedef, enum) +% template parameters +% draw, fill, text colors +\newcommand{\umlclass}[4][]{% + \pgfkeys{/tikzuml/class/.cd, x/.initial=0, y/.initial=0, width/.initial=10ex, type/.initial=class, template/.initial={}, name/.initial={tikzumlEmpty},% + draw/.initial=\tikzumldrawcolor, fill template/.initial=\tikzumlfilltemplatecolor, fill/.initial=\tikzumlfillclasscolor,% + text/.initial=\tikzumltextcolor, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlclass, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/class/.cd,#1}% + \pgfkeys{/tikzuml/class/.cd, x/.get=\umlclassX, y/.get=\umlclassY, width/.get=\umlclassMinimumWidth, type/.get=\umlclassType, template/.get=\umlclassTemplateParam,% + name/.get=\umlclassName,% + draw/.get=\tikzumlclassdraw, fill/.get=\tikzumlclassfill, text/.get=\tikzumlclasstext, fill template/.get=\tikzumlclasstemplate}% + % + \ifthenelse{\equal{\umlclassType}{class}\OR\equal{\umlclassType}{abstract}}{% + \def\tikzumlClassType{}% + }{% + \def\tikzumlClassType{$<<$\umlclassType$>>$ \\}% + }% + % + \ifthenelse{\equal{\umlclassTemplateParam}{}}{% + \def\tikzumlClassVPadding{}% + \def\tikzumlClassHPadding{}% + }{% + \def\tikzumlClassVPadding{\vspace{0.1em} \\}% + \def\tikzumlClassHPadding{\hspace{0.5ex} $ $}% + }% + % + \def\tikzumlClassName{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x% + % + \ifthenelse{\equal{\umlclassName}{tikzumlEmpty}}{}{% + \def\tikzumlClassNodeName{\umlclassName}% + }% + % + \StrSubstitute{\tikzumlClassNodeName}{:}{@COLON@}[\tikzumlClassNodeName] + % + \ifthenelse{\equal{\umlclassType}{abstract}}{% + \let\tikzumlClassNameOld\tikzumlClassName% + \def\tikzumlClassName{{\it \tikzumlClassNameOld}}% + }{}% + % + \def\tikzumlClassPos{\umlclassX,\umlclassY}% + \def\tikzumlClassAttributes{#3}% + \def\tikzumlClassOperations{#4}% + % + \node[tikzuml class style, draw=\tikzumlclassdraw, fill=\tikzumlclassfill, text=\tikzumlclasstext, font=\tikzumlfont, minimum width=\umlclassMinimumWidth] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlClassOperations% + \end{tabular}% + };% + % + \ifthenelse{\equal{\umlclassTemplateParam}{}}{}{% + \draw (\tikzumlClassNodeName.north east) node[tikzuml template style, name=\tikzumlClassNodeName-template, draw=\tikzumlclassdraw, fill=\tikzumlclasstemplate, text=\tikzumlclasstext, font=\tikzumlfont] {\umlclassTemplateParam};% + }% + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \ifthenelse{\equal{\umlclassTemplateParam}{}}{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName)}% + }{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}% + }% + \stepcounter{tikzumlPackageClassNum}% + \fi% +}% + +% shortcuts for interface, enum and typedef environments +\newcommand{\umlabstract}[4][]{\umlclass[type=abstract,#1]{#2}{#3}{#4}}% +\newcommand{\umlinterface}[4][]{\umlclass[type=interface,#1]{#2}{#3}{#4}}% +\newcommand{\umltypedef}[4][]{\umlclass[type=typedef,#1]{#2}{#3}{#4}}% +\newcommand{\umlenum}[4][]{\umlclass[type=enum,#1]{#2}{#3}{#4}}% + +% shortcut to define an empty class +\newcommand{\umlemptyclass}[2][]{\umlclass[#1]{#2}{}{}}% + +% define a class attribute +\newcommand{\umlattr}[1]{\def\tikzumlClassAttributes{#1}}% + +% underline the text for static arg +\newcommand{\umlstatic}[1]{\underline{#1}}% +\newcommand{\umlvirt}[1]{\textit{#1}}% + +% define a class operation +\newcommand{\umlop}[1]{\def\tikzumlClassOperations{#1}}% + +% define node for n-ary association +\newcommand{\umlNarynode}[2][]{% + \def\tikzumlNaryNodeAnchor{.north} + \def\tikzumlNaryNodeLabelPos{above} + \pgfkeys{/tikzuml/narynode/.cd, x/.initial=0, y/.initial=0, width/.initial=6ex, name/.initial={tikzumlEmpty},% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillclasscolor,% + text/.initial=\tikzumltextcolor, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{above}}{% + \def\tikzumlNaryNodeAnchor{.north}% + \def\tikzumlNaryNodeLabelPos{above}% + }{% + \ifthenelse{\equal{\keyname}{above left}}{% + \def\tikzumlNaryNodeAnchor{.north west}% + \def\tikzumlNaryNodeLabelPos{above left}% + }{% + \ifthenelse{\equal{\keyname}{left}}{% + \def\tikzumlNaryNodeAnchor{.west}% + \def\tikzumlNaryNodeLabelPos{left}% + }{% + \ifthenelse{\equal{\keyname}{below left}}{% + \def\tikzumlNaryNodeAnchor{.south west}% + \def\tikzumlNaryNodeLabelPos{below left}% + }{% + \ifthenelse{\equal{\keyname}{below}}{% + \def\tikzumlNaryNodeAnchor{.south}% + \def\tikzumlNaryNodeLabelPos{below}% + }{% + \ifthenelse{\equal{\keyname}{below right}}{% + \def\tikzumlNaryNodeAnchor{.south east}% + \def\tikzumlNaryNodeLabelPos{below right}% + }{% + \ifthenelse{\equal{\keyname}{right}}{% + \def\tikzumlNaryNodeAnchor{.east}% + \def\tikzumlNaryNodeLabelPos{right}% + }{% + \ifthenelse{\equal{\keyname}{above right}}{% + \def\tikzumlNaryNodeAnchor{.north east}% + \def\tikzumlNaryNodeLabelPos{above right}% + }{% + \errmessage{TIKZUML ERROR : in umlNarynode, invalid option \keyname}% + }% + }% + }% + }% + }% + }% + }% + }% + }}% + \pgfkeys{/tikzuml/narynode/.cd,#1}% + \pgfkeys{/tikzuml/narynode/.cd, x/.get=\umlnarynodeX, y/.get=\umlnarynodeY, width/.get=\umlnarynodeMinimumWidth, name/.get=\umlnaryName,% + draw/.get=\tikzumlnarynodedraw, fill/.get=\tikzumlnarynodefill, text/.get=\tikzumlnarynodetext}% + % + \def\tikzumlNaryName{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlNaryNodeName{\tikzumlNaryName}}\x% + % + \ifthenelse{\equal{\umlnaryName}{tikzumlEmpty}}{}{% + \def\tikzumlNaryNodeName{\umlnaryName}% + }% + % + \StrSubstitute{\tikzumlNaryNodeName}{:}{@COLON@}[\tikzumlNaryNodeName] + % + \def\tikzumlNarynodePos{\umlnarynodeX,\umlnarynodeY}% + % + \node[tikzuml narynode style, draw=\tikzumlnarynodedraw, fill=\tikzumlnarynodefill, text=\tikzumlnarynodetext, font=\tikzumlfont, minimum width=\umlnarynodeMinimumWidth, minimum height=\umlnarynodeMinimumWidth] (\tikzumlNaryNodeName) at (\tikzumlNarynodePos) {};% + \draw (\tikzumlNaryNodeName\tikzumlNaryNodeAnchor) node[\tikzumlNaryNodeLabelPos] {\tikzumlNaryName}; + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlNaryNodeName)}% + \stepcounter{tikzumlPackageClassNum}% + \fi% +}% + +% main command to define a relation between two classes +% args : src class +% dest class +% optional : geometry of the line +% barycentric weight +% name of the src class type attribute defined by the relation +% multiplicity of the src class type attribute defined by the relation +% position on the relation +% text justification on the relation +% name of the dest class type attribute defined by the relation +% multiplicity of the dest class type attribute defined by the relation +% position on the relation +% anchors on linked classes +% text justification on the relation +% start angle, end angle and size of the relation (only if recursive) +% stereotype of the relation +% style of the relation (association, aggregation, composition, inherit, ...) +\newcommand{\umlrelation}[3][]{% + \pgfkeys{/tikzuml/relation/.cd, geometry/.initial=--, weight/.initial=0.5, arm1/.initial={auto}, arm2/.initial={auto},% + arg1/.initial={}, arg2/.initial={}, arg/.initial={},% + mult1/.initial={}, mult2/.initial={}, mult/.initial={},% + pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial={tikzumlEmpty},% + align1/.initial={}, align2/.initial={}, align/.initial={},% + anchor1/.initial={tikzumlEmpty}, anchor2/.initial={tikzumlEmpty},% + angle1/.initial=-30, angle2/.initial=30, loopsize/.initial=3em,% + stereo/.initial={}, pos stereo/.initial=0.5,% + style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,% + recursive mode/.initial=default, recursive direction start/.initial=right,% + recursive direction end/.initial=bottom,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{with port}% + \OR\equal{\keyname}{interface}% + \OR\equal{\keyname}{padding}% + \OR\equal{\keyname}{width}% + \OR\equal{\keyname}{first arm}% + \OR\equal{\keyname}{second arm}% + \OR\equal{\keyname}{middle arm}% + \OR\equal{\keyname}{last arm}% + \OR\equal{\keyname}{distance}}{}{% + \errmessage{TIKZUML ERROR : in umlrelation, invalid option \keyname}% + }% + }}% + \pgfkeys{/tikzuml/relation/.cd,#1}% + \pgfkeys{/tikzuml/relation/.cd, geometry/.get=\geometry, weight/.get=\weight, arm1/.get=\armO, arm2/.get=\armT,% + arg1/.get=\attrName, arg2/.get=\attrNameTO, arg/.get=\attrNameTT,% + mult1/.get=\multiplicity, mult2/.get=\multiplicityTO, mult/.get=\multiplicityTT,% + pos1/.get=\position, pos2/.get=\positionTO, pos/.get=\positionTT,% + align1/.get=\align, align2/.get=\alignTO, align/.get=\alignTT,% + anchor1/.get=\tikzumlSrcAnchor, anchor2/.get=\tikzumlDestAnchor,% + angle1/.get=\startangle, angle2/.get=\endangle, loopsize/.get=\loopsize,% + stereo/.get=\stereo, pos stereo/.get=\positionStereotype,% + style/.get=\style, name/.get=\relationName,% + recursive mode/.get=\tikzumlrecmode,% + recursive direction start/.get=\tikzumlrecdirstart,% + recursive direction end/.get=\tikzumlrecdirend}% + % + % managing \_ in class names for node names + \def\tikzumlSrcClassName{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x% + % + \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName] + % + \def\tikzumlDestClassName{#3}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x% + % + \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName] + % + % managing alias keys + \def\attrNameT{\attrNameTO\attrNameTT}% + \def\multiplicityT{\multiplicityTO\multiplicityTT}% + \def\alignT{\alignTO\alignTT}% + \def\posAttrName{}% + \def\posMultiplicity{}% + \def\posAttrNameT{}% + \def\posMultiplicityT{}% + % + \ifthenelse{\equal{\positionTT}{tikzumlEmpty}}{% + \def\positionT{\positionTO}% + }{% + \def\positionT{\positionTT}% + }% + % + \def\attrAlign{}% + \def\multAlign{}% + \def\attrAlignT{}% + \def\multAlignT{}% + % + \ifthenelse{\equal{\align}{left}}{% + \def\attrAlign{above right}% + \def\multAlign{below right}% + }{% + \ifthenelse{\equal{\align}{right}}{% + \def\attrAlign{above left}% + \def\multAlign{below left}% + }{}% + }% + % + \ifthenelse{\equal{\alignT}{left}}{% + \def\attrAlignT{above right}% + \def\multAlignT{below right}% + }{% + \ifthenelse{\equal{\alignT}{right}}{% + \def\attrAlignT{above left}% + \def\multAlignT{below left}% + }{}% + }% + % + % def stereotype + \ifthenelse{\equal{\stereo}{}}{% + \def\stereotype{}% + }{% + \def\stereotype{$<<$\stereo$>>$}% + }% + + % def anchors macros + \ifthenelse{\equal{\tikzumlSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlSrcAnchor{}% + }{% + \let\tikzumlSrcAnchorold\tikzumlSrcAnchor% + \def\tikzumlSrcAnchor{.\tikzumlSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlDestAnchor{}% + }{% + \let\tikzumlDestAnchorold\tikzumlDestAnchor% + \def\tikzumlDestAnchor{.\tikzumlDestAnchorold}% + }% + % + \setcounter{pos}{100*\real{\position}}% + \setcounter{posT}{100*\real{\positionT}}% + \setcounter{posStereo}{100*\real{\positionStereotype}}% + % + %\pgfmathsetmacro{\weightT}{1-\real{\weight}}% + \tikzmath{% + real \weightT;% + \weightT = 1 - real \weight;% + }% + % + \def\tikzumlControlNodesNum{0}% + % + \def\pos{\position}% + \def\posT{\positionT}% + \def\posStereo{\positionStereotype}% + % + \node[inner sep=0] (\relationName-middle) at (barycentric cs:\tikzumlSrcClassNodeName=\weightT,\tikzumlDestClassNodeName=\weight) {};% + % + % straight line + \ifthenelse{\equal{\geometry}{--}}{% + \ifthenelse{\equal{\tikzumlSrcClassNodeName}{\tikzumlDestClassNodeName}}{% + \def\arcNum{1}% + \def\arcNumT{1}% + % + \ifthenelse{\equal{\tikzumlrecmode}{default}}{% + \xdef\tikzumlLastArc{node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% + node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% + node[pos=\positionStereotype, anchor=center] {\stereotype} }% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName) edge[in=\endangle, out=\startangle, distance=\loopsize] \tikzumlLastArc% + node[midway, inner sep=0, name=\relationName-1, anchor=center] {} (\tikzumlDestClassNodeName) }% + }{% + \ifthenelse{\equal{\tikzumlrecmode}{transition}}{% + \xdef\tikzumlFirstArc{node[midway, inner sep=0, name=\relationName-1, anchor=center] {}}% + \xdef\tikzumlMidOneArc{node[midway, inner sep=0, name=\relationName-3, anchor=center] {}}% + % + \ifthenelse{\equal{\tikzumlrecdirstart}{\tikzumlrecdirend}}{% + \def\numArcs{3}% + \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-5, anchor=center] {}}% + % + \begin{pgfonlayer}{connections}% + \draw (\tikzumlSrcClassNodeName) edge[in=\endangle, out=\startangle, distance=\loopsize, draw=none] % + node[midway, inner sep=0, name=\relationName-tmp, anchor=center] {} (\tikzumlDestClassNodeName);% + \ifthenelse{\equal{\tikzumlrecdirstart}{right}\OR\equal{\tikzumlrecdirstart}{left}}{% + \node[inner sep=0, name=\relationName-2] at (\tikzumlSrcClassNodeName.\startangle -| \relationName-tmp) {};% + \node[inner sep=0, name=\relationName-4] at (\tikzumlDestClassNodeName.\endangle -| \relationName-tmp) {};% + }{% + \node[inner sep=0, name=\relationName-2] at (\tikzumlSrcClassNodeName.\startangle |- \relationName-tmp) {};% + \node[inner sep=0, name=\relationName-4] at (\tikzumlDestClassNodeName.\endangle |- \relationName-tmp) {};% + }% + \end{pgfonlayer}% + }{% + \def\numArcs{4}% + \xdef\tikzumlMidTwoArc{node[midway, inner sep=0, name=\relationName-5, anchor=center] {}}% + \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-7, anchor=center] {}}% + % + \begin{pgfonlayer}{connections}% + \draw (\tikzumlSrcClassNodeName) edge[in=\endangle, out=\startangle, distance=\loopsize, draw=none] % + node[midway, name=\relationName-4, anchor=center] {} (\tikzumlDestClassNodeName);% + \ifthenelse{\equal{\tikzumlrecdirstart}{right}\OR\equal{\tikzumlrecdirstart}{left}}{% + \node[inner sep=0, name=\relationName-2] at (\tikzumlSrcClassNodeName.\startangle -| \relationName-4) {};% + \node[inner sep=0, name=\relationName-6] at (\tikzumlDestClassNodeName.\endangle |- \relationName-4) {};% + }{% + \node[inner sep=0, name=\relationName-2] at (\tikzumlSrcClassNodeName.\startangle |- \relationName-4) {};% + \node[inner sep=0, name=\relationName-6] at (\tikzumlDestClassNodeName.\endangle -| \relationName-4) {};% + }% + \end{pgfonlayer}% + }% + % + \ifnum\numArcs=4% + \ifnum\theposStereo>300% + \pgfmathsetmacro{\posStereo}{(\theposStereo-300)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype}}% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype}}% + \else% + \ifnum\theposStereo>200% + \pgfmathsetmacro{\posStereo}{(\theposStereo-200)/100}% + \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\posStereo, anchor=center] {\stereotype}}% + \else% + \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posStereo, anchor=center] {\stereotype}}% + \fi% + \fi% + \fi% + % + \ifthenelse{\thepos=300\OR\thepos=100}{% + \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }% + }% + }% + }{}% + % + \ifthenelse{\thepos=200}{% + \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\thepos>300% + \pgfmathsetmacro{\pos}{(\thepos-300)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% + }% + \else% + \ifnum\thepos<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% + }% + \else% + \ifnum\thepos>200% + \pgfmathsetmacro{\pos}{(\thepos-200)/100}% + \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% + }% + \else% + \pgfmathsetmacro{\pos}{(\thepos-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% + }% + \fi% + \fi% + \fi% + % + \ifthenelse{\theposT=300\OR\theposT=100}{% + \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }% + }% + }% + }{}% + \ifthenelse{\theposT=200}{% + \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{bottom}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% + \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirend}{left}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\theposT>300% + \pgfmathsetmacro{\posT}{(\theposT-300)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% + }% + \else% + \ifnum\theposT<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% + }% + \else% + \ifnum\theposT>200% + \pgfmathsetmacro{\posT}{(\theposT-200)/100}% + \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% + }% + \else% + \pgfmathsetmacro{\posT}{(\theposT-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% + }% + \fi% + \fi% + \fi% + \else% + \ifnum\theposStereo>200% + \pgfmathsetmacro{\posStereo}{(\theposStereo-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \else% + \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \fi% + \fi% + % + \ifthenelse{\thepos=100}{% + \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }% + }% + }% + }{}% + % + \ifthenelse{\thepos=200}{% + \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\thepos>200% + \pgfmathsetmacro{\pos}{(\thepos-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% + }% + \else% + \ifnum\thepos<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% + }% + \else% + \pgfmathsetmacro{\pos}{(\thepos-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% + }% + \fi% + \fi% + % + \ifthenelse{\theposT=100}{% + \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }% + }% + }% + }{}% + % + \ifthenelse{\theposT=200}{% + \ifthenelse{\equal{\tikzumlrecdirstart}{right}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{left}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlrecdirstart}{top}}{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\endangle<\startangle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\theposT>200% + \pgfmathsetmacro{\posT}{(\theposT-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% + }% + \else% + \ifnum\theposT<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% + }% + \else% + \pgfmathsetmacro{\posT}{(\theposT-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% + }% + \fi% + \fi% + \fi% + % + \ifthenelse{\equal{\tikzumlrecdirstart}{\tikzumlrecdirend}}{% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\startangle) -- \tikzumlFirstArc (\relationName-2.center) -- \tikzumlMidOneArc (\relationName-4.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\endangle) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) (\relationName-4) (\relationName-5)}% + \fi% + }{% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\startangle) -- \tikzumlFirstArc (\relationName-2.center) -- \tikzumlMidOneArc (\relationName-4.center) -- \tikzumlMidTwoArc (\relationName-6.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\endangle) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) (\relationName-4) (\relationName-5) (\relationName-6) (\relationName-7)}% + \fi% + }% + }{}% + }% + }{% + \def\arcNum{1}% + \def\arcNumT{1}% + % + \node[inner sep=0] (\relationName-1) at (\relationName-middle) {};% + \xdef\tikzumlLastArc{node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity}% + node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT}% + node[pos=\positionStereotype, anchor=center] {\stereotype} }% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) }% + \fi% + }% + }{% + % first vertical then horizontal line + \ifthenelse{\equal{\geometry}{|-}}% + {% + \def\tikzumlControlNodesNum{1}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\relationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-3, anchor=center]{} }% + % + \begin{pgfonlayer}{connections}% + \node[inner sep=0] (\relationName-2) at (\tikzumlSrcClassNodeName\tikzumlSrcAnchor |- \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% + \end{pgfonlayer}% + % + \ifnum\theposStereo>100% + \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \else% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \fi% + % + \ifnum\thepos>100% + \pgfmathsetmacro{\pos}{(\thepos-100)/100}% + \def\arcNum{2}% + \else% + \def\arcNum{1}% + \ifnum\thepos=100% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + \fi% + \fi% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + % + \ifnum\theposT>100% + \pgfmathsetmacro{\posT}{(\theposT-100)/100}% + \def\arcNumT{2}% + \else% + \def\arcNumT{1}% + \ifnum\theposT=100% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + \fi% + \fi% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlFirstArc (\relationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) }% + \fi% + }{% + % first horizontal then vertical line + \ifthenelse{\equal{\geometry}{-|}}{% + \def\tikzumlControlNodesNum{1}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\relationName-1, anchor=center]{} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-3, anchor=center] {} }% + % + \begin{pgfonlayer}{connections}% + \node[inner sep=0] (\relationName-2) at (\tikzumlSrcClassNodeName\tikzumlSrcAnchor -| \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% + \end{pgfonlayer}% + % + \ifnum\theposStereo>100% + \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \else% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \fi% + % + \ifnum\thepos>100% + \pgfmathsetmacro{\pos}{(\thepos-100)/100}% + \def\arcNum{2}% + \else% + \def\arcNum{1}% + \ifnum\thepos=100% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + \fi% + \fi% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + % + \ifnum\theposT>100% + \pgfmathsetmacro{\posT}{(\theposT-100)/100}% + \def\arcNumT{2}% + \else% + \def\arcNumT{1}% + \ifnum\theposT=100% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + \fi% + \fi% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlFirstArc (\relationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) }% + \fi% + }{% + % first vertical, then horizontal, finally vertical line + \ifthenelse{\equal{\geometry}{|-|}}{% + \def\tikzumlControlNodesNum{2}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\relationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-5, anchor=center] {} }% + \def\tikzumlMidOneArc{ }% + % + \begin{pgfonlayer}{connections}% + % + \ifthenelse{\equal{\armO}{auto}}{% + \ifthenelse{\equal{\armT}{auto}}{% + \node[inner sep=0] (\relationName-3) at (\relationName-middle) {};% + \node[inner sep=0] (\relationName-2) at (\tikzumlSrcClassNodeName\tikzumlSrcAnchor |- \relationName-3) {};% + \node[inner sep=0] (\relationName-4) at (\relationName-3 -| \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% + }{% + \draw (\tikzumlDestClassNodeName\tikzumlDestAnchor)+(0,\armT) node[inner sep=0, name=\relationName-4] {};% + \node[inner sep=0] (\relationName-2) at (\relationName-4 -| \tikzumlSrcClassNodeName\tikzumlSrcAnchor) {};% + \node[inner sep=0] (\relationName-3) at (barycentric cs:\relationName-2=0.5,\relationName-4=0.5) {};% + }% + }{% + \draw (\tikzumlSrcClassNodeName\tikzumlSrcAnchor)+(0,\armO) node[inner sep=0, name=\relationName-2] {};% + \node[inner sep=0] (\relationName-4) at (\relationName-2 -| \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% + \node[inner sep=0] (\relationName-3) at (barycentric cs:\relationName-2=0.5,\relationName-4=0.5) {};% + }% + \end{pgfonlayer}% + % + \ifnum\theposStereo>200% + \pgfmathsetmacro{\posStereo}{(\theposStereo-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \else% + \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \fi% + \fi% + % + \ifthenelse{\thepos=200\OR\thepos=100}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{}% + % + \ifthenelse{\thepos>200}{% + \pgfmathsetmacro{\pos}{(\thepos-200)/100}% + \def\arcNum{3}% + }{% + \ifthenelse{\thepos<100}{% + \def\arcNum{1}% + }{% + \pgfmathsetmacro{\pos}{(\thepos-100)/100}% + \def\arcNum{2}% + }% + }% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + \ifnum\arcNum=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + % + \ifthenelse{\theposT=200\OR\theposT=100}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{}% + % + \ifthenelse{\theposT>200}{% + \pgfmathsetmacro{\posT}{(\theposT-200)/100}% + \def\arcNumT{3}% + }{% + \ifthenelse{\theposT<100}{% + \def\arcNumT{1}% + }{% + \pgfmathsetmacro{\posT}{(\theposT-100)/100}% + \def\arcNumT{2}% + }% + }% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + \ifnum\arcNumT=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlFirstArc (\relationName-2.base) -- \tikzumlMidOneArc (\relationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) (\relationName-4) (\relationName-5) }% + \fi% + }{% + % first horizontal, then vertical, finally horizontal line + \ifthenelse{\equal{\geometry}{-|-}}{% + \def\tikzumlControlNodesNum{2}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\relationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\relationName-5, anchor=center] {} }% + \def\tikzumlMidOneArc{}% + % + \begin{pgfonlayer}{connections}% + % + \ifthenelse{\equal{\armO}{auto}}{% + \ifthenelse{\equal{\armT}{auto}}{% + \node[inner sep=0] (\relationName-3) at (\relationName-middle) {};% + \node[inner sep=0] (\relationName-2) at (\tikzumlSrcClassNodeName\tikzumlSrcAnchor -| \relationName-3) {};% + \node[inner sep=0] (\relationName-4) at (\relationName-3 |- \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% + }{% + \draw (\tikzumlDestClassNodeName\tikzumlDestAnchor)+(\armT,0) node[inner sep=0, name=\relationName-4] {};% + \node[inner sep=0] (\relationName-2) at (\relationName-4 |- \tikzumlSrcClassNodeName\tikzumlSrcAnchor) {};% + \node[inner sep=0] (\relationName-3) at (barycentric cs:\relationName-2=0.5,\relationName-4=0.5) {};% + }% + }{% + \draw (\tikzumlSrcClassNodeName\tikzumlSrcAnchor)+(\armO,0) node[inner sep=0, name=\relationName-2] {};% + \node[inner sep=0] (\relationName-4) at (\relationName-2 |- \tikzumlDestClassNodeName\tikzumlDestAnchor) {};% + \node[inner sep=0] (\relationName-3) at (barycentric cs:\relationName-2=0.5,\relationName-4=0.5) {};% + }% + \end{pgfonlayer}% + % + % + \ifnum\theposStereo>200% + \pgfmathsetmacro{\posStereo}{(\theposStereo-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \else% + \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \fi% + \fi% + % + \ifthenelse{\thepos=200\OR\thepos=100}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{}% + % + \ifthenelse{\thepos>200}{% + \pgfmathsetmacro{\pos}{(\thepos-200)/100}% + \def\arcNum{3}% + }{% + \ifthenelse{\thepos<100}{% + \def\arcNum{1}% + }{% + \pgfmathsetmacro{\pos}{(\thepos-100)/100}% + \def\arcNum{2}% + }% + }% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + \ifnum\arcNum=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + % + \ifthenelse{\theposT=200\OR\theposT=100}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{}% + % + \ifthenelse{\theposT>200}{% + \pgfmathsetmacro{\posT}{(\theposT-200)/100}% + \def\arcNumT{3}% + }{% + \ifthenelse{\theposT<100}{% + \def\arcNumT{1}% + }{% + \pgfmathsetmacro{\posT}{(\theposT-100)/100}% + \def\arcNumT{2}% + }% + }% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + \ifnum\arcNumT=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlFirstArc (\relationName-2.base) -- \tikzumlMidOneArc (\relationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\relationName-1) (\relationName-2) (\relationName-3) (\relationName-4) (\relationName-5) }% + \fi% + }{% + \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% + }% + }% + }% + }% + }% + % + \begin{pgfonlayer}{connections}% + \draw[auto, \style, font=\tikzumlfont] \tikzumlPath ;% + \end{pgfonlayer}% + % + \stepcounter{tikzumlRelationNum}% +}% + +% shortcuts of \umlrelation +\newcommand{\umlHVrelation}[3][]{% + \pgfkeys{/tikzuml/HVrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVrelation, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/HVrelation/.cd, #1}% + \umlrelation[geometry=-|, #1]{#2}{#3}% +}% + +\newcommand{\umlVHrelation}[3][]{% + \pgfkeys{/tikzuml/VHrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHrelation, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/VHrelation/.cd, #1}% + \umlrelation[geometry=|-, #1]{#2}{#3}% +}% + +\newcommand{\umlHVHrelation}[3][]{% + \pgfkeys{/tikzuml/HVHrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHrelation, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/HVHrelation/.cd, #1}% + \umlrelation[geometry=-|-, #1]{#2}{#3}% +}% + +\newcommand{\umlVHVrelation}[3][]{% + \pgfkeys{/tikzuml/VHVrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVrelation, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/VHVrelation/.cd, #1}% + \umlrelation[geometry=|-|, #1]{#2}{#3}% +}% + +% shortcuts for relations +\newcommand{\umlinherit}[3][]{\umlrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlimpl}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlreal}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlassoc}[3][]{\umlrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umluniassoc}[3][]{\umlrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlaggreg}[3][]{\umlrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umluniaggreg}[3][]{\umlrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlcompo}[3][]{\umlrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlunicompo}[3][]{\umlrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlimport}[3][]{\umlrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umldep}[3][]{\umlrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlfriend, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% + +\newcommand{\umlHVinherit}[3][]{\umlHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlHVimpl}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVreal}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVassoc}[3][]{\umlHVrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlHVuniassoc}[3][]{\umlHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlHVaggreg}[3][]{\umlHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVuniaggreg}[3][]{\umlHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVcompo}[3][]{\umlHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVunicompo}[3][]{\umlHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVimport}[3][]{\umlHVrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlHVdep}[3][]{\umlHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlHVfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% + +\newcommand{\umlVHinherit}[3][]{\umlVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlVHimpl}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHreal}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHassoc}[3][]{\umlVHrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlVHuniassoc}[3][]{\umlVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlVHaggreg}[3][]{\umlVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHuniaggreg}[3][]{\umlVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHcompo}[3][]{\umlVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHunicompo}[3][]{\umlVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHimport}[3][]{\umlVHrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlVHdep}[3][]{\umlVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlVHfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% + +\newcommand{\umlHVHinherit}[3][]{\umlHVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlHVHimpl}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVHreal}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVHassoc}[3][]{\umlHVHrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlHVHuniassoc}[3][]{\umlHVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlHVHaggreg}[3][]{\umlHVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVHuniaggreg}[3][]{\umlHVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVHcompo}[3][]{\umlHVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVHunicompo}[3][]{\umlHVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVHimport}[3][]{\umlHVHrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlHVHdep}[3][]{\umlHVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlHVHfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=-|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% + +\newcommand{\umlVHVinherit}[3][]{\umlVHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlVHVimpl}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHVreal}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHVassoc}[3][]{\umlVHVrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlVHVuniassoc}[3][]{\umlVHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlVHVaggreg}[3][]{\umlVHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHVuniaggreg}[3][]{\umlVHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHVcompo}[3][]{\umlVHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHVunicompo}[3][]{\umlVHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHVimport}[3][]{\umlVHVrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlVHVdep}[3][]{\umlVHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlVHVfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=|-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% + +% define a node +\newcommand{\umlnode}[2]{% + \node (#2) at (#1) {};% +}% + +% main command to define a relation between two classes through a control node +% args : src class +% control node +% dest class +% optional : geometry of the line +% barycentric weight +% name of the src class type attribute defined by the relation +% multiplicity of the src class type attribute defined by the relation +% position on the relation +% text justification on the relation +% name of the dest class type attribute defined by the relation +% multiplicity of the dest class type attribute defined by the relation +% position on the relation +% border anchors +% text justification on the relation +% start angle, end angle and size of the relation (only if recursive) +% stereotype of the relation +% style of the relation (association, aggregation, composition, inherit, ...) +\newcommand{\umlCNrelation}[4][]% +{% + \pgfkeys{/tikzuml/relation/.cd, arg1/.initial={}, arg2/.initial={}, arg/.initial={},% + mult1/.initial={}, mult2/.initial={}, mult/.initial={},% + pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial={tikzumlEmpty},% + align1/.initial={}, align2/.initial={}, align/.initial={},% + anchor1/.initial={tikzumlempty}, anchor2/.initial={tikzumlempty},% + stereo/.initial={}, pos stereo/.initial=1,% + style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlCNrelation, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/relation/.cd,#1}% + \pgfkeys{/tikzuml/relation/.cd, arg1/.get=\attrName, arg2/.get=\attrNameTO, arg/.get=\attrNameTT,% + mult1/.get=\multiplicity, mult2/.get=\multiplicityTO, mult/.get=\multiplicityTT,% + pos1/.get=\position, pos2/.get=\positionTO, pos/.get=\positionTT,% + align1/.get=\align, align2/.get=\alignTO, align/.get=\alignTT,% + anchor1/.get=\tikzumlSrcAnchor, anchor2/.get=\tikzumlDestAnchor,% + stereo/.get=\stereo, pos stereo/.get=\positionStereotype,% + style/.get=\style, name/.get=\relationName}% + % + % managing \_ in class names for node names + \def\tikzumlSrcClassName{#2}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x% + % + \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName] + % + \def\tikzumlDestClassName{#4}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x% + % + \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName] + % + % managing alias keys + \def\attrNameT{\attrNameTO\attrNameTT}% + \def\multiplicityT{\multiplicityTO\multiplicityTT}% + \def\alignT{\alignTO\alignTT}% + \def\orientationT{\orientationTO\orientationTT}% + % + \ifthenelse{\equal{\positionTT}{tikzumlEmpty}}{% + \def\positionT{\positionTO}% + }{% + \def\positionT{\positionTT}% + }% + % + \def\attrAlign{}% + \def\multAlign{}% + \def\attrAlignT{}% + \def\multAlignT{}% + % + \ifthenelse{\equal{\align}{left}}{% + \def\attrAlign{above right}% + \def\multAlign{below right}% + }{% + \ifthenelse{\equal{\align}{right}}{% + \def\attrAlign{above left}% + \def\multAlign{below left}% + }{}% + }% + % + \ifthenelse{\equal{\alignT}{left}}{% + \def\attrAlignT{above right}% + \def\multAlignT{below right}% + }{% + \ifthenelse{\equal{\alignT}{right}}{% + \def\attrAlignT{above left}% + \def\multAlignT{below left}% + }{}% + }% + % + % def stereotype + \ifthenelse{\equal{\stereo}{}}{% + \def\stereotype{}% + }{% + \def\stereotype{$<<$\stereo$>>$}% + }% + % + % def anchors macros + \ifthenelse{\equal{\tikzumlSrcAnchor}{tikzumlempty}}{% + \def\tikzumlSrcAnchor{}% + }{% + \let\tikzumlSrcAnchorold\tikzumlSrcAnchor% + \def\tikzumlSrcAnchor{.\tikzumlSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlDestAnchor}{tikzumlempty}}{% + \def\tikzumlDestAnchor{}% + }{% + \let\tikzumlDestAnchorold\tikzumlDestAnchor% + \def\tikzumlDestAnchor{.\tikzumlDestAnchorold}% + }% + % + \setcounter{pos}{100*\real{\position}}% + \setcounter{posT}{100*\real{\positionT}}% + \setcounter{posStereo}{100*\real{\positionStereotype}}% + % + \def\pos{\position}% + \def\posT{\positionT}% + \def\posStereo{\positionStereotype}% + % + % straight line + \def\tikzumlControlNodesNum{1}% + % + \def\tikzumlFirstArc{node[midway, name=\relationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, name=\relationName-3, anchor=center]{} }% + \def\posAttrName{}% + \def\posMultiplicity{}% + \def\posAttrNameT{}% + \def\posMultiplicityT{}% + % + \begin{pgfonlayer}{connections}% + \node (\relationName-2) at (#3) {};% + \end{pgfonlayer}% + % + \ifnum\theposStereo>100% + \pgfmathsetmacro{\posStereo}{(\theposStereo-100)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \else% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posStereo, anchor=center] {\stereotype} }% + \fi% + % + \ifnum\thepos>100% + \pgfmathsetmacro{\pos}{(\thepos-100)/100}% + \def\arcNum{2}% + \else% + \def\arcNum{1}% + \ifnum\thepos=100% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + \fi% + \fi% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\pos, \posAttrName, \attrAlign] {\attrName}% + node[pos=\pos, swap, \posMultiplicity, \multAlign] {\multiplicity} }% + \fi% + % + \ifnum\theposT>100% + \pgfmathsetmacro{\posT}{(\theposT-100)/100}% + \def\arcNumT{2}% + \else% + \def\arcNumT{1}% + \ifnum\theposT=100% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + \fi% + \fi% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\posT, \posAttrNameT, \attrAlignT] {\attrNameT}% + node[pos=\posT, swap, \posMultiplicityT, \multAlignT] {\multiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlSrcAnchor) -- \tikzumlFirstArc (\relationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlDestAnchor) }% + + \begin{pgfonlayer}{connections}% + \draw[auto, \style, font=\tikzumlfont] \tikzumlPath ;% + \end{pgfonlayer}% + % + \stepcounter{tikzumlRelationNum}% +}% + +% shortcuts for cnrelations +\newcommand{\umlCNinherit}[4][]{\umlCNrelation[style={tikzuml inherit style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNimpl}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNreal}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNassoc}[4][]{\umlCNrelation[style={tikzuml association style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNuniassoc}[4][]{\umlCNrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNaggreg}[4][]{\umlCNrelation[style={tikzuml aggregation style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNuniaggreg}[4][]{\umlCNrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNcompo}[4][]{\umlCNrelation[style={tikzuml composition style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNunicompo}[4][]{\umlCNrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNimport}[4][]{\umlCNrelation[style={tikzuml import style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNdep}[4][]{\umlCNrelation[style={tikzuml dependency style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNfriend}[4][]{% + \pgfkeys{/tikzuml/friendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlCNfriend, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlCNrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% +}% + +% define a note +% arg : attached class +% label of the note +% optional : x,y coordinates of the note +% width of the note +% draw, fill, text colors +\newcommand{\umlnote}[3][]{% ajouter options weight, arm, anchor1, anchor2 + \pgfkeys{/tikzuml/note/.cd, x/.initial=0, y/.initial=0, width/.initial=3cm, geometry/.initial=--,% + weight/.initial=0.5, arm/.initial={auto}, anchor1/.initial={tikzumlEmpty}, anchor2/.initial={tikzumlEmpty},% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillnotecolor, text/.initial=\tikzumltextcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlnote, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/note/.cd, #1}% + \pgfkeys{/tikzuml/note/.cd, x/.get=\tikzumlnoteX, y/.get=\tikzumlnoteY, width/.get=\notetextwidth, geometry/.get=\tikzumlnotegeometry,% + weight/.get=\tikzumlnoteweight, arm/.get=\tikzumlnotearm, anchor1/.get=\tikzumlnoteSrcAnchor, anchor2/.get=\tikzumlnoteDestAnchor,% + draw/.get=\tikzumlnotedraw, fill/.get=\tikzumlnotefill, text/.get=\tikzumlnotetext}% + % + \def\tikzumlClassName{#2}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x% + % + % def anchors macros + \ifthenelse{\equal{\tikzumlnoteSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlnoteSrcAnchor{}% + }{% + \let\tikzumlnoteSrcAnchorold\tikzumlnoteSrcAnchor% + \def\tikzumlnoteSrcAnchor{.\tikzumlnoteSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlnoteDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlnoteDestAnchor{}% + }{% + \let\tikzumlnoteDestAnchorold\tikzumlnoteDestAnchor% + \def\tikzumlnoteDestAnchor{.\tikzumlnoteDestAnchorold}% + }% + % + \node[text=\tikzumlnotetext, text width=\notetextwidth, font=\tikzumlfont, outer sep=0, inner xsep=1ex, inner ysep=3ex] (note-\thetikzumlNoteNum-coord) at (\tikzumlnoteX, \tikzumlnoteY) {#3};% + \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-right-top, below=2ex, inner sep=0] {};% + \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-top-right, left=2ex, inner sep=0] {};% + \draw[draw=\tikzumlnotedraw, fill=\tikzumlnotefill] (note-\thetikzumlNoteNum-coord.south west) -- (note-\thetikzumlNoteNum-coord.south east) -- (note-\thetikzumlNoteNum-right-top.base) -- (note-\thetikzumlNoteNum-top-right.base) -- (note-\thetikzumlNoteNum-coord.north west) -- cycle;% + \node[text=\tikzumlnotetext, text width=\notetextwidth, outer sep=0, inner xsep=1ex, inner ysep=3ex, font=\tikzumlfont] (note-\thetikzumlNoteNum) at (note-\thetikzumlNoteNum-coord) {#3};% + \begin{scope}[shift=(note-\thetikzumlNoteNum.north east)]% + \draw[draw=\tikzumlnotedraw, fill=\tikzumlnotefill] (-2ex,-2ex) -- ++(2ex,0) -- ++(-2ex,2ex) -- cycle;% + \end{scope}% + % + \pgfmathsetmacro{\tikzumlnoteweightT}{1-\tikzumlnoteweight} + \node (note-\thetikzumlNoteNum-middle) at (barycentric cs:note-\thetikzumlNoteNum-coord=\tikzumlnoteweight,\tikzumlClassNodeName=\tikzumlnoteweightT) {};% + % + \ifthenelse{\equal{\tikzumlnotegeometry}{--}\OR\equal{\tikzumlnotegeometry}{-|}\OR\equal{\tikzumlnotegeometry}{|-}}{% + \edef\tikzumlnotepath{\tikzumlnotegeometry} + }{% + \ifthenelse{\equal{\tikzumlnotegeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlnotearm}{auto}}{% + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlassocclassSrcAnchor -| note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center |- \tikzumlClassNodeName\tikzumlassocclassDestAnchor) --}% + }{% + \draw (note-\thetikzumlNoteNum-coord\tikzumlnoteSrcAnchor)+(\tikzumlnotearm,0) node[name=note-\thetikzumlNoteNum-tmp] {}; + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) |-}% + }% + }{% + \ifthenelse{\equal{\tikzumlnotegeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlnotearm}{auto}}{% + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlassocclassSrcAnchor |- note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center -| \tikzumlClassNodeName\tikzumlassocclassDestAnchor) --}% + }{% + \draw (note-\thetikzumlNoteNum-coord\tikzumlnoteSrcAnchor)+(0,\tikzumlnotearm) node[name=note-\thetikzumlNoteNum-tmp] {}; + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) -|}% + }% + + }{% + \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% + }% + }% + }% + % + \begin{pgfonlayer}{connections}% + \draw[dashed] (note-\thetikzumlNoteNum-coord\tikzumlnoteSrcAnchor) \tikzumlnotepath (\tikzumlClassNodeName\tikzumlnoteDestAnchor);% + \end{pgfonlayer}% + % + \stepcounter{tikzumlNoteNum}% +}% + +% shortcuts for note with geometry +\newcommand{\umlHVnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVnote, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=-|, #1]{#2}{#3}% +}% +\newcommand{\umlVHnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHnote, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=|-, #1]{#2}{#3}% +}% +\newcommand{\umlVHVnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVnote, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=|-|, #1]{#2}{#3}% +}% +\newcommand{\umlHVHnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHnote, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=-|-, #1]{#2}{#3}% +}% + +% define a uml association class (command) +% args : name of the class +% attributes of the class +% operations of the class +% optional : x,y coordinates of the class +% width of the class node +% type of class (class, interface, typedef, enum) +% template parameters +% draw, fill, text colors +\newcommand{\umlassocclass}[5][]{% + \pgfkeys{/tikzuml/assocclass/.cd, x/.initial=0, y/.initial=0, width/.initial=10ex, type/.initial=class, template/.initial={}, name/.initial={tikzumlEmpty}, geometry/.initial=--,% + weight/.initial=0.5, arm/.initial={auto}, anchor1/.initial={tikzumlEmpty}, anchor2/.initial={tikzumlEmpty},% + draw/.initial=\tikzumldrawcolor, fill template/.initial=\tikzumlfilltemplatecolor, fill/.initial=\tikzumlfillclasscolor,% + text/.initial=\tikzumltextcolor, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlassocclass, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/assocclass/.cd,#1}% + \pgfkeys{/tikzuml/assocclass/.cd, x/.get=\umlassocclassX, y/.get=\umlassocclassY, width/.get=\umlassocclassMinimumWidth, type/.get=\umlassocclassType, template/.get=\umlassocclassTemplateParam,% + name/.get=\umlassocclassName, geometry/.get=\tikzumlassocclassgeometry,% + weight/.get=\tikzumlassocclassweight, arm/.get=\tikzumlassocclassarm, anchor1/.get=\tikzumlassocclassSrcAnchor, anchor2/.get=\tikzumlassocclassDestAnchor,% + draw/.get=\tikzumlassocclassdraw, fill/.get=\tikzumlassocclassfill, text/.get=\tikzumlassocclasstext, fill template/.get=\tikzumlassocclasstemplate}% + % + \ifthenelse{\equal{\umlassocclassType}{class}\OR\equal{\umlassocclassType}{abstract}}{% + \def\tikzumlAssocClassType{}% + }{% + \def\tikzumlAssocClassType{$<<$\umlassocclassType$>>$ \\}% + }% + % + \ifthenelse{\equal{\umlassocclassTemplateParam}{}}{% + \def\tikzumlAssocClassVPadding{}% + \def\tikzumlAssocClassHPadding{}% + }{% + \def\tikzumlAssocClassVPadding{\vspace{0.1em} \\}% + \def\tikzumlAssocClassHPadding{\hspace{0.5ex} $ $}% + }% + % + \def\tikzumlAssocClassName{#2}% + \def\tikzumlAssocClassRelationName{#3}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssocClassNodeName{\tikzumlAssocClassName}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssocClassRelationNodeName{\tikzumlAssocClassRelationName}}\x% + % + \ifthenelse{\equal{\umlassocclassName}{tikzumlEmpty}}{}{% + \def\tikzumlAssocClassNodeName{\umlassocclassName}% + }% + % + \StrSubstitute{\tikzumlAssocClassNodeName}{:}{@COLON@}[\tikzumlAssocClassNodeName] + % + \ifthenelse{\equal{\umlassocclassType}{abstract}}{% + \let\tikzumlAssocClassNameOld\tikzumlAssocClassName% + \def\tikzumlAssocClassName{{\it \tikzumlAssocClassNameOld}}% + }{}% + % + \def\tikzumlAssocClassPos{\umlassocclassX,\umlassocclassY}% + \def\tikzumlAssocClassAttributes{#4}% + \def\tikzumlAssocClassOperations{#5}% + % + % def anchors macros + \ifthenelse{\equal{\tikzumlassocclassSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlassocclassSrcAnchor{}% + }{% + \let\tikzumlassocclassSrcAnchorold\tikzumlassocclassSrcAnchor% + \def\tikzumlassocclassSrcAnchor{.\tikzumlassocclassSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlassocclassDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlassocclassDestAnchor{}% + }{% + \let\tikzumlassocclassDestAnchorold\tikzumlassocclassDestAnchor% + \def\tikzumlassocclassDestAnchor{.\tikzumlassocclassDestAnchorold}% + }% + % + \node[tikzuml class style, draw=\tikzumlassocclassdraw, fill=\tikzumlassocclassfill, text=\tikzumlassocclasstext, font=\tikzumlfont, minimum width=\umlassocclassMinimumWidth] (\tikzumlAssocClassNodeName) at (\tikzumlAssocClassPos) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlAssocClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlAssocClassOperations% + \end{tabular}% + };% + % + \ifthenelse{\equal{\umlassocclassTemplateParam}{}}{}{% + \draw (\tikzumlAssocClassNodeName.north east) node[tikzuml template style, name=\tikzumlAssocClassNodeName-template, draw=\tikzumlassocclassdraw, fill=\tikzumlassocclasstemplate, text=\tikzumlassocclasstext, font=\tikzumlfont] {\umlassocclassTemplateParam};% + }% + % + \pgfmathsetmacro{\tikzumlassocclassweightT}{1-\tikzumlassocclassweight} + \node (\tikzumlAssocClassNodeName-middle) at (barycentric cs:\tikzumlAssocClassNodeName=\tikzumlnoteweight,\tikzumlAssocClassRelationNodeName=\tikzumlnoteweightT) {};% + % + \ifthenelse{\equal{\tikzumlassocclassgeometry}{--}\OR\equal{\tikzumlassocclassgeometry}{-|}\OR\equal{\tikzumlassocclassgeometry}{|-}}{% + \edef\tikzumlassocclasspath{\tikzumlassocclassgeometry} + }{% + \ifthenelse{\equal{\tikzumlassocclassgeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlassocclassarm}{auto}}{% + \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlassocclassSrcAnchor -| \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center |- \tikzumlAssocClassRelationNodeName\tikzumlassocclassDestAnchor) --}% + }{% + \draw (\tikzumlAssocClassNodeName\tikzumlassocclassSrcAnchor)+(\tikzumlassocclassarm,0) node[name=\tikzumlAssocClassNodeName-tmp] {}; + \edef\tikzumlnotepath{-- (\tikzumlAssocClassNodeName-tmp.center) |-}% + }% + }{% + \ifthenelse{\equal{\tikzumlassocclassgeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlassocclassarm}{auto}}{% + \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlassocclassSrcAnchor |- \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center -| \tikzumlAssocClassRelationNodeName\tikzumlassocclassDestAnchor) --}% + }{% + \draw (\tikzumlAssocClassNodeName\tikzumlassocclassSrcAnchor)+(0,\tikzumlassocclassarm) node[name=\tikzumlAssocClassNodeName-tmp] {}; + \edef\tikzumlassocclasspath{-- (\thetikzumlAssocClassNodeName-tmp.center) -|}% + }% + + }{% + \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% + }% + }% + }% + % + \begin{pgfonlayer}{connections}% + \draw[dashed] (\tikzumlAssocClassNodeName\tikzumlassocclassSrcAnchor) \tikzumlassocclasspath (\tikzumlAssocClassRelationNodeName\tikzumlassocclassDestAnchor);% + \end{pgfonlayer}% + % + + + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \ifthenelse{\equal{\umlassocclassTemplateParam}{}}{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName)(\tikzumlAssocClassNodeName-middle)}% + }{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName) (\tikzumlAssocClassNodeName-template)(\tikzumlAssocClassNodeName-middle)}% + }% + \stepcounter{tikzumlPackageClassNum}% + \fi% +}% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% use case diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\tikzstyle{tikzuml usecase style}=[ellipse, text centered]% +\tikzstyle{tikzuml actor style}=[ellipse, inner sep=0, outer sep=0]% + +\newcounter{tikzumlSystemUseCaseNum}% +\newcounter{tikzumlSystemLevel}% +\newcounter{tikzumlUseCaseNum}% +\newcounter{tikzumlActorNum}% + +% define a system +% arg : name +% optional : x, y coordinates of the system +% draw, fill, text colors +\newenvironment{umlsystem}[2][]{% + \gdef\tikzumlSystemFit{}% + \def\tikzumlSystemName{#2}% + \setcounter{tikzumlSystemUseCaseNum}{0}% + % + \pgfkeys{/tikzuml/system/.cd, x/.initial=0, y/.initial=0, x/.default=0, y/.default=0,% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillsystemcolor, text/.initial=\tikzumltextcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlsystem, invalid option \keyname}% + }}% + % + \pgfkeys{/tikzuml/system/.cd, #1}% + \pgfkeys{/tikzuml/system/.cd, x/.get=\xshift, y/.get=\yshift, draw/.get=\tikzumlsystemdraw, fill/.get=\tikzumlsystemfill, text/.get=\tikzumlsystemtext}% + % + \stepcounter{tikzumlSystemLevel}% + % + \begin{scope}[xshift=\xshift cm, yshift=\yshift cm]% +}{% + \addtocounter{tikzumlSystemLevel}{-1}% + % if contains no usecase, one define a fictive node to enable the fit option + \ifnum\c@tikzumlSystemUseCaseNum=0% + \node[inner xsep=10ex, inner ysep=1em] (\tikzumlSystemName-root) at (0,0) {};% + \xdef\tikzumlSystemFit{(\tikzumlSystemName-root)}% + \fi% + % + \begin{pgfonlayer}{background}% + \node[inner ysep=1em, inner xsep=2ex, fit = \tikzumlSystemFit] (\tikzumlSystemName-tmp) {};% + \node[text=\tikzumlsystemtext, font=\tikzumlfont] (\tikzumlSystemName-caption-tmp) at (\tikzumlSystemName-tmp.north) {\tikzumlSystemName};% + \node[draw=\tikzumlsystemdraw, fill=\tikzumlsystemfill, text=\tikzumlsystemtext, font=\tikzumlfont, inner ysep=1em, inner xsep=2ex, fit = (\tikzumlSystemName-tmp) (\tikzumlSystemName-caption-tmp)] (\tikzumlSystemName) {};% + \node[text=\tikzumlsystemtext, font=\tikzumlfont] (\tikzumlSystemName-caption) at (\tikzumlSystemName-caption-tmp.north) {\tikzumlSystemName};% + \end{pgfonlayer}% + \end{scope}% + % +}% + +% define a use case +% arg : label of the use case +% optional : x, y coordinates of the use case +% name of the node +% draw, fill, text colors +\newcommand{\umlusecase}[2][]{% + \stepcounter{tikzumlUseCaseNum}% + \pgfkeys{/tikzuml/usecase/.cd, x/.initial=0, y/.initial=0, width/.initial=auto, name/.initial=usecase-\thetikzumlUseCaseNum,% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillusecasecolor, text/.initial=\tikzumltextcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlusecase, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/usecase/.cd, #1}% + \pgfkeys{/tikzuml/usecase/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlusecasetextwidth, name/.get=\usecaseName,% + draw/.get=\tikzumlusecasedraw, fill/.get=\tikzumlusecasefill, text/.get=\tikzumlusecasetext}% + % + \def\tikzumlUseCaseText{#2}% + % + \def\tikzumlUseCasePos{\posx,\posy}% + % + \ifthenelse{\equal{\tikzumlusecasetextwidth}{auto}}{% + \node[tikzuml usecase style, draw=\tikzumlusecasedraw, fill=\tikzumlusecasefill, text=\tikzumlusecasetext, font=\tikzumlfont] (\usecaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};% + }{% + \node[tikzuml usecase style, draw=\tikzumlusecasedraw, fill=\tikzumlusecasefill, text=\tikzumlusecasetext, font=\tikzumlfont, text width=\tikzumlusecasetextwidth] (\usecaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};% + }% + % + % add to fit + \ifnum\c@tikzumlSystemLevel>0% + \let\tikzumlSystemFitOld\tikzumlSystemFit% + \xdef\tikzumlSystemFit{\tikzumlSystemFitOld (\usecaseName)}% + \stepcounter{tikzumlSystemUseCaseNum}% + \fi% +}% + +% define the actor symbol +% optional : global tikzpicture styles +\newcommand{\picturedactor}[1]{% + \pgfkeys{/tikzuml/picactor/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/picactor/.cd,#1}% + \pgfkeys{/tikzuml/picactor/.cd, scale/.get=\tikzumlpicactorscale}% + % + \begin{tikzpicture}[#1] + \coordinate (head) at (0,4ex); + \coordinate (left-hand) at (-2ex,2ex); + \coordinate (right-hand) at (2ex,2ex); + \coordinate (left-foot) at (-2ex,-2ex); + \coordinate (right-foot) at (2ex,-2ex); + \coordinate (empty) at (0,-3ex); + \draw (empty) (0,0) -- (head); + \draw (left-hand) -- (right-hand); + \draw (0,0) -- (left-foot) (0,0) -- (right-foot); + \node[fill, draw, circle, inner sep=\tikzumlpicactorscale*0.3333ex, minimum size=\tikzumlpicactorscale*2ex] at (head) {}; + \end{tikzpicture} +}% + +% define an actor +% arg : var name +% optional : x, y coordinates of the actor +% name of the node +% draw, text colors +\newcommand{\umlactor}[2][]{% + \stepcounter{tikzumlActorNum}% + \pgfkeys{/tikzuml/actor/.cd, x/.initial=0, y/.initial=0, scale/.initial=1, below/.initial=0.5cm,% + draw/.initial=\tikzumldrawcolor, text/.initial=\tikzumltextcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlactor, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/actor/.cd, #1}% + \pgfkeys{/tikzuml/actor/.cd, x/.get=\posx, y/.get=\posy, scale/.get=\tikzumlactorscale, below/.get=\tikzumlactorbelow,% + draw/.get=\tikzumlactordraw, text/.get=\tikzumlactortext}% + % + \def\tikzumlActorName{#2}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlActorNodeName{\tikzumlActorName}}\x% + % + \def\tikzumlActorPos{\posx,\posy}% + % + \ifthenelse{\equal{}{tikzumlEmpty}}{}{} + \node[tikzuml actor style, text=\tikzumlactortext, font=\tikzumlfont] (\tikzumlActorNodeName) at (\tikzumlActorPos) {\picturedactor{scale=\tikzumlactorscale, fill=white, draw=\tikzumlactordraw, thick}};% + \node[text=\tikzumlactortext, font=\tikzumlfont, below=\tikzumlactorscale*\tikzumlactorbelow] at (\tikzumlActorNodeName) {\tikzumlActorName};% + % +}% + +% shortcuts for include and extend relation +\newcommand{\umlinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlinclude, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlextend, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% + +\newcommand{\umlHVinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlHVextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% + +\newcommand{\umlVHinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlVHextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR :in umlVHextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHextend, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% + +\newcommand{\umlHVHinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=-|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlHVHextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=-|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% + +\newcommand{\umlVHVinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=|-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlVHVextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option geometry}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=|-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% + +\newcommand{\umlCNinclude}[4][]{% + \pgfkeys{/tikzuml/includerelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlCNinclude, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlCNrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% +}% + +\newcommand{\umlCNextend}[4][]{% + \pgfkeys{/tikzuml/extendrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlCNextend, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlCNrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% +}% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% state diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\tikzstyle{tikzuml state style}=[rectangle split, rectangle split parts=2, rounded corners, inner xsep=1.5ex]% +\tikzstyle{tikzuml transition style}=[color=\tikzumldrawcolor, rounded corners, -angle 45]% + +\newcounter{tikzumlStateJoinNum}% +\newcounter{tikzumlStateDecisionNum}% +\newcounter{tikzumlStateInitialNum}% +\newcounter{tikzumlStateFinalNum}% +\newcounter{tikzumlStateEnterNum}% +\newcounter{tikzumlStateExitNum}% +\newcounter{tikzumlStateEndNum}% +\newcounter{tikzumlStateHistoryNum}% +\newcounter{tikzumlStateDeepHistoryNum}% +\newcounter{tikzumlStateLevel}% +\newcounter{tikzumlStateSubStateNum}% +\newcounter{tikzumlStateText}% + +\newcommand{\umlstatejoin}[1][]{% + \pgfkeys{/tikzuml/statejoin/.cd, x/.initial=0, y/.initial=0, width/.initial=3ex,% + name/.initial=statejoin-\thetikzumlStateJoinNum, color/.initial=\tikzumldrawcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlstatejoin, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/statejoin/.cd, #1}% + \pgfkeys{/tikzuml/statejoin/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstatejoinwidth,% + name/.get=\tikzumlstatejoinname, color/.get=\tikzumlstatejoincolor}% + % + \def\tikzumlStateJoinPos{\posx,\posy}% + % + \node[circle, minimum size=\tikzumlstatejoinwidth, draw=\tikzumlstatejoincolor, fill=\tikzumlstatejoincolor] (\tikzumlstatejoinname) at (\tikzumlStateJoinPos) {};% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstatejoinname)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateJoinNum}% +}% + +\newcommand{\umlstatedecision}[1][]{% + \pgfkeys{/tikzuml/statedecision/.cd, x/.initial=0, y/.initial=0, width/.initial=3ex,% + name/.initial=statedecision-\thetikzumlStateDecisionNum, color/.initial=\tikzumldrawcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlstatedecision, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/statedecision/.cd, #1}% + \pgfkeys{/tikzuml/statedecision/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstatedecisionwidth,% + name/.get=\tikzumlstatedecisionname, color/.get=\tikzumlstatedecisioncolor}% + % + \def\tikzumlStateDecisionPos{\posx,\posy}% + % + \node[rectangle, rotate=45, minimum size=\tikzumlstatedecisionwidth, draw=\tikzumlstatedecisioncolor] (\tikzumlstatedecisionname) at (\tikzumlStateDecisionPos) {};% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstatedecisionname)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateDecisionNum}% +}% + +\newcommand{\umlstateinitial}[1][]{% + \pgfkeys{/tikzuml/stateinitial/.cd, x/.initial=0, y/.initial=0, width/.initial=5ex,% + name/.initial=stateinitial-\thetikzumlStateInitialNum, color/.initial=\tikzumldrawcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlstateinitial, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/stateinitial/.cd, #1}% + \pgfkeys{/tikzuml/stateinitial/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstateinitialwidth,% + name/.get=\tikzumlstateinitialname, color/.get=\tikzumlstateinitialcolor}% + % + \def\tikzumlStateInitialPos{\posx,\posy}% + % + \node[circle, minimum size=\tikzumlstateinitialwidth, fill=\tikzumlstateinitialcolor] (\tikzumlstateinitialname) at (\tikzumlStateInitialPos) {};% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstateinitialname)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateInitialNum}% +}% + +\newcommand{\umlstatefinal}[1][]{% + \pgfkeys{/tikzuml/statefinal/.cd, x/.initial=0, y/.initial=0, width/.initial=5.5ex,% + name/.initial=statefinal-\thetikzumlStateFinalNum, color/.initial=\tikzumldrawcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlstatefinal, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/statefinal/.cd, #1}% + \pgfkeys{/tikzuml/statefinal/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstatefinalwidth,% + name/.get=\tikzumlstatefinalname, color/.get=\tikzumlstatefinalcolor}% + % + \def\tikzumlStateFinalPos{\posx,\posy}% + % + \node[circle, minimum size=\tikzumlstatefinalwidth, draw=\tikzumlstatefinalcolor, fill=\tikzumlstatefinalcolor, double, double distance=0.1cm] (\tikzumlstatefinalname) at (\tikzumlStateFinalPos) {};% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstatefinalname)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateFinalNum}% +}% + +\newcommand{\umlstateenter}[1][]{% + \pgfkeys{/tikzuml/stateenter/.cd, x/.initial=0, y/.initial=0, width/.initial=5ex,% + name/.initial=stateenter-\thetikzumlStateEnterNum, color/.initial=\tikzumldrawcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlstateenter, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/stateenter/.cd, #1}% + \pgfkeys{/tikzuml/stateenter/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstateenterwidth,% + name/.get=\tikzumlstateentername, color/.get=\tikzumlstateentercolor}% + % + \def\tikzumlStateEnterPos{\posx,\posy}% + % + \node[circle, minimum size=\tikzumlstateenterwidth, draw=\tikzumlstateentercolor] (\tikzumlstateentername) at (\tikzumlStateEnterPos) {};% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstateentername)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateEnterNum}% +}% + +\newcommand{\umlstateexit}[1][]{% + \pgfkeys{/tikzuml/stateexit/.cd, x/.initial=0, y/.initial=0, width/.initial=5ex,% + name/.initial=stateexit-\thetikzumlStateExitNum, color/.initial=\tikzumldrawcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlstateexit, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/stateexit/.cd, #1}% + \pgfkeys{/tikzuml/stateexit/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstateexitwidth,% + name/.get=\tikzumlstateexitname, color/.get=\tikzumlstateexitcolor}% + % + \def\tikzumlStateExitPos{\posx,\posy}% + % + \node[circle, minimum size=\tikzumlstateexitwidth, draw=\tikzumlstateexitcolor] (\tikzumlstateexitname) at (\tikzumlStateExitPos) {};% + \draw[draw=\tikzumlstateexitcolor] (\tikzumlstateexitname.north east) -- (\tikzumlstateexitname.south west) (\tikzumlstateexitname.north west) -- (\tikzumlstateexitname.south east); + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstateexitname)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateExitNum}% +}% + +\newcommand{\umlstateend}[1][]{% + \pgfkeys{/tikzuml/stateend/.cd, x/.initial=0, y/.initial=0, width/.initial=5ex,% + name/.initial=stateend-\thetikzumlStateEndNum, color/.initial=\tikzumldrawcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlstateend, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/stateend/.cd, #1}% + \pgfkeys{/tikzuml/stateend/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstateendwidth,% + name/.get=\tikzumlstateendname, color/.get=\tikzumlstateendcolor}% + % + \def\tikzumlStateEndPos{\posx,\posy}% + % + \node[circle, minimum size=\tikzumlstateendwidth] (\tikzumlstateendname) at (\tikzumlStateEndPos) {};% + \draw[draw=\tikzumlstateendcolor] (\tikzumlstateendname.north east) -- (\tikzumlstateendname.south west) (\tikzumlstateendname.north west) -- (\tikzumlstateendname.south east); + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstateendname)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateEndNum}% +}% + +\newcommand{\picturedhistory}[1]{% + \begin{tikzpicture}[#1] + \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm) + (-0.1cm,0) -- (0.1cm,0) + (0.1cm,-0.15cm) -- (0.1cm,0.15cm); + \end{tikzpicture} +}% + +\newcommand{\umlstatehistory}[1][]{% + \pgfkeys{/tikzuml/statehistory/.cd, x/.initial=0, y/.initial=0, width/.initial=5ex,% + name/.initial=statehistory-\thetikzumlStateHistoryNum, color/.initial=\tikzumldrawcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlstatehistory, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/statehistory/.cd, #1}% + \pgfkeys{/tikzuml/statehistory/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstatehistorywidth,% + name/.get=\tikzumlstatehistoryname, color/.get=\tikzumlstatehistorycolor}% + % + \def\tikzumlStateHistoryPos{\posx,\posy}% + % + \node[circle, minimum size=\tikzumlstatehistorywidth, draw=\tikzumlstatehistorycolor] (\tikzumlstatehistoryname) at (\tikzumlStateHistoryPos) {\picturedhistory{draw=\tikzumlstatehistorycolor}};% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstatehistoryname)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateHistoryNum}% +}% + +\newcommand{\pictureddeephistory}[1]{% + \begin{tikzpicture}[#1] + \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm) + (-0.1cm,0) -- (0.1cm,0) + (0.1cm,-0.15cm) -- (0.1cm,0.15cm) + (0.23cm,0.19cm) -- (0.23cm,0.11cm) + (0.20cm,0.17cm) -- (0.26cm,0.13cm) + (0.20cm,0.13cm) -- (0.26cm,0.17cm); + \end{tikzpicture} +}% + +\newcommand{\umlstatedeephistory}[1][]{% + \pgfkeys{/tikzuml/statedeephistory/.cd, x/.initial=0, y/.initial=0, width/.initial=5ex,% + name/.initial=statedeephistory-\thetikzumlStateDeepHistoryNum, color/.initial=\tikzumldrawcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlstatedeephistory, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/statedeephistory/.cd, #1}% + \pgfkeys{/tikzuml/statedeephistory/.cd, x/.get=\posx, y/.get=\posy, width/.get=\tikzumlstatedeephistorywidth,% + name/.get=\tikzumlstatedeephistoryname, color/.get=\tikzumlstatedeephistorycolor}% + % + \def\tikzumlStateDeepHistoryPos{\posx,\posy}% + % + \node[circle, minimum size=\tikzumlstatedeephistorywidth, draw=\tikzumlstatedeephistorycolor] (\tikzumlstatedeephistoryname) at (\tikzumlStateDeepHistoryPos) {\pictureddeephistory{draw=\tikzumlstatedeephistorycolor}};% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlstatedeephistoryname)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateDeepHistoryNum}% +}% + +% define a uml state +% args : name of the state +% content of the state +% optional args : x,y coordinates of the state +% width of the state node +\newenvironment{umlstate}[2][]{% + \ifnum\thetikzumlStateLevel>0% + \let\tikzumlState@nameold\tikzumlState@fitname% + \let\tikzumlState@parentold\tikzumlState@parent% + \edef\tikzumlState@parent{\tikzumlState@parentold @@\tikzumlState@nameold}% + \else% + \def\tikzumlState@parent{}% + \fi% + + \stepcounter{tikzumlStateLevel}% + + \pgfkeys{/tikzuml/state/.cd, x/.initial=0, y/.initial=0, width/.initial=10ex, type/.initial=class, name/.initial={},% + entry/.initial={}, do/.initial={}, exit/.initial={},% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillstatecolor, text/.initial=\tikzumltextcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlstate, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/state/.cd, #1}% + \pgfkeys{/tikzuml/state/.cd, x/.get=\tikzumlstateX, y/.get=\tikzumlstateY, width/.get=\umlstateMinimumWidth, type/.get=\umlstateType, name/.get=\umlstateName,% + entry/.get=\umlstateentry, do/.get=\umlstatedo, exit/.get=\umlstateexit,% + draw/.get=\tikzumlstatedraw, fill/.get=\tikzumlstatefill, text/.get=\tikzumlstatetext}% + % + \ifthenelse{\equal{\umlstateName}{}}{% + \edef\tikzumlState@name{#2}% + }{% + \edef\tikzumlState@name{\umlstateName}% + }% + % + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlState@fitname{\tikzumlState@name}}\x% + % + \let\tikzumlState@nodeNameold\tikzumlState@nodeName% + \def\tikzumlState@caption{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlState@nodeName{\tikzumlState@name}}\x% + % + \expandafter\gdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{}% + % + \setcounter{tikzumlStateSubStateNum}{0}% + \setcounter{tikzumlStateText}{0}% + % + \def\tikzumlStateText{tikzumlEmpty}% + \begin{scope}[xshift=\tikzumlstateX cm, yshift=\tikzumlstateY cm]% +}{% + % + \def\tikzumlstaterootlabel{\phantom{\tikzumlState@nodeName}}% + % + \def\tikzumlstaterootinnerysep{0.5ex}% + \def\tikzumlstatebodyinnerysep{2ex}% + % + \ifthenelse{\equal{\umlstateentry}{}}{}{% + \def\tikzumlStateText{entry/\umlstateentry}% + \setcounter{tikzumlStateText}{1}% + \ifnum\c@tikzumlStateSubStateNum=0% + \def\tikzumlstatebodyinnerysep{0}% + \def\tikzumlstaterootinnerysep{0}% + \fi% + }% + \ifthenelse{\equal{\umlstatedo}{}}{}{% + \ifnum\c@tikzumlStateText=0% + \def\tikzumlStateText{do/\umlstatedo}% + \else% + \let\tikzumlStateTextOld\tikzumlStateText% + \def\tikzumlStateText{\tikzumlStateTextOld \\ do/\umlstatedo}% + \fi% + \setcounter{tikzumlStateText}{1}% + \ifnum\c@tikzumlStateSubStateNum=0% + \def\tikzumlstatebodyinnerysep{0}% + \def\tikzumlstaterootinnerysep{0}% + \fi% + }% + \ifthenelse{\equal{\umlstateexit}{}}{}{% + \ifnum\c@tikzumlStateText=0% + \def\tikzumlStateText{exit/\umlstateexit}% + \else% + \let\tikzumlStateTextOld\tikzumlStateText% + \def\tikzumlStateText{\tikzumlStateTextOld \\ exit/\umlstateexit}% + \fi% + \setcounter{tikzumlStateText}{1}% + \ifnum\c@tikzumlStateSubStateNum=0% + \def\tikzumlstatebodyinnerysep{0}% + \def\tikzumlstaterootinnerysep{0}% + \fi% + }% + % + \addtocounter{tikzumlStateLevel}{-1}% + \begin{pgfonlayer}{state\thetikzumlStateLevel}% + % + % if contains nothing, one define a fictive node to enable the fit option + \ifnum\c@tikzumlStateSubStateNum=0% + \node[inner ysep=\tikzumlstaterootinnerysep] (\tikzumlState@nodeName-root) at (0,0) {\tikzumlstaterootlabel};% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{(\tikzumlState@nodeName-root)}% + \fi% + % + \ifnum\c@tikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent\endcsname{\tikzumlStateFitTmp (\tikzumlState@nodeName-body) (\tikzumlState@nodeName-caption)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + % + \node[inner xsep=2ex, inner ysep=\tikzumlstatebodyinnerysep, fit = \csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname] (\tikzumlState@nodeName-body) {};% + \def\tikzumlState@orig{body}% + \ifnum\c@tikzumlStateText=1% + \node[above=0] (\tikzumlState@nodeName-texttmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};% + \def\tikzumlState@orig{texttmp}% + \fi% + \node[above] (\tikzumlState@nodeName-captiontmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\tikzumlState@caption};% + \node[rounded corners, draw=\tikzumlstatedraw, fill=\tikzumlstatefill, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-captiontmp)] {};% + \ifnum\c@tikzumlStateText=1% + \node (\tikzumlState@nodeName-text) at (\tikzumlState@nodeName-texttmp) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};% + \fi% + \node (\tikzumlState@nodeName-caption) at (\tikzumlState@nodeName-captiontmp) {\tikzumlState@caption};% + \draw (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north west) -- (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north east);% + \end{pgfonlayer}% + \end{scope}% +}% + +% shortcut for empty state +\newcommand{\umlbasicstate}[2][]{\begin{umlstate}[#1]{#2} \end{umlstate}}% + +% command to add text in a state +\newcommand{\umlstatetext}[1]{% + \def\tikzumlStateText{#1}% + \setcounter{tikzumlStateText}{1}% +}% + +% shortcuts for state transitions macros +\newcommand{\umltrans}[3][]{% + \ifthenelse{\equal{#2}{#3}}{% + \umlrelation[style={tikzuml transition style}, recursive mode=transition, #1]{#2}{#3}% + }{% + \umlrelation[style={tikzuml transition style}, #1]{#2}{#3}% + }% +}% +\newcommand{\umlHVtrans}[3][]{\umlHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlVHtrans}[3][]{\umlVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlVHVtrans}[3][]{\umlVHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlHVHtrans}[3][]{\umlHVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlCNtrans}[4][]{\umlCNrelation[style={tikzuml transition style}, #1]{#2}{#3}{#4}}% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% sequence diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\tikzstyle{tikzuml synchron-msg style}=[color=\tikzumldrawcolor, -triangle 45]% +\tikzstyle{tikzuml asynchron-msg style}=[color=\tikzumldrawcolor, -angle 45]% +\tikzstyle{tikzuml return-msg style}=[color=\tikzumldrawcolor, dashed, -angle 45]% +\tikzstyle{tikzuml call return style}=[color=\tikzumldrawcolor, dashed, -angle 45]% +\tikzstyle{tikzuml activity style}=[inner xsep=1ex, inner ysep=1ex]% + +\newcounter{tikzumlObjectNum} +\newcounter{tikzumlCallLevel} +\newcounter{tikzumlCallNum} +\newcounter{tikzumlFragmentLevel} +\newcounter{tikzumlFragmentLevelNum} +\newcounter{tikzumlFragmentNum} +\newcounter{tikzumlFragmentPartNum} +\newcounter{tikzumlCallStartFragmentNum} +\newcounter{tikzumlCallEndFragmentNum} + +% define a sequence diagram +% +\newenvironment{umlseqdiag}{% + \gdef\tikzumlInCreateCall{0}% + \setcounter{tikzumlObjectNum}{0}% + \setcounter{tikzumlCallLevel}{0}% + \setcounter{tikzumlCallNum}{0}% + \setcounter{tikzumlFragmentLevel}{0}% + \setcounter{tikzumlFragmentLevelNum}{0}% + \setcounter{tikzumlFragmentNum}{0}% + \setcounter{tikzumlFragmentPartNum}{0}% + \setcounter{tikzumlCallStartFragmentNum}{0}% + \setcounter{tikzumlCallEndFragmentNum}{0}% + % + \ifx \@umlactor \@empty + \newcommand{\umlactor}[2][]{% + \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}% + }{}% + }% + }% + % + \pgfkeys{/tikzuml/actorobj/.cd, ##1}% + \umlobject[stereo=actor, ##1]{##2}% + }% + \else% + \renewcommand{\umlactor}[2][]{ + \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}% + }{}% + }% + }% + % + \pgfkeys{/tikzuml/actorobj/.cd, ##1}% + \umlobject[stereo=actor, ##1]{##2}% + }% + \fi% + \begin{scope}[font=\tikzumlfont]% +}{% + % draw lifelines of each object + \begin{pgfonlayer}{lifelines}% + \foreach \id in \tikzumlIdList {% + \draw (\csname tikzumlLastChild@\id \endcsname)+(0,-2.5ex) node[inner sep=0, name=end-\id] {};% + \draw[dotted] (\id) -- (end-\id);% + }% + \end{pgfonlayer}% + \end{scope}% +}% + +% define the actor symbol +% optional : global tikzpicture styles +\newcommand{\pictureddatabase}[1]{% + \pgfkeys{/tikzuml/database/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/database/.cd,#1}% + \pgfkeys{/tikzuml/database/.cd, scale/.get=\tikzumldatabasescale}% + % + \begin{tikzpicture}[#1] + \node[fill, draw, ellipse, minimum width=\tikzumldatabasescale*4ex, minimum height=\tikzumldatabasescale*2ex, inner sep=0] (bottom) at (0,-2ex) {}; + \node[fill, draw, ellipse, minimum width=\tikzumldatabasescale*4ex, minimum height=\tikzumldatabasescale*2ex, inner sep=0] (top) at (0,4ex) {}; + \fill (bottom.west) rectangle (top.east); + \begin{scope} + \clip (-3.5ex,-0.5ex) rectangle (3.5ex,2.5ex); + \node[draw, dashed, ellipse, minimum width=\tikzumldatabasescale*4ex, minimum height=\tikzumldatabasescale*2ex, inner sep=0] (bottom2) at (0,-2ex) {}; + \end{scope} + \node[draw, ellipse, minimum width=\tikzumldatabasescale*4ex, minimum height=\tikzumldatabasescale*2ex, inner sep=0] (top2) at (0,4ex) {}; + \draw (bottom.west) -- (top.west) (bottom.east) -- (top.east); + \end{tikzpicture} +}% + +% define the actor symbol +% optional : global tikzpicture styles +\newcommand{\picturedentity}[1]{% + \pgfkeys{/tikzuml/entity/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/entity/.cd,#1}% + \pgfkeys{/tikzuml/entity/.cd, scale/.get=\tikzumlentityscale}% + % + \begin{tikzpicture}[#1]% + \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlentityscale*5ex] (center) at (0,0) {};% + \draw (center.south) node[coordinate, name=bottom] {};% + \draw (bottom)+(-2ex,0) node[coordinate, name=bottom-left] {};% + \draw (bottom)+(2ex,0) node[coordinate, name=bottom-right] {};% + \draw (center) -- (bottom);% + \draw (bottom-left) -- (bottom-right);% + \end{tikzpicture}% +}% + +% define the actor symbol +% optional : global tikzpicture styles +\newcommand{\picturedboundary}[1]{% + \pgfkeys{/tikzuml/boundary/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/boundary/.cd,#1}% + \pgfkeys{/tikzuml/boundary/.cd, scale/.get=\tikzumlboundaryscale}% + % + \begin{tikzpicture}[#1] + \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlboundaryscale*5ex] (center) at (0,0) {}; + \draw (center.west)+(-0.8ex,0) node[coordinate, name=left] {}; + \draw (left)+(0,0.2ex) node[coordinate, name=left-top] {}; + \draw (left)+(0,-0.2ex) node[coordinate, name=left-bottom] {}; + \draw (center) -- (left); + \draw (left-top) -- (left-bottom); + \end{tikzpicture} +}% + +% define the actor symbol +% optional : global tikzpicture styles +\newcommand{\picturedcontrol}[1]{% + \pgfkeys{/tikzuml/control/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/control/.cd,#1}% + \pgfkeys{/tikzuml/control/.cd, scale/.get=\tikzumlcontrolscale}% + % + \begin{tikzpicture}[#1, decoration={markings, mark=at position 0.25 with {\arrow{>}}}] + \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlcontrolscale*5ex, postaction={decorate}] (center) at (0,0) {}; + \end{tikzpicture} +}% + +% define a uml object for a sequence diagram +% args : name of the object +% optional : x, y coordinates of the object +% stereotype of the object (object, actor, database, boundary, control, entity, multiobject) +% class of the object +% draw, fill, text colors +\newcommand{\umlobject}[2][]{ + \stepcounter{tikzumlObjectNum}% + % + \pgfkeys{/tikzuml/obj/.cd, x/.initial={tikzumlEmpty}, y/.initial=0, stereo/.initial=object, class/.initial={}, scale/.initial=1,% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillobjectcolor, text/.initial=\tikzumltextcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlobj, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/obj/.cd, #1}% + \pgfkeys{/tikzuml/obj/.cd, x/.get=\tikzumlobjectX, y/.get=\tikzumlobjectY, stereo/.get=\tikzumlobjectstereo, class/.get=\tikzumlobjectclass,% + scale/.get=\tikzumlobjectscale,% + draw/.get=\tikzumlobjectdraw, fill/.get=\tikzumlobjectfill, text/.get=\tikzumlobjecttext}% + % + \ifthenelse{\equal{\tikzumlobjectX}{tikzumlEmpty}}{% + \pgfmathsetmacro{\tikzumlobjectX}{4*(\thetikzumlObjectNum-1)}% + }{}% + % + \def\tikzumlObjectName{#2}% + \expandafter\xdef\csname tikzumlLastChild@\tikzumlObjectName \endcsname{\tikzumlObjectName}% + % + \ifnum\thetikzumlObjectNum=1% + \xdef\tikzumlIdList{\tikzumlObjectName}% + \else% + \let\tikzumlIdListOld\tikzumlIdList% + \xdef\tikzumlIdList{\tikzumlIdListOld,\tikzumlObjectName}% + \fi% + % + \tikzstyle{tikzuml object box style}=[rectangle, text=\tikzumlobjecttext, font=\tikzumlfont]% + % + \ifthenelse{\equal{\tikzumlobjectstereo}{object}}{% + \tikzstyle{tikzuml object box style}+=[draw=\tikzumlobjectdraw, fill=\tikzumlobjectfill]% + }{% + \ifthenelse{\equal{\tikzumlobjectstereo}{multi}}{% + \tikzstyle{tikzuml object box style}+=[fill=\tikzumlobjectfill]% + }{}% + }% + % + \ifnum\tikzumlInCreateCall=1% + \draw (\tikzumlCreateCallObjectSrc -| \tikzumlobjectX,0) node[tikzuml object box style] (\tikzumlObjectName) {\tikzumlObjectName:\tikzumlobjectclass};% + \else% + \node[tikzuml object box style] (\tikzumlObjectName) at (\tikzumlobjectX,\tikzumlobjectY) {\tikzumlObjectName:\tikzumlobjectclass};% + \fi% + % + \ifthenelse{\equal{\tikzumlobjectstereo}{multi}}{% + \draw (\tikzumlObjectName.north east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tr, coordinate] {}; + \draw (\tikzumlObjectName.north west)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tl, coordinate] {}; + \draw (\tikzumlObjectName.south east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-br, coordinate] {}; + \draw (\tikzumlObjectName-tr)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttr, coordinate] {}; + \draw (\tikzumlObjectName-tl)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttl, coordinate] {}; + \draw (\tikzumlObjectName-br)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tbr, coordinate] {}; + \fill[fill=\tikzumlobjectfill] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-ttl |- \tikzumlObjectName.north); + \draw[draw=\tikzumlobjectdraw] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east); + \fill[fill=\tikzumlobjectfill] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-tl |- \tikzumlObjectName.north); + \draw[draw=\tikzumlobjectdraw] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east); + \draw[draw=\tikzumlobjectdraw] (\tikzumlObjectName.north west) rectangle (\tikzumlObjectName.south east); + }{% + \ifthenelse{\equal{\tikzumlobjectstereo}{object}}{}{% + \node[above=1ex, name=\tikzumlObjectName-picture] at (\tikzumlObjectName) {\csname pictured\tikzumlobjectstereo \endcsname{draw=\tikzumlobjectdraw, fill=\tikzumlobjectfill, scale=\tikzumlobjectscale}}; + }% + }% +} + +% shortcuts for objects +\newcommand{\umldatabase}[2][]{% + \pgfkeys{/tikzuml/databaseobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umldatabase, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/databaseobj/.cd, #1}% + \umlobject[stereo=database, #1]{#2}% +}% +\newcommand{\umlentity}[2][]{% + \pgfkeys{/tikzuml/entityobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlentity, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/entityobj/.cd, #1}% + \umlobject[stereo=entity, #1]{#2}% +}% +\newcommand{\umlcontrol}[2][]{% + \pgfkeys{/tikzuml/controlobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlcontrol, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/controlobj/.cd, #1}% + \umlobject[stereo=control, #1]{#2}% +}% +\newcommand{\umlboundary}[2][]{% + \pgfkeys{/tikzuml/boundaryobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlboundary, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/boundaryobj/.cd, #1}% + \umlobject[stereo=boundary, #1]{#2}% +}% +\newcommand{\umlmulti}[2][]{% + \pgfkeys{/tikzuml/multiobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlmulti, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/multiobj/.cd, #1}% + \umlobject[stereo=multi, #1]{#2}% +}% + +\newlength{\tikzumlCall@xa}% +\newlength{\tikzumlCall@xb}% + +% define a uml operation call for sequence diagrams +% args : call sender +% call receiver +% optional : dt, time delay from precedent event end +% name of the call +% operation name and input args +% return value +% type of the call (synchron, asynchron) +% draw, fill, text colors +% time padding from call start and to call end +\newenvironment{umlcall}[3][]{% + \stepcounter{tikzumlCallNum}% + \def\tikzumlCallWithReturn{false}% + \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls + \gdef\tikzumlCallBottom{0}% + % + \pgfkeys{/tikzuml/call/.cd, dt/.initial={tikzumlEmpty}, name/.initial={call-\thetikzumlCallNum}, op/.initial={}, return/.initial={}, type/.initial=synchron,% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillcallcolor, text/.initial=\tikzumltextcolor,% + padding/.initial=2,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{with return}}{% + \def\tikzumlCallWithReturn{true}% + }{% + \errmessage{TIKZUML ERROR : in umlcall, invalid option \keyname}% + }% + }}% + \pgfkeys{/tikzuml/call/.cd, #1}% + \pgfkeys{/tikzuml/call/.cd, dt/.get=\tikzumlcallDT, name/.get=\tikzumlcallname, op/.get=\tikzumlcallop, return/.get=\tikzumlcallreturn, type/.get=\tikzumlcalltype,% + padding/.get=\tikzumlcallpadding,% + draw/.get=\tikzumlcalldraw, fill/.get=\tikzumlcallfill, text/.get=\tikzumlcalltext}% + % + \edef\tikzumlfillcall{\tikzumlcallfill}% + \edef\tikzumldrawcall{\tikzumlcalldraw}% + \edef\tikzumltextcall{\tikzumlcalltext}% + \edef\tikzumltypecall{\tikzumlcalltype}% + \ifthenelse{\equal{\tikzumlcallDT}{tikzumlEmpty}}{% + \ifnum\thetikzumlCallNum=1% + \def\tikzumlcallDT{2}% + \def\tikzumlcallSrc{2}% + \else% + \def\tikzumlcallDT{2}% + \def\tikzumlcallSrc{1}% + \fi% + }{ + \def\tikzumlcallSrc{0}% + }% + % + \let\tikzumlCallStartNodeNameold\tikzumlCallStartNodeName% + \def\tikzumlCallStartNodeName{#2}% + \let\tikzumlCallEndNodeNameold\tikzumlCallEndNodeName% + \def\tikzumlCallEndNodeName{#3}% + \def\tikzumlcallheight{\tikzumlcallpadding}% + % + % managing time delays from previous/parent fragments + \ifnum\thetikzumlCallStartFragmentNum>0% + \let\tikzumlcallDTold\tikzumlcallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% + \edef\tikzumlcallDT{\pgfmathresult}% + \addtocounter{tikzumlCallStartFragmentNum}{-1} + \fi% + \ifnum\thetikzumlCallEndFragmentNum>0% + \let\tikzumlcallDTold\tikzumlcallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% + \edef\tikzumlcallDT{\pgfmathresult}% + \addtocounter{tikzumlCallEndFragmentNum}{-1} + \fi% + \ifnum\thetikzumlFragmentPartNum>0% + \let\tikzumlcallDTold\tikzumlcallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% + \edef\tikzumlcallDT{\pgfmathresult}% + \fi% + % + % managing parent-child structure + \ifnum\thetikzumlCallLevel>0% + \let\tikzumlCall@nameold\tikzumlCall@name% + \edef\tikzumlCall@name{\tikzumlcallname}% + \let\tikzumlCall@parentold\tikzumlCall@parent% + \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}% + \else% + \edef\tikzumlCall@parent{}% + \edef\tikzumlCall@parentold{}% + \edef\tikzumlCall@nameold{} + \edef\tikzumlCall@name{\tikzumlcallname}% + \fi% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlCall@nodeName{\tikzumlCall@name}}\x% + % + \let\tikzumlCall@nodeNameold\tikzumlCall@nodeName% + % + \def\tikzumlcallstyle{tikzuml \tikzumlcalltype-msg style}% + % + % top node of activity period of call sender + \begin{pgfonlayer}{connections}% + \pgfmathparse{\tikzumlcallDT+\tikzumlcallSrc}% + \draw (\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname)+(0,-\pgfmathresult ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (st-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + % + % update last node drawn on sender lifeline + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{st-\tikzumlCall@nodeName}% + % + % top node of activity period of call receiver + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% + \draw (st-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlcallpadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + }{% + \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- st-\tikzumlCall@nodeName) {};% + }% + % + % update last node drawn on receiver lifeline + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{et-\tikzumlCall@nodeName}% + \xdef\tikzumlCallBottomSrc{et-\tikzumlCall@nodeName}% + \end{pgfonlayer}% + % + \stepcounter{tikzumlCallLevel}% +}{% + \addtocounter{tikzumlCallLevel}{-1}% + % + % bottom nodes of activity periods of call sender and receiver + \begin{pgfonlayer}{connections}% + \ifnum\tikzumlCall@lastchildNum=\thetikzumlCallNum% + % + % this test occurs a bug with latex package preview + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallpadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlcallpadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + }{% + \ifthenelse{\equal{\tikzumlcallreturn}{tikzumlEmpty}}{% + \pgfmathsetmacro{\tikzumlcallpaddingd}{0.5*\tikzumlcallpadding}% + }{% + \pgfmathsetmacro{\tikzumlcallpaddingd}{1.2*\tikzumlcallpadding}% + }% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallpaddingd ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};% + }% + \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}% + \else% + % + % managing time delays from previous/parent fragments + \ifnum\thetikzumlCallStartFragmentNum>0% + \let\tikzumlcallheightold\tikzumlcallpadding + \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy} + \edef\tikzumlcallheight{\pgfmathresult} + \addtocounter{tikzumlCallStartFragmentNum}{-1} + \fi% + \ifnum\thetikzumlCallEndFragmentNum>0% + \let\tikzumlcallheightold\tikzumlcallpadding + \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy} + \edef\tikzumlcallheight{\pgfmathresult} + \addtocounter{tikzumlCallEndFragmentNum}{-1} + \fi% + % + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlcallpadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + }{% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};% + }% + % + \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}% + \fi% + \end{pgfonlayer}% + % + % draw activity periods + \begin{pgfonlayer}{activity}% + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% + % draw root activity period only + \ifnum\thetikzumlCallLevel=0% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + \else% + % draw root activity from inner call + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + }% + \fi% + }{% + % draw root activity period + \ifnum\thetikzumlCallLevel=0% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + \else% + % draw root activity from inner call + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + }% + \fi% + % draw receiver activity period + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (et-\tikzumlCall@nodeName.north west) rectangle (eb-\tikzumlCall@nodeName.south east);% + }% + \end{pgfonlayer}% + \ifthenelse{\equal{\tikzumlfillcallcolor}{\tikzumlcallfill}}{}{% + \fill[\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + \draw[\tikzumldrawcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south west) (st-\tikzumlCall@nodeName.north east) rectangle (sb-\tikzumlCall@nodeName.south east); + }% + % + % update last nodes drawn on sender and receiver lifelines + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{eb-\tikzumlCall@nodeName}% + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{sb-\tikzumlCall@nodeName}% + % + % draw call arrows + \begin{pgfonlayer}{connections}% + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% + \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlcallpadding ex,0) % + -- ++(0,-0.75*\tikzumlcallpadding ex) % + node[font=\tikzumlfont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-op] {\tikzumlcallop} % + -- (et-\tikzumlCall@nodeName.east);% + % + % draw return arrow and update fit for parent fragment + \ifthenelse{\equal{\tikzumltypecall}{synchron}}{% + \ifthenelse{\NOT\equal{\tikzumlcallreturn}{}\OR\equal{\tikzumlCallWithReturn}{true}}{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}% + \fi% + % + \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlcallpadding ex,0) -- ++(0,-0.75*\tikzumlcallpadding ex) % + node[font=\tikzumlfont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-return] {\tikzumlcallreturn} % + -- (sb-\tikzumlCall@nodeName.east);% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + % + }% + }{% + % draw call arrows + \pgfextractx{\tikzumlCall@xa}{\pgfpointanchor{\tikzumlCallStartNodeName}{center}}% + \pgfextractx{\tikzumlCall@xb}{\pgfpointanchor{\tikzumlCallEndNodeName}{center}}% + % + \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{% + \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- (et-\tikzumlCall@nodeName.west) % + node[font=\tikzumlfont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlcallop};% + }{% + \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.west) -- (et-\tikzumlCall@nodeName.east) % + node[font=\tikzumlfont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlcallop};% + }% + % + % draw return arrow and update fit for parent fragment + \ifthenelse{\equal{\tikzumltypecall}{synchron}}{% + \ifthenelse{\NOT\equal{\tikzumlcallreturn}{}\OR\equal{\tikzumlCallWithReturn}{true}}{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}% + \fi% + % + \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{% + \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.west) -- (sb-\tikzumlCall@nodeName.east) % + node[font=\tikzumlfont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlcallreturn};% + }{% + \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- (sb-\tikzumlCall@nodeName.west) % + node[font=\tikzumlfont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlcallreturn};% + }% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }% + \end{pgfonlayer}% +}% + +% alias for function self call +\newenvironment{umlcallself}[2][]{\begin{umlcall}[#1]{#2}{#2} }{\end{umlcall}}% + +% define a combined fragment +% optional : name of fragment +% type of fragment (opt, alt, break, loop, par, critical, ignore, consider, assert, neg, weak, strict, ref) +% label of fragment (ex : condition for opt, iterator for loop, ...) +% inner xsep and ysep (padding of the fragment box) +% draw, fill, text colors +\newenvironment{umlfragment}[1][]{% + + % define a fragment separator + % optional : label of the fragment part (ex : else for alt) + \providecommand{\umlfpart}[1][]{% + \stepcounter{tikzumlFragmentPartNum}% + % + \node[outer sep=0, inner xsep=\tikzumlfragmentxsep ex, inner ysep=\tikzumlfragmentysep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-Part-tmp] {};% + \node[anchor=east, name=\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum] at (\tikzumlFragment@name-Part-tmp.north west |- \tikzumlCallBottomSrc) {\phantom{\tikzumlfragmenttype}}; + \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum.north west |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum] {}; + \draw (\tikzumlFragment@name-Part-tmp.north east |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum] {}; + \draw[dashed] (\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum) -- (\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum); + \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=tikzumlTmpNode] {\phantom{\tikzumlfragmenttype}}; + \node[anchor=north west] at (tikzumlTmpNode.south west) {[##1]};% + }% + + \stepcounter{tikzumlFragmentNum}% + % + \pgfkeys{/tikzuml/fragment/.cd, name/.initial={fragment@\alph{tikzumlFragmentNum}}, type/.initial=opt, label/.initial={tikzumlEmpty},% + inner xsep/.initial=1, inner ysep/.initial=1,% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillfragmentcolor, text/.initial=\tikzumltextcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlfragment, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/fragment/.cd, #1}% + \pgfkeys{/tikzuml/fragment/.cd, name/.get=\tikzumlfragmentname, type/.get=\tikzumlfragmenttype, label/.get=\tikzumlfragmentlabel,% + inner xsep/.get=\tikzumlfragmentxsep, inner ysep/.get=\tikzumlfragmentysep,% + draw/.get=\tikzumlfragmentdraw, fill/.get=\tikzumlfragmentfill, text/.get=\tikzumlfragmenttext}% + % + \ifthenelse{\equal{\tikzumlfragmentlabel}{tikzumlEmpty}}{% + \def\tikzumlfragmentlabel{}% + }{% + \let\tikzumlfragmentlabelold\tikzumlfragmentlabel% + \def\tikzumlfragmentlabel{[\tikzumlfragmentlabelold]}% + }% + + % + \ifnum\thetikzumlFragmentLevel>0% + \let\tikzumlFragment@parentold\tikzumlFragment@parent% + \let\tikzumlFragment@nameold\tikzumlFragment@name% + \edef\tikzumlFragment@parent{\tikzumlFragment@nameold}% + \else% + \setcounter{tikzumlFragmentPartNum}{0}% + \edef\tikzumlFragment@parent{}% + \edef\tikzumlFragment@parentold{}% + \edef\tikzumlFragment@nameold{}% + \fi% + % + \edef\tikzumlFragment@name{\tikzumlfragmentname}% + \expandafter\gdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{}% + % + \stepcounter{tikzumlFragmentLevel}% + % + \ifnum\thetikzumlCallLevel>0% + \stepcounter{tikzumlCallStartFragmentNum}% + \fi% + % + \pgfmathparse{6*\tikzumlfragmentysep}% + \xdef\tikzumlFragment@paddingy{\pgfmathresult}% + \if\c@tikzumlFragmentLevelNum=0% + \setcounter{tikzumlFragmentLevelNum}{\thetikzumlFragmentLevel}% + \fi% + % + % time delay adjustment for two consecutive fragments + \ifnum\thetikzumlCallEndFragmentNum>0% + \addtocounter{tikzumlCallEndFragmentNum}{-1} + \fi% +}{% + % + \addtocounter{tikzumlFragmentLevel}{-1}% + % + \ifnum\thetikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname{\tikzumlFragmentFitOld (\tikzumlFragment@name)}% + \fi% + % + % draw working fragment box + \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}% + \node[outer sep=0, inner xsep=\tikzumlfragmentxsep ex, inner ysep=\tikzumlfragmentysep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-back] {};% + \end{pgfonlayer}% + % + % draw type and label + \node[text=\tikzumlfragmenttext, font=\tikzumlfont, anchor=north east, name=\tikzumlFragment@name-type] % + at (\tikzumlFragment@name-back.north west) {\tikzumlfragmenttype};% + \node[text=\tikzumlfragmenttext, font=\tikzumlfont, anchor=north west, name=\tikzumlFragment@name-label] % + at (\tikzumlFragment@name-type.south west) {\tikzumlfragmentlabel};% + % + % draw final fragment box + \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}% + \node[draw=\tikzumlfragmentdraw, fill=\tikzumlfragmentfill, outer sep=0, inner sep=0, font=\tikzumlfont, fit=(\tikzumlFragment@name-back) (\tikzumlFragment@name-type) (\tikzumlFragment@name-label), name=\tikzumlFragment@name] {};% + \end{pgfonlayer}% + % + \draw[draw=\tikzumlfragmentdraw] (\tikzumlFragment@name.north west) rectangle (\tikzumlFragment@name.south east);% + \draw (\tikzumlFragment@name-type.south east)+(0,1ex) node[name=\tikzumlFragment@name-typetop, inner sep=0] {};% + \draw (\tikzumlFragment@name-type.south east)+(-1ex,0) node[name=\tikzumlFragment@name-typeleft, inner sep=0] {};% + \draw (\tikzumlFragment@name.north west) -| (\tikzumlFragment@name-typetop.center) -- (\tikzumlFragment@name-typeleft.center) -| (\tikzumlFragment@name.north west);% + % + \ifnum\thetikzumlCallLevel>0% + \stepcounter{tikzumlCallEndFragmentNum}% + \fi% +}% + +% define a constructor call +% arg : call sender +% name of constructed object +% optional : x coordinate of the new object +% stereotype of the new object +% class type of the new object +% time delay from last event +% name of the call +% draw, fill, text colors +\newcommand{\umlcreatecall}[3][]{% + \stepcounter{tikzumlCallNum}% + \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls + \gdef\tikzumlInCreateCall{1}% + \pgfkeys{/tikzuml/createcall/.cd, x/.initial={tikzumlEmpty}, stereo/.initial=object, class/.initial={},% + dt/.initial=4, name/.initial={call-\thetikzumlCallNum},% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillcallcolor, text/.initial=\tikzumltextcolor,% + draw obj/.initial=\tikzumldrawcolor, fill obj/.initial=\tikzumlfillobjectcolor, text obj/.initial=\tikzumltextcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlcreatecall, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/createcall/.cd, #1}% + \pgfkeys{/tikzuml/createcall/.cd, x/.get=\tikzumlcallX, stereo/.get=\tikzumlcallstereo, class/.get=\tikzumlcallclass,% + dt/.get=\tikzumlcallDT, name/.get=\tikzumlcallname,% + draw/.get=\tikzumlcalldraw, fill/.get=\tikzumlcallfill, text/.get=\tikzumlcalltext,% + draw obj/.get=\tikzumlcallobjdraw, fill obj/.get=\tikzumlcallobjfill, text obj/.get=\tikzumlcallobjtext}% + % + \def\tikzumlCreateCallSrc@name{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlCreateCallSrc@nodeName{\tikzumlCreateCallSrc@name}}\x% + % + % managing time delays from previous/parent fragments + \ifnum\thetikzumlCallStartFragmentNum>0% + \let\tikzumlcallDTold\tikzumlcallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% + \edef\tikzumlcallDT{\pgfmathresult}% + \addtocounter{tikzumlCallStartFragmentNum}{-1} + \fi% + \ifnum\thetikzumlCallEndFragmentNum>0% + \let\tikzumlcallDTold\tikzumlcallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% + \edef\tikzumlcallDT{\pgfmathresult}% + \addtocounter{tikzumlCallEndFragmentNum}{-1} + \fi% + \ifnum\thetikzumlFragmentPartNum>0% + \let\tikzumlcallDTold\tikzumlcallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlcallDTold}% + \edef\tikzumlcallDT{\pgfmathresult}% + \fi% + % + % managing parent-child structure + \ifnum\thetikzumlCallLevel>0% + \let\tikzumlCall@nameold\tikzumlCall@name% + \def\tikzumlCall@name{\tikzumlcallname}% + \let\tikzumlCall@parentold\tikzumlCall@parent% + \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}% + \else% + \edef\tikzumlCall@parent{}% + \edef\tikzumlCall@parentold{}% + \edef\tikzumlCall@nameold{} + \edef\tikzumlCall@name{\tikzumlcallname}% + \fi% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlCreateCall@nodeName{\tikzumlCall@name}}\x% + % + \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname)+(0,-\tikzumlcallDT ex) node[name=st-\tikzumlCreateCall@nodeName, tikzuml activity style] {};% + % + \xdef\tikzumlCreateCallObjectSrc{st-\tikzumlCreateCall@nodeName}% + % + \umlobject[x=\tikzumlcallX, stereo=\tikzumlcallstereo, class=\tikzumlcallclass, draw=\tikzumlcallobjdraw, fill=\tikzumlcallobjfill, text=\tikzumlcallobjtext]{#3}% + % + \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname |- #3)+(0,-0.5*\tikzumlcallDT ex) node[name=sb-\tikzumlCreateCall@nodeName, tikzuml activity style] {};% + % + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname{sb-\tikzumlCreateCall@nodeName}% + \xdef\tikzumlCallBottomSrc{sb-\tikzumlCreateCall@nodeName}% + % + \begin{pgfonlayer}{connections}% + \draw[tikzuml synchron-msg style, \tikzumlcalldraw] (st-\tikzumlCreateCall@nodeName) -- (#3) node[midway, above, font=\tikzumlfont, text=\tikzumlcalltext, name=\tikzumlCreateCall@nodeName-op] {create};% + \end{pgfonlayer}% + % + \ifnum\thetikzumlCallLevel=0% + \begin{pgfonlayer}{activity}% + \draw[draw=\tikzumlcalldraw, fill=\tikzumlcallfill] (st-\tikzumlCreateCall@nodeName.north west) rectangle (sb-\tikzumlCreateCall@nodeName.south east);% + \end{pgfonlayer}% + \fi% + % add to fit fragment + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCreateCall@nodeName) (sb-\tikzumlCreateCall@nodeName) (\tikzumlCreateCall@nodeName-op) (#3) }% + \fi% +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% component diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\tikzstyle{tikzuml connector style}=[color=\tikzumldrawcolor, -]% + +\newcounter{tikzumlComponentLevel}% +\newcounter{tikzumlComponentSubComponentNum}% +\newcounter{tikzumlConnectorNum}% +\setcounter{tikzumlConnectorNum}{1}% + +\newcommand{\picturedcomponent}[1]{% + \pgfkeys{/tikzuml/component/picture/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/component/picture/.cd,#1}% + \pgfkeys{/tikzuml/component/picture/.cd, scale/.get=\tikzumlcomponentscale}% + \begin{tikzpicture}[#1]% + \filldraw (0,0) rectangle (1ex,1.5ex);% + \filldraw (-0.2ex,0.4ex) rectangle (0.2ex,0.6ex);% + \filldraw (-0.2ex,0.9ex) rectangle (0.2ex,1.1ex);% + \end{tikzpicture}% +}% + +% define a uml component +% args : name of the component +% content of the component +% optional args : x,y coordinates of the component +% width of the component node +\newenvironment{umlcomponent}[2][]{% + \ifnum\thetikzumlComponentLevel>0% + \let\tikzumlComponent@nameold\tikzumlComponent@fitname% + \let\tikzumlComponent@parentold\tikzumlComponent@parent% + \edef\tikzumlComponent@parent{\tikzumlComponent@parentold @@\tikzumlComponent@nameold}% + \else% + \def\tikzumlComponent@parent{}% + \fi% + % + \stepcounter{tikzumlComponentLevel}% + % + \pgfkeys{/tikzuml/component/.cd, x/.initial=0, y/.initial=0, width/.initial=10ex, name/.initial={},% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillcomponentcolor,% + text/.initial=\tikzumltextcolor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \errmessage{TIKZUML ERROR : in umlcomponent, invalid option \keyname}% + }}% + \pgfkeys{/tikzuml/component/.cd, #1}% + \pgfkeys{/tikzuml/component/.cd, x/.get=\tikzumlcomponentX, y/.get=\tikzumlcomponentY,% + width/.get=\umlcomponentMinimumWidth, name/.get=\umlcomponentName,% + draw/.get=\tikzumlcomponentdraw, fill/.get=\tikzumlcomponentfill,% + text/.get=\tikzumlcomponenttext}% + % + \ifthenelse{\equal{\umlcomponentName}{}}{% + \edef\tikzumlComponent@name{#2}% + }{% + \edef\tikzumlComponent@name{\umlcomponentName}% + }% + % + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlComponent@fitname{\tikzumlComponent@name}}\x% + % + \let\tikzumlComponent@nodeNameold\tikzumlComponent@nodeName% + \def\tikzumlComponent@caption{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlComponent@nodeName{\tikzumlComponent@name}}\x% + % + \expandafter\gdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{}% + % + \setcounter{tikzumlComponentSubComponentNum}{0}% + % + \begin{scope}[xshift=\tikzumlcomponentX cm, yshift=\tikzumlcomponentY cm]% +}{% + \addtocounter{tikzumlComponentLevel}{-1}% + \begin{pgfonlayer}{component\thetikzumlComponentLevel}% + % + % if contains nothing, one define a fictive node to enable the fit option + \ifnum\c@tikzumlComponentSubComponentNum=0% + \node[inner ysep=0.5ex, font=\tikzumlfont] (\tikzumlComponent@nodeName-root) at (0,0) {\phantom{\tikzumlComponent@nodeName}};% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{(\tikzumlComponent@nodeName-root)}% + \fi% + % + \ifnum\c@tikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname}% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname{\tikzumlComponentFitTmp (\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-caption)}% + \stepcounter{tikzumlComponentSubComponentNum}% + \fi% + % + \node[inner sep=2ex, font=\tikzumlfont, fit = \csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname] (\tikzumlComponent@nodeName-body) {};% + \node[above, font=\tikzumlfont] (\tikzumlComponent@nodeName-captiontmp) at (\tikzumlComponent@nodeName-body.north) {\tikzumlComponent@caption};% + \node (\tikzumlComponent@nodeName-logotmp) at (\tikzumlComponent@nodeName-captiontmp.north -| \tikzumlComponent@nodeName-body.east) {\picturedcomponent{draw=\tikzumlcomponentdraw, fill=\tikzumlcomponentfill, font=\tikzumlfont} };% + \node[draw=\tikzumlcomponentdraw, fill=\tikzumlcomponentfill, name=\tikzumlComponent@nodeName, fit=(\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-captiontmp)] {};% + \node[font=\tikzumlfont] (\tikzumlComponent@nodeName-caption) at (\tikzumlComponent@nodeName-captiontmp) {\tikzumlComponent@caption};% + \draw (\tikzumlComponent@nodeName-caption.north -| \tikzumlComponent@nodeName-body.east) node[below=-0.8ex, name=\tikzumlComponent@nodeName-logo] {\picturedcomponent{draw=\tikzumlcomponentdraw, fill=\tikzumlcomponentfill, font=\tikzumlfont} };% + \draw (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north west) -- (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north east);% + \end{pgfonlayer}% + \end{scope}% +}% + +% shortcut for empty state +\newcommand{\umlbasiccomponent}[2][]{\begin{umlcomponent}[#1]{#2} \end{umlcomponent}}% + +\newcommand{\umlprovidedinterface}[2][]{% + \def\tikzumlInterfaceWithPort{tikzumlFalse}% + \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.initial={}, distance/.initial=2cm,% + width/.initial=1em, padding/.initial=1cm,% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillcomponentcolor}% + \pgfkeys{/tikzuml/providedinterfacerelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{with port}}{% + \def\tikzumlInterfaceWithPort{tikzumlTrue}% + }{}% + }% + }% + \pgfkeys{/tikzuml/providedinterfacerelation/.cd, #1}% + \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.get=\tikzumlProvidedInterfaceLabel,% + distance/.get=\tikzumlProvidedInterfaceDistance,% + width/.get=\tikzumlProvidedInterfaceWidth,% + padding/.get=\tikzumlProvidedInterfacePadding,% + draw/.get=\tikzumlprovidedinterfacedraw, fill/.get=\tikzumlprovidedinterfacefill,}% + % + \edef\tikzumlProvidedInterface@name{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlProvidedInterface@nodeName{\tikzumlProvidedInterface@name}}\x% + % + \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{% + \node[inner sep=0.5*\tikzumlProvidedInterfaceWidth, rectangle, draw=\tikzumlprovidedinterfacedraw, fill=\tikzumlprovidedinterfacefill] (\tikzumlProvidedInterface@nodeName-east-port) at (\tikzumlProvidedInterface@nodeName.east) {};% + }{% + \node[inner sep=0] (\tikzumlProvidedInterface@nodeName-east-port) at (\tikzumlProvidedInterface@nodeName.east) {};% + }% + \begin{scope}% + \draw (\tikzumlProvidedInterface@nodeName)+(\tikzumlProvidedInterfaceDistance,0) node[inner sep=0, text width=\tikzumlProvidedInterfaceWidth, circle, name=\tikzumlProvidedInterface@nodeName-east-interface-tmp] {};% + \clip (\tikzumlProvidedInterface@nodeName-east-interface-tmp.north) rectangle (\tikzumlProvidedInterface@nodeName-east-interface-tmp.south -| \tikzumlProvidedInterface@nodeName-east-interface-tmp.west);% + \node[inner sep=0, text width=\tikzumlProvidedInterfaceWidth, circle, draw=\tikzumlprovidedinterfacedraw] (\tikzumlProvidedInterface@nodeName-east-interface) at (\tikzumlProvidedInterface@nodeName-east-interface-tmp) {};% + \end{scope}% + \node[above] at (\tikzumlProvidedInterface@nodeName-east-interface.north) {\tikzumlProvidedInterfaceLabel};% + % + \umlrelation[style={tikzuml connector style}, #1]{\tikzumlProvidedInterface@nodeName-east-port}{\tikzumlProvidedInterface@nodeName-east-interface}% + + % add to fit + \draw (\tikzumlProvidedInterface@nodeName-east-interface)+(\tikzumlProvidedInterfacePadding,0) node[name=\tikzumlProvidedInterface@nodeName-east-padding] {};% + \ifnum\thetikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlProvidedInterface@nodeName-east-padding) (\tikzumlProvidedInterface@nodeName-east-port) }% + \fi% +}% + +\newcommand{\umlrequiredinterface}[2][]{% + \def\tikzumlInterfaceWithPort{tikzumlFalse}% + \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.initial={}, distance/.initial=3cm,% + width/.initial=1em, padding/.initial=1cm,% + draw/.initial=\tikzumldrawcolor, fill/.initial=\tikzumlfillcomponentcolor}% + \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{with port}}{% + \def\tikzumlInterfaceWithPort{tikzumlTrue}% + }{}% + }% + }% + \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, #1}% + \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.get=\tikzumlRequiredInterfaceLabel,% + distance/.get=\tikzumlRequiredInterfaceDistance,% + padding/.get=\tikzumlRequiredInterfacePadding,% + width/.get=\tikzumlRequiredInterfaceWidth,% + draw/.get=\tikzumlrequiredinterfacedraw, fill/.get=\tikzumlrequiredinterfacefill,}% + % + \edef\tikzumlRequiredInterface@name{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlRequiredInterface@nodeName{\tikzumlRequiredInterface@name}}\x% + % + \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{% + \node[inner sep=0.5*\tikzumlRequiredInterfaceWidth, rectangle, draw=\tikzumlrequiredinterfacedraw, fill=\tikzumlrequiredinterfacefill] (\tikzumlRequiredInterface@nodeName-west-port) at (\tikzumlRequiredInterface@nodeName.west) {};% + }{% + \node[inner sep=0] (\tikzumlRequiredInterface@nodeName-west-port) at (\tikzumlRequiredInterface@nodeName.west) {};% + }% + \draw (\tikzumlRequiredInterface@nodeName)+(-\tikzumlRequiredInterfaceDistance,0) node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, draw=\tikzumlrequiredinterfacedraw, fill=\tikzumlrequiredinterfacefill, name=\tikzumlRequiredInterface@nodeName-west-interface] {};% + \node[above] at (\tikzumlRequiredInterface@nodeName-west-interface.north) + {\tikzumlRequiredInterfaceLabel};% + % + \umlrelation[style={tikzuml connector style}, #1]{\tikzumlRequiredInterface@nodeName-west-port}{\tikzumlRequiredInterface@nodeName-west-interface}% + + % add to fit + \draw (\tikzumlRequiredInterface@nodeName-west-interface)+(-\tikzumlRequiredInterfacePadding,0) node[name=\tikzumlRequiredInterface@nodeName-west-padding] {};% + \ifnum\thetikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlRequiredInterface@nodeName-west-padding) (\tikzumlRequiredInterface@nodeName-west-port) }% + \fi% +}% + +\newlength{\tikzuml@AC@xa}% +\newlength{\tikzuml@AC@ya}% +\newlength{\tikzuml@AC@xb}% +\newlength{\tikzuml@AC@yb}% +\newlength{\tikzuml@AC@xi}% +\newlength{\tikzuml@AC@yi}% +\newlength{\tikzuml@AC@xic}% +\newlength{\tikzuml@AC@yic}% +\newlength{\tikzuml@AC@xio}% +\newlength{\tikzuml@AC@yio}% +\newlength{\tikzuml@AC@AB}% +\newlength{\tikzuml@AC@lambda}% +\newlength{\tikzuml@AC@xtrc}% +\newlength{\tikzuml@AC@ytrc}% +\newlength{\tikzuml@AC@xtlc}% +\newlength{\tikzuml@AC@ytlc}% +\newlength{\tikzuml@AC@xblc}% +\newlength{\tikzuml@AC@yblc}% +\newlength{\tikzuml@AC@xbrc}% +\newlength{\tikzuml@AC@ybrc}% +\newlength{\tikzuml@AC@middleArm}% + +\newcommand{\umlassemblyconnectorsymbol}[2]{% + \ifthenelse{\NOT\equal{\tikzumlAssemblyConnectorLabel}{}}{% + \edef\tikzuml@ACStart@name{#1}% + \edef\tikzuml@ACEnd@name{#2}% + \edef\tikzuml@AC@width{\tikzumlAssemblyConnectorWidth}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzuml@ACStart@nodeName{\tikzuml@ACStart@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzuml@ACEnd@nodeName{\tikzuml@ACEnd@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzuml@ACInterface@nodeName{\tikzumlAssemblyConnectorSymbolName}}\x% + % + \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}% + \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}% + \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}% + \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}% + \pgfmathsetlength{\tikzuml@AC@xi}{0.5*\tikzuml@AC@xa+0.5*\tikzuml@AC@xb}% + \pgfmathsetlength{\tikzuml@AC@yi}{0.5*\tikzuml@AC@ya+0.5*\tikzuml@AC@yb}% + \pgfmathsetlength{\tikzuml@AC@AB}{veclen(\tikzuml@AC@xa-\tikzuml@AC@xb,\tikzuml@AC@ya-\tikzuml@AC@yb)}% + \pgfmathsetlength{\tikzuml@AC@lambda}{0.25*\tikzuml@AC@width/\tikzuml@AC@AB}% + \pgfmathsetlength{\tikzuml@AC@xic}{\tikzuml@AC@xi-\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@yic}{\tikzuml@AC@yi-\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \pgfmathsetlength{\tikzuml@AC@xio}{\tikzuml@AC@xi+\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@yio}{\tikzuml@AC@yi+\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \node[inner sep=0.5*\tikzuml@AC@width] (\tikzuml@ACInterface@nodeName-interface) at (\tikzuml@AC@xi,\tikzuml@AC@yi) {};% + \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlassemblyconnectordraw, fill=\tikzumlassemblyconnectorfill] (\tikzuml@ACInterface@nodeName-io) at (\tikzuml@AC@xio,\tikzuml@AC@yio) {};% + \begin{scope}% + \pgfmathsetlength{\tikzuml@AC@xtrc}{\tikzuml@AC@xic-2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \pgfmathsetlength{\tikzuml@AC@ytrc}{\tikzuml@AC@yic+2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@xbrc}{\tikzuml@AC@xic+2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \pgfmathsetlength{\tikzuml@AC@ybrc}{\tikzuml@AC@yic-2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@xtlc}{\tikzuml@AC@xic-3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@ytlc}{\tikzuml@AC@yic+3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@ya-\tikzuml@AC@yb)}% + \pgfmathsetlength{\tikzuml@AC@xblc}{\tikzuml@AC@xic+3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xa-\tikzuml@AC@xb)}% + \pgfmathsetlength{\tikzuml@AC@yblc}{\tikzuml@AC@yic-3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \coordinate (\tikzuml@ACInterface@nodeName-trc) at (\tikzuml@AC@xtrc,\tikzuml@AC@ytrc);% + \coordinate (\tikzuml@ACInterface@nodeName-brc) at (\tikzuml@AC@xbrc,\tikzuml@AC@ybrc);% + \coordinate (\tikzuml@ACInterface@nodeName-tlc) at (\tikzuml@AC@xtlc,\tikzuml@AC@ytlc);% + \coordinate (\tikzuml@ACInterface@nodeName-blc) at (\tikzuml@AC@xblc,\tikzuml@AC@yblc);% + \clip (\tikzuml@ACInterface@nodeName-trc) -- (\tikzuml@ACInterface@nodeName-tlc) -- (\tikzuml@ACInterface@nodeName-blc) -- (\tikzuml@ACInterface@nodeName-brc) -- cycle;% + \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlassemblyconnectordraw, fill=\tikzumlassemblyconnectorfill] (\tikzuml@ACInterface@nodeName-ic) at (\tikzuml@AC@xic,\tikzuml@AC@yic) {};% + \end{scope}% + \node[above, font=\tikzumlfont] at (\tikzuml@ACInterface@nodeName-interface.north) + {\tikzumlAssemblyConnectorLabel};% + }{}% +}% + +\newcommand{\umlassemblyconnector}[3][]{% + \def\tikzumlAssemblyConnectorWithPort{tikzumlFalse}% + \def\tikzumlAssemblyConnectorFirstArm{tikzumlFalse}% + \def\tikzumlAssemblyConnectorSecondArm{tikzumlFalse}% + \def\tikzumlAssemblyConnectorMiddleArm{tikzumlFalse}% + \def\tikzumlAssemblyConnectorLastArm{tikzumlFalse}% + \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.initial=--, interface/.initial={},% + arm1/.initial={auto}, arm2/.initial={auto},% + name/.initial=connector-\thetikzumlConnectorNum, width/.initial=1em,% + anchor1/.initial={}, anchor2/.initial={},% + draw/.initial=\tikzumldrawcolor,% + fill assembly connector/.initial=\tikzumlfillassemblyconnectorcolor,% + fill port/.initial=\tikzumlfillportcolor}% + \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{with port}}{% + \def\tikzumlAssemblyConnectorWithPort{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{first arm}}{% + \def\tikzumlAssemblyConnectorFirstArm{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{second arm}}{% + \def\tikzumlAssemblyConnectorSecondArm{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{middle arm}}{% + \def\tikzumlAssemblyConnectorMiddleArm{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{last arm}}{% + \def\tikzumlAssemblyConnectorLastArm{tikzumlTrue}% + }{% + }% + }% + }% + }% + }% + }% + }% + % + \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, #1}% + \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd,% + geometry/.get=\tikzumlAssemblyConnectorGeometry,% + name/.get=\tikzumlAssemblyConnectorName,% + interface/.get=\tikzumlAssemblyConnectorLabel,% + width/.get=\tikzumlAssemblyConnectorWidth,% + arm1/.get=\tikzumlAssemblyConnectorStartArm,% + arm2/.get=\tikzumlAssemblyConnectorEndArm,% + anchor1/.get=\umlAssemblyConnectorStartAnchor,% + anchor2/.get=\umlAssemblyConnectorEndAnchor,% + draw/.get=\tikzumlassemblyconnectordraw,% + fill assembly connector/.get=\tikzumlassemblyconnectorfill,% + fill port/.get=\tikzumlassemblyconnectorportfill}% + % + \edef\tikzumlAssemblyConnectorStart@name{#2}% + \edef\tikzumlAssemblyConnectorEnd@name{#3}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssemblyConnectorStart@nodeName{\tikzumlAssemblyConnectorStart@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssemblyConnectorEnd@nodeName{\tikzumlAssemblyConnectorEnd@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssemblyConnectorLabel@nodeName{\tikzumlAssemblyConnectorLabel}}\x% + % + \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}% + \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}% + \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}% + \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{% + \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% + \def\tikzumlAssemblyConnectorStartAnchor{east}% + \def\tikzumlAssemblyConnectorEndAnchor{west}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{west}% + \def\tikzumlAssemblyConnectorEndAnchor{east}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{% + \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% + \def\tikzumlAssemblyConnectorStartAnchor{east}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{west}% + } + \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{% + \def\tikzumlAssemblyConnectorEndAnchor{south}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{north}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{% + \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% + \def\tikzumlAssemblyConnectorEndAnchor{west}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{east}% + } + \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{% + \def\tikzumlAssemblyConnectorStartAnchor{north}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{south}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@xa + 0.5 * \tikzuml@AC@xb}% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xb+\tikzumlAssemblyConnectorEndArm}% + }% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xa+\tikzumlAssemblyConnectorStartArm}% + }% + \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xa} + \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xb} + \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xa}}{% + \def\tikzumlAssemblyConnectorStartAnchor{east}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{west}% + } + \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xb}}{% + \def\tikzumlAssemblyConnectorEndAnchor{east}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{west}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@ya + 0.5 * \tikzuml@AC@yb}% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@yb+\tikzumlAssemblyConnectorEndArm}% + }% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@ya+\tikzumlAssemblyConnectorStartArm}% + }% + \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@ya}{% + \def\tikzumlAssemblyConnectorStartAnchor{north}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{south}% + } + \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@yb}{% + \def\tikzumlAssemblyConnectorEndAnchor{north}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{south}% + } + }{}% + % + \ifthenelse{\equal{\umlAssemblyConnectorStartAnchor}{}}{% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{\umlAssemblyConnectorStartAnchor}% + }% + \ifthenelse{\equal{\umlAssemblyConnectorEndAnchor}{}}{% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{\umlAssemblyConnectorEndAnchor}% + }% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorWithPort}{tikzumlTrue}}{% + \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlassemblyconnectordraw, fill=\tikzumlassemblyconnectorportfill] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};% + \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlassemblyconnectordraw, fill=\tikzumlassemblyconnectorportfill] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};% + }{% + \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};% + \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};% + }% + % + \umlrelation[style={tikzuml connector style}, #1]{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorEnd@nodeName}% + % + \addtocounter{tikzumlRelationNum}{-1}% + \ifthenelse{\equal{\tikzumlAssemblyConnectorName}{connector-\thetikzumlConnectorNum}}{% + \edef\tikzumlAssemblyConnectorName{relation-\thetikzumlRelationNum}% + \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorLabel@nodeName}% + }{% + \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorName}% + }% + % + \stepcounter{tikzumlRelationNum}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorEnd@nodeName}% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}% + }% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}% + }% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}% + }% + }% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}% + }% + }% + }{}% + }% + }% + }% + }% + \stepcounter{tikzumlConnectorNum}% +}% + +% shortcuts of \umlassemblyconnector +\newcommand{\umlHVassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/HVassemblyconnector/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVassemblyconnector, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/HVassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=-|, #1]{#2}{#3}% +}% + +\newcommand{\umlVHassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/VHassemblyconnector/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHassemblyconnector, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/VHassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=|-, #1]{#2}{#3}% +}% + +\newcommand{\umlHVHassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/HVHassemblyconnector/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHassemblyconnector, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/HVHassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=-|-, #1]{#2}{#3}% +}% + +\newcommand{\umlVHVassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/VHVassemblyconnector/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVassemblyconnector, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/VHVassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=|-|, #1]{#2}{#3}% +}% + +\newcommand{\umldelegateconnector}[3][]{% + \pgfkeys{/tikzuml/delegateconnector/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umldelegateconnector, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/delegateconnector/.cd, #1}% + \umlrelation[style={tikzuml connector style}, stereo=delegate, #1]{#2}{#3}% +}% + + +% shortcuts of \umldelegateconnector +\newcommand{\umlHVdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/HVdelegateconnector/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVdelegateconnector, forbidden option \keyname}% + }{}% + }% + }% + \pgfkeys{/tikzuml/HVdelegateconnector/.cd, #1}% + \umlrelation[style={tikzuml connector style}, stereo=delegate, geometry=-|, #1]{#2}{#3}% +}% + +\newcommand{\umlVHdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/VHdelegateconnector/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHdelegateconnector, forbidden option \keyname}% + }{}% + }% + }% + \pgfkeys{/tikzuml/VHdelegateconnector/.cd, #1}% + \umlrelation[style={tikzuml connector style}, stereo=delegate, geometry=|-, #1]{#2}{#3}% +}% + +\newcommand{\umlHVHdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/HVHdelegateconnector/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHdelegateconnector, forbidden option \keyname}% + }{}% + }% + }% + \pgfkeys{/tikzuml/HVHdelegateconnector/.cd, #1}% + \umlrelation[style={tikzuml connector style}, stereo=delegate, geometry=-|-, #1]{#2}{#3}% +}% + +\newcommand{\umlVHVdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/VHVdelegateconnector/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVdelegateconnector, forbidden option \keyname}% + }{}% + }% + }% + \pgfkeys{/tikzuml/VHVdelegateconnector/.cd, #1}% + \umlrelation[style={tikzuml connector style}, stereo=delegate, geometry=|-|, #1]{#2}{#3}% +}% +%%% End of tikz-uml.sty +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%