49 Commits
final ... lab4

Author SHA1 Message Date
de4bfa4f84 Результаты работы 2024-11-29 20:45:03 +03:00
25a5646093 Особенности реализации 2024-11-29 20:38:29 +03:00
9e3e5cda0c Начало отчёта 2024-11-29 20:21:07 +03:00
a3061e6678 Тесты для filterByPredicate 2024-11-29 20:00:44 +03:00
f05a39da06 filterByPredicate 2024-11-29 19:33:07 +03:00
7ccdb8346e Тесты для первой функции 2024-11-29 19:26:04 +03:00
1aa359b5c1 Написал isCongruent 2024-11-29 19:24:05 +03:00
69e7f5537a Создал проект в stack для 4 лабы 2024-11-29 18:22:51 +03:00
2ad9d5d784 Добавил задание к 4 2024-11-29 18:13:23 +03:00
9f7e34f7cd Добавил все искажения 2024-11-23 17:23:23 +03:00
ddabccfd2b Закодированный текст 2024-11-23 17:14:58 +03:00
bfa7c918b2 Дописки про алфавит 2024-11-21 15:34:40 +03:00
b816f9f17c Обновлённые результаты 2024-11-21 15:34:28 +03:00
d8db6809e4 Алфавит считывается из файла при декодировании 2024-11-21 15:12:08 +03:00
09b722a8eb Сохранение алфавита в файл 2024-11-21 15:08:04 +03:00
66279d0ff4 Сохранения зашифрованного текста в файл 2024-11-21 15:04:13 +03:00
1ea541e8c4 Заключение 2024-11-19 20:34:58 +03:00
377cc25109 Результаты работы программы 2024-11-19 20:27:17 +03:00
3065249023 чтение данных из изображения 2024-11-19 20:05:57 +03:00
ae0bc951aa Сохранение данных в картинке 2024-11-19 20:03:02 +03:00
2097a70cbf Работа с файлами 2024-11-19 19:49:49 +03:00
33c029ce7f Про биты 2024-11-19 19:21:39 +03:00
2781fbabbc Кодирование и декодирование 2024-11-19 19:12:34 +03:00
8c75ccf7ef Шифр Цезаря в мат описании 2024-11-19 18:51:23 +03:00
1d7ceb8fc9 Изображение и текст 2024-11-19 18:31:38 +03:00
842bffc8cd Заготовка для отчёта 2024-11-19 17:21:35 +03:00
622224db79 Добавил кол-во бит в название 2024-11-19 15:18:21 +03:00
b9cf0e7fe3 Баг с извлечением смещения 2024-11-19 14:58:01 +03:00
e90dfd6816 Ввод смещения и кол-ва бит 2024-11-19 14:53:23 +03:00
0faffa20ce Ограничил список доступных функций 2024-11-19 14:37:33 +03:00
19b8202fa8 Извлечение ключа из имени файла 2024-11-19 14:32:34 +03:00
01003c1ee0 Красивенький вывод в консольку 2024-11-19 14:17:30 +03:00
2dedc4416a Дешифровка текста из картинки 2024-11-19 13:56:31 +03:00
3205247f1c Сохранение кода в картинке 2024-11-19 12:33:19 +03:00
54e266b899 Заготовка для генератора картинки 2024-11-18 03:45:29 +03:00
5711244be4 Искажение и сохранение изображения 2024-11-18 02:07:14 +03:00
e6d636cff2 Биты хранятся в Vector 2024-11-18 01:35:40 +03:00
abb078e1b6 Чтение изображения с JuicyPixels 2024-11-17 20:48:05 +03:00
d9076f7dfa Форматирование кода 2024-11-17 20:20:23 +03:00
a69a81d89a Функция декодирования цезаря 2024-11-17 20:19:01 +03:00
f1fd3c1dea Из битов в текст 2024-11-17 20:10:32 +03:00
2dc18efbe4 Текст в список бит 2024-11-17 19:47:13 +03:00
ef9f0448e4 Шифрование по цезарю 2024-11-17 19:21:47 +03:00
098db8a7f0 Динамическое извлечение алфавита 2024-11-17 19:09:02 +03:00
035f2baf76 Задание в текстовом виде 2024-11-17 18:21:09 +03:00
bb1dcb815f Фрагмент биографии 2024-11-17 16:29:25 +03:00
a4ed564c62 Портрет в bmp 2024-11-17 16:13:26 +03:00
40b467cba5 stack project initialized 2024-11-17 16:00:25 +03:00
7b452ed326 Курсач и 3 лаба сами задания 2024-11-17 14:17:47 +03:00
48 changed files with 1617 additions and 0 deletions

BIN
coursework/task.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

3
lab3/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.stack-work/
*~
!*.txt

11
lab3/CHANGELOG.md Normal file
View File

@@ -0,0 +1,11 @@
# Changelog for `lab3`
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to the
[Haskell Package Versioning Policy](https://pvp.haskell.org/).
## Unreleased
## 0.1.0.0 - YYYY-MM-DD

26
lab3/LICENSE Normal file
View File

@@ -0,0 +1,26 @@
Copyright 2024 Author name here
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1
lab3/README.md Normal file
View File

@@ -0,0 +1 @@
# lab3

2
lab3/Setup.hs Normal file
View File

@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain

83
lab3/app/Main.hs Normal file
View File

@@ -0,0 +1,83 @@
module Main (main) where
import Text.Read (readMaybe)
import Codec.Picture
import qualified Data.Vector.Unboxed as VU
import Lib
main :: IO ()
main = do
putStrLn "Введите значение сдвига для шифра Цезаря:"
inputCaesarShift <- getLine
let caesarShift = case readMaybe inputCaesarShift of
Just value -> value
Nothing -> error "Ожидалось целое число!"
putStrLn "Введите количество бит для кодирования:"
inputBitsPerByte <- getLine
let bitsPerByte = case readMaybe inputBitsPerByte of
Just value -> value
Nothing -> error "Ожидалось целое число!"
let sourceTextPath = "resources/biography.txt"
let sourceImagePath = "resources/david.bmp"
let alphabetPath = "tmp/alphabet.txt"
let encryptedTextPath = "tmp/biography_encrypted.txt"
let encodedImagePath = "tmp/david_" ++ show bitsPerByte ++ "_" ++ show caesarShift ++ ".bmp"
let decodedTextPath = "tmp/biography.txt"
putStrLn $ "\nЧтение текста из файла \"" ++ sourceTextPath ++ "\""
inputText <- readFile sourceTextPath
putStrLn $ "10 символов текста: \"" ++ take 10 inputText ++ "\""
putStrLn "\nШифрование текста"
let alphabet = createAlphabetFromText inputText
putStrLn $ "Размер алфавита: " ++ show (length alphabet)
writeFile alphabetPath alphabet
putStrLn $ "Алфавит сохранён в файл \"" ++ alphabetPath ++ "\""
let encryptedText = encryptCaesar alphabet caesarShift inputText
putStrLn $ "10 символов шифра: \"" ++ take 10 encryptedText ++ "\""
writeFile encryptedTextPath encryptedText
putStrLn $ "Зашифрованный текст сохранён в файл \"" ++ encryptedTextPath ++ "\""
let encryptedTextBits = textToBits encryptedText
putStrLn $ "10 битов шифра: \"" ++ show (take 10 $ VU.toList encryptedTextBits) ++ "\""
putStrLn "\nКодирование текста в изображение"
readSourceImageResult <- readImage sourceImagePath
case readSourceImageResult of
Left err -> putStrLn $ "Ошибка при чтении изображения: " ++ err
Right dynImg -> do
let img = convertRGB8 dynImg
let width = imageWidth img
let height = imageHeight img
let totalBits = width * height * 3 * bitsPerByte
let bits = encryptedTextBits VU.++ VU.replicate (totalBits - VU.length encryptedTextBits) 0
let resultImage = generateImage (encodePixel bitsPerByte img bits) width height
saveBmpImage encodedImagePath (ImageRGB8 resultImage)
putStrLn $ "Изображение сохранено по пути: \"" ++ encodedImagePath ++ "\""
putStrLn $ "\nЧтение алфавита из файла \"" ++ alphabetPath ++ "\""
alphabetFromFile <- readFile alphabetPath
putStrLn "\nДекодирование текста из изображения"
case extractShift encodedImagePath of
Just extractedCaesarShift -> do
putStrLn $ "Из названия файла извлечён ключ: " ++ show extractedCaesarShift
readEncodedImageResult <- readImage encodedImagePath
case readEncodedImageResult of
Left err -> putStrLn $ "Ошибка при чтении изображения: " ++ err
Right dynImg -> do
let img = convertRGB8 dynImg
let bits = VU.fromList $ extractBitsFromImage bitsPerByte img
putStrLn $ "10 битов шифра: \"" ++ show (take 10 $ VU.toList bits) ++ "\""
let encryptedTextFromImage = takeWhile (/= '\NUL') (bitsToText bits)
putStrLn $ "10 символов шифра: \"" ++ take 10 encryptedTextFromImage ++ "\""
let decryptedText = decryptCaesar alphabetFromFile extractedCaesarShift encryptedTextFromImage
putStrLn $ "10 символов текста: \"" ++ take 10 decryptedText ++ "\""
writeFile decodedTextPath decryptedText
putStrLn $ "Текст сохранён по пути: \"" ++ decodedTextPath ++ "\""
Nothing -> putStrLn "Не удалось извлечь ключ."

73
lab3/lab3.cabal Normal file
View File

@@ -0,0 +1,73 @@
cabal-version: 2.2
-- This file has been generated from package.yaml by hpack version 0.37.0.
--
-- see: https://github.com/sol/hpack
name: lab3
version: 0.1.0.0
description: Please see the README on GitHub at <https://github.com/githubuser/lab3#readme>
homepage: https://github.com/githubuser/lab3#readme
bug-reports: https://github.com/githubuser/lab3/issues
author: Author name here
maintainer: example@example.com
copyright: 2024 Author name here
license: BSD-3-Clause
license-file: LICENSE
build-type: Simple
extra-source-files:
README.md
CHANGELOG.md
source-repository head
type: git
location: https://github.com/githubuser/lab3
library
exposed-modules:
Lib
other-modules:
Paths_lab3
autogen-modules:
Paths_lab3
hs-source-dirs:
src
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
build-depends:
JuicyPixels
, base >=4.7 && <5
, vector
default-language: Haskell2010
executable lab3-exe
main-is: Main.hs
other-modules:
Paths_lab3
autogen-modules:
Paths_lab3
hs-source-dirs:
app
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
build-depends:
JuicyPixels
, base >=4.7 && <5
, lab3
, vector
default-language: Haskell2010
test-suite lab3-test
type: exitcode-stdio-1.0
main-is: Spec.hs
other-modules:
Paths_lab3
autogen-modules:
Paths_lab3
hs-source-dirs:
test
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
build-depends:
JuicyPixels
, base >=4.7 && <5
, lab3
, vector
default-language: Haskell2010

61
lab3/package.yaml Normal file
View File

@@ -0,0 +1,61 @@
name: lab3
version: 0.1.0.0
github: "githubuser/lab3"
license: BSD-3-Clause
author: "Author name here"
maintainer: "example@example.com"
copyright: "2024 Author name here"
extra-source-files:
- README.md
- CHANGELOG.md
# Metadata used when publishing your package
# synopsis: Short description of your package
# category: Web
# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
# common to point users to the README.md file.
description: Please see the README on GitHub at <https://github.com/githubuser/lab3#readme>
dependencies:
- base >= 4.7 && < 5
- JuicyPixels
- vector
ghc-options:
- -Wall
- -Wcompat
- -Widentities
- -Wincomplete-record-updates
- -Wincomplete-uni-patterns
- -Wmissing-export-lists
- -Wmissing-home-modules
- -Wpartial-fields
- -Wredundant-constraints
library:
source-dirs: src
executables:
lab3-exe:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- lab3
tests:
lab3-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- lab3

5
lab3/report/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
**/*
!.gitignore
!report.tex
!img
!img/*

BIN
lab3/report/img/david.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
lab3/report/img/results.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

463
lab3/report/report.tex Normal file
View File

@@ -0,0 +1,463 @@
\documentclass[a4paper, final]{article}
%\usepackage{literat} % Нормальные шрифты
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\usepackage{tabularx}
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{amsmath}
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
\usepackage{ragged2e} %для растягивания по ширине
\usepackage{setspace} %для межстрочного интервала
\usepackage{moreverb} %для работы с листингами
\usepackage{indentfirst} % для абзацного отступа
\usepackage{moreverb} %для печати в листинге исходного кода программ
\usepackage{pdfpages} %для вставки других pdf файлов
\usepackage{tikz}
\usepackage{graphicx}
\usepackage{afterpage}
\usepackage{longtable}
\usepackage{float}
% \usepackage[paper=A4,DIV=12]{typearea}
\usepackage{pdflscape}
% \usepackage{lscape}
\usepackage{array}
\usepackage{multirow}
\renewcommand\verbatimtabsize{4\relax}
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
\usepackage{listings} %листинги
\usepackage{xcolor} % цвета
\usepackage{hyperref}% для гиперссылок
\usepackage{enumitem} %для перечислений
% Настраиваем листинги, чтобы они использовали счётчик figure
% \AtBeginDocument{
% \renewcommand{\thelstlisting}{\thefigure} % Листинги используют тот же счетчик, что и рисунки
% \renewcommand{\lstlistingname}{Рис.} % Меняем подпись на "Рисунок"
% }
% Автоматически увеличиваем счетчик figure перед каждым листингом
% \let\oldlstlisting\lstlisting
% \renewcommand{\lstlisting}[1][]{%
% \refstepcounter{figure}% Увеличиваем счетчик figure
% \oldlstlisting[#1]% Вызываем оригинальную команду lstlisting
% }
\newcommand{\specialcell}[2][l]{\begin{tabular}[#1]{@{}l@{}}#2\end{tabular}}
\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях
\hypersetup{colorlinks,
allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)
% подгружаемые языки — подробнее в документации listings (это всё для листингов)
\lstloadlanguages{ Haskell}
% включаем кириллицу и добавляем кое−какие опции
\lstset{tabsize=2,
breaklines,
basicstyle=\footnotesize,
columns=fullflexible,
flexiblecolumns,
numbers=left,
numberstyle={\footnotesize},
keywordstyle=\color{blue},
inputencoding=cp1251,
extendedchars=true
}
\lstdefinelanguage{MyC}{
language=Haskell,
% ndkeywordstyle=\color{darkgray}\bfseries,
% identifierstyle=\color{black},
% morecomment=[n]{/**}{*/},
% commentstyle=\color{blue}\ttfamily,
% stringstyle=\color{red}\ttfamily,
% morestring=[b]",
% showstringspaces=false,
% morecomment=[l][\color{gray}]{//},
keepspaces=true,
escapechar=\%,
texcl=true
}
\textheight=24cm % высота текста
\textwidth=16cm % ширина текста
\oddsidemargin=0pt % отступ от левого края
\topmargin=-1.5cm % отступ от верхнего края
\parindent=24pt % абзацный отступ
\parskip=5pt % интервал между абзацами
\tolerance=2000 % терпимость к "жидким" строкам
\flushbottom % выравнивание высоты страниц
% Настройка листингов
\lstset{
language=Haskell,
extendedchars=\true,
inputencoding=utf8,
keepspaces=true,
captionpos=t,
}
\begin{document} % начало документа
% НАЧАЛО ТИТУЛЬНОГО ЛИСТА
\begin{center}
\hfill \break
\hfill \break
\normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
\normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt]
\normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt]
\normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
\hfill \break
\hfill \break
\hfill \break
\hfill \break
\large{Отчет по лабораторной работе №3}\\
\large{по дисциплине}\\
\large{<<Функциональное программирование>>}\\
\large{Вариант 20}\\
\hfill \break
% \hfill \break
% \hfill \break
\end{center}
\small{
\begin{tabular}{lrrl}
\!\!\!Студент, & \hspace{2cm} & & \\
\!\!\!группы 5130201/20102 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
\!\!\!Преподаватель,\\ \hspace{-5pt}к. т. н., доц. & \hspace{2cm} & \underline{\hspace{3cm}} & Моторин Д. Е. \\\\
&&\hspace{4cm}
\end{tabular}
\begin{flushright}
<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2024г.
\end{flushright}
}
\hfill \break
% \hfill \break
\begin{center} \small{Санкт-Петербург, 2024} \end{center}
\thispagestyle{empty} % выключаем отображение номера для этой страницы
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
\newpage
\tableofcontents
% \newpage
% \section*{Введение}
% \addcontentsline{toc}{section}{Введение}
\newpage
\section {Постановка задачи}
Для выполнения лабораторной работы необходимо было сделать следующее. Создать проект в stack. Все чистые функции записать в библиотеку Lib.hs и ограничить доступ к вспомогательным функциям. Использовать do-нотацию для работы с внешними файлами. Найти портрет Дэвида Дойча. Перевести изображение в формат .bmp (24-разрядный). Сохранить в файл формата .txt фрагмент биографии (не менее 1000 символов без пробелов, текст не должен обрываться на середине слова или предложения). Закодировать текст в изображение шифром Цезаря (смещение задается пользователем). Ключ к шифру записывается в имя файла. Написать функцию расшифровывающую текст из изображения используя ключ из имени файла и сохраняющую результат в отдельный текстовый файл. Создать функции шифрующие текст в последний бит каждого байта, последние два бита
каждого байта, …, все биты в байте. В отчете привести примеры искажений изображения.
\newpage
\section {Математическое описание}
\subsection{Шифр Цезаря}
Шифр Цезаря (лат. Notae Caesarianae), также известный как шифр сдвига или код Цезаря — разновидность шифра подстановки, в котором каждый символ в открытом тексте заменяется символом, находящимся на некотором постоянном числе позиций левее или правее него в алфавите (так, в шифре со сдвигом вправо на 3, А была бы заменена на Г, Б станет Д, и так далее). Шифр был назван в честь римского полководца Гая Юлия Цезаря, использовавшего его для секретной переписки со своими военачальниками.
Если сопоставить каждому символу алфавита его порядковый номер (нумеруя с 0), то шифрование и дешифрование можно выразить формулами модульной арифметики~\cite{caesar}:
\[
y = (x + k) \mod n
\]
\[
x = (y - k) \mod n
\]
где: \\
$x$ — символ открытого текста, \\
$y$ — символ шифрованного текста, \\
$n$ — мощность алфавита, \\
$k$ — ключ.
\newpage
\section {Особенности реализации}
\subsection{Исходное изображение и текст}
Для выполнения лабораторной работы необходимо было найти изображение Дэвида Дойча (см. Рис.~\ref{fig:david}). Изображение было переведено из формата \texttt{jpeg} в формат \texttt{bmp} с помощью сайта~\cite{convertio}.
\begin{figure}[h]
\centering
\includegraphics[width=0.5\linewidth]{img/david.jpg}
\caption{Изображение Дэвида Дойча, размещённое на его личном сайте~\cite{david}.}
\label{fig:david}
\end{figure}
Отрывок биографии Дэвида Дойча длиною в 1157 символов без учёта пробелов представлен ниже.
\texttt{
David Elieser Deutsch FRS (DOYTCH; born 18 May 1953) is a British physicist at the University of Oxford. He is a visiting professor in the Department of Atomic and Laser Physics at the Centre for Quantum Computation (CQC) in the Clarendon Laboratory of the University of Oxford. He pioneered the field of quantum computation by formulating a description for a quantum Turing machine, as well as specifying an algorithm designed to run on a quantum computer. He is a proponent of the many-worlds interpretation of quantum mechanics.
Deutsch was born to a Jewish family in Haifa, Israel on 18 May 1953, the son of Oskar and Tikva Deutsch. In London, David attended Geneva House school in Cricklewood (his parents owned and ran the Alma restaurant on Cricklewood Broadway), followed by William Ellis School in Highgate before reading Natural Sciences at Clare College, Cambridge and taking Part III of the Mathematical Tripos. He went on to Wolfson College, Oxford for his doctorate in theoretical physics, about quantum field theory in curved space-time, supervised by Dennis Sciama and Philip Candelas.
His work on quantum algorithms began with a 1985 paper, later expanded in 1992 along with Richard Jozsa, to produce the DeutschJozsa algorithm, one of the first examples of a quantum algorithm that is exponentially faster than any possible deterministic classical algorithm.
}
\subsection{Кодирование и декодирование текста с помощью шифра Цезаря}
Код функций для кодирования и декодирования текста с помощью шифра Цезаря представлен в листинге~\ref{lst:encrypt-caesar}. Функция \texttt{encryptCaesar} принимает алфавит в виде списка символов, смещение и сам текст, а возвращает зашифрованный текст. В её коде используется вспомогательная функция \texttt{indexOf}. Функция принимает список и элемент списка, а возвращает индекс этого элемента. Для создания алфавита используется функция \texttt{createAlphabetFromText}. Она принимает текст, а возвращает алфавит, который в нём используется, в виде списка символов. Для декодирования текста используется функция \texttt{decryptCaesar}, которая, по-сути, является лишь обёрткой над функцией \texttt{encryptCaesar}, так как процесс кодирования осуществляется почти так же как и декодирования. Функция \texttt{decryptCaesar} принимает на вход алфавит, смещение и закодированный текст, а возвращает декодированный текст. Алфавит сохраняется в отдельный файл и должен передаваться вместе с зашифрованным текстом, чтобы этот текст можно было дешифровать.
\begin{lstlisting}[caption={Функции для кодирования и декодирования текста с помощью шифра Цезаря.}, label={lst:encrypt-caesar}]
encryptCaesar :: [Char] -> Int -> String -> String
encryptCaesar alphabet shift text = map caesarChar text
where
caesarChar c = alphabet !! ((indexOf alphabet c + shift) `mod` length alphabet)
indexOf :: (Eq t) => [t] -> t -> Int
indexOf [] _ = -1
indexOf (x : xs) target
| x == target = 0
| otherwise = 1 + indexOf xs target
createAlphabetFromText :: String -> [Char]
createAlphabetFromText [] = []
createAlphabetFromText (x:xs)
| x `elem` alphabet = alphabet
| otherwise = x : alphabet
where
alphabet = createAlphabetFromText xs
decryptCaesar :: [Char] -> Int -> String -> String
decryptCaesar alphabet shift =
encryptCaesar alphabet (alphabetLength - (shift `mod` alphabetLength))
where
alphabetLength = length alphabet
\end{lstlisting}
Пример закодированного с помощью шифра Цезаря текста биографии Дэвида Дойча для смещения 5 представлен ниже.
\noindent
\texttt{
uiHF rWtFaga.ruabYgo;r3qkrNuCLS59Grcm.lrDwrvinrDJRBTrFgrirM.FYFg;rs;ngFo\\
FgYriYrY;arAlFHa.gFYnrmerCdem. Ur9arFgrirHFgFYFlhrs.meaggm.rFlrY;aruasi.\\
YQalYrmerIYmQForil r)iga.r8;ngFogriYrY;ar5alY.arem.r(bilYbQr5mQsbYiYFmlr\\
N5(5TrFlrY;ar5ti.al mlr)icm.iYm.nrmerY;arAlFHa.gFYnrmerCdem. Ur9arsFmlaa\\
.a rY;areFat rmerpbilYbQromQsbYiYFmlrcnrem.QbtiYFlhrir ago.FsYFmlrem.rir\\
pbilYbQrSb.FlhrQio;Flayrigr,attrigrgsaoFenFlhrilrithm.FY;Qr agFhla rYmr.\\
blrmlrirpbilYbQromQsbYa.Ur9arFgrirs.msmlalYrmerY;arQiln,m.t grFlYa.s.aYi\\
YFmlrmerpbilYbQrQao;ilFogU1uabYgo;r,igrcm.lrYmrirxa,Fg;reiQFtnrFlr9iFeiy\\
r-g.iatrmlrDwrvinrDJRByrY;argmlrmerCg2i.ril rSF2HiruabYgo;Ur-lr)ml mlyru\\
iHF riYYal a rEalaHir9mbgargo;mmtrFlr5.Fo2ta,mm rN;Fgrsi.alYgrm,la ril r\\
.ilrY;arItQir.agYib.ilYrmlr5.Fo2ta,mm rM.mi ,inTyremttm,a rcnrPFttFiQrWt\\
tFgrko;mmtrFlr9Fh;hiYarcaem.ar.ai FlhrOiYb.itrkoFaloagriYr5ti.ar5mttahay\\
r5iQc.F haril rYi2Flhr8i.Yr---rmerY;arviY;aQiYFoitrS.FsmgUr9ar,alYrmlrYm\\
rPmtegmlr5mttahayrCdem. rem.r;Fgr moYm.iYarFlrY;am.aYFoitrs;ngFogyricmbY\\
rpbilYbQreFat rY;am.nrFlrob.Ha rgsioaYFQayrgbsa.HFga rcnruallFgrkoFiQiri\\
l r8;FtFsr5il atigU19Fgr,m.2rmlrpbilYbQrithm.FY;Qgrcahilr,FY;rirDJwRrsis\\
a.yrtiYa.radsil a rFlrDJJzritmlhr,FY;rqFo;i. rxmfgiyrYmrs.m boarY;aruabY\\
go;xmfgirithm.FY;QyrmlarmerY;areF.gYradiQstagrmerirpbilYbQrithm.FY;QrY;i\\
YrFgradsmlalYFittnreigYa.rY;ilrilnrsmggFctar aYa.QFlFgYForotiggFoitrithm\\
.FY;QU}
\subsection{Представление текста в виде последовательности бит}
Код функций для преобразования текста в последовательность бит и обратно представлен в листинге~\ref{lst:bit}. Функция \texttt{textToBits} принимает текст в виде строки и возвращает его представление в виде вектора бит. Она использует вспомогательную функцию \texttt{charToBits}, которая преобразует символ в список бит, представляющих его код ASCII в двоичном виде. Для преобразования последовательности бит обратно в текст используется функция \texttt{bitsToText}. Она рекурсивно делит вектор бит на блоки по 8 бит, преобразует каждый блок в символ ASCII и объединяет их в строку. В процессе этого преобразования используется функция \texttt{bitsToInt}, которая преобразует вектор бит в целое число, интерпретируя их как двоичное представление этого числа.
\begin{lstlisting}[caption={Функции для конвертации текста в последовательность бит и обратно.}, label={lst:bit}]
textToBits :: String -> VU.Vector Int
textToBits text = VU.fromList $ concatMap charToBits text
charToBits :: Char -> [Int]
charToBits c = [if testBit (ord c) i then 1 else 0 | i <- [7,6..0]]
bitsToText :: VU.Vector Int -> String
bitsToText bits
| VU.null bits = []
| otherwise = (chr $ bitsToInt (VU.take 8 bits)) : bitsToText (VU.drop 8 bits)
bitsToInt :: VU.Vector Int -> Int
bitsToInt bits =
sum [bit * (2 ^ index) | (bit, index) <- zip (VU.toList bits) [len,(len - 1)..0]]
where
len = VU.length bits - 1
\end{lstlisting}
\subsection{Работа с файлами}
Для работы с текстовыми файлами использовались базовые функции Haskell -- \texttt{readFile} (читает содержимое файла и возвращает его как строку) и \texttt{writeFile} (записывает строку в файл, заменяя его содержимое).
Для работы с изображениями использовалась библиотека \texttt{JuicyPixels}~\cite{JuicyPixels}. С её помощью можно как прочитать изображение в любом популярном формате, так и сохранить его. В частности в работе использовались функции: \texttt{readImage} -- для чтения изображения из указанного файла, \texttt{saveBmpImage} -- для сохранения изображения в формате bmp.
\subsection{Сохранение зашифрованных данных в изображении}
Код функций для создания изображения с закодированными данными представлен в листинге~\ref{lst:genImg}. Функция \texttt{encodePixel} отвечает за кодирование последовательности бит в определённый пиксель изображения. Она принимает количество бит данных, которое будет сохранено в каждый байт изображения, исходное изображение, вектор бит зашифрованных данных, координаты пикселя (\(x, y\)) и возвращает новый пиксель с закодированными данными. Для этого функция вычисляет индекс пикселя в изображении, извлекает соответствующую часть вектора бит данных, преобразует её в целые числа, накладывает битовую маску, которая соответствует количество изменяемых бит в байте, и записывает закодированные данные. Для создания маски используется вспомогательная функция \texttt{createMask}.
Функция \texttt{encodePixel} затем используется вместе с функцией \texttt{generateImage} из библиотеки JuicyPixels для генерации нового изображения.
При сохранении изображения в файл, в его названии сохраняется смещение шифра Цезаря и количество бит в байте, отведённых для хранения зашифрованных данных. Например, название изображения \texttt{david\_2\_10.bmp} означает, что при кодировании использовался код Цезаря со смещением 10, а для хранения закодированных данных в каждом байте изображения использовалось 2 бита.
\begin{lstlisting}[caption={Функции для создания изображения с закодированными данными.}, label={lst:genImg}]
createMask :: Int -> Int
createMask shift = shiftL (complement 0) shift .&. complement 0
encodePixel :: Int -> Image PixelRGB8 -> VU.Vector Int -> Int -> Int -> PixelRGB8
encodePixel bitsPerByte img bits x y = PixelRGB8 newR newG newB
where
width = imageWidth img
index = x + y * width
startPos = index * 3 * bitsPerByte
pixelBits = VU.slice startPos (3 * bitsPerByte) bits
bitsIntR = bitsToInt $ VU.slice 0 bitsPerByte pixelBits
bitsIntG = bitsToInt $ VU.slice bitsPerByte bitsPerByte pixelBits
bitsIntB = bitsToInt $ VU.slice (2 * bitsPerByte) bitsPerByte pixelBits
mask = createMask bitsPerByte
PixelRGB8 r g b = pixelAt img x y
newR = intToWord8 $ ((word8ToInt r) .&. mask) .|. bitsIntR
newG = intToWord8 $ ((word8ToInt g) .&. mask) .|. bitsIntG
newB = intToWord8 $ ((word8ToInt b) .&. mask) .|. bitsIntB
\end{lstlisting}
\subsection{Чтение зашифрованных данных из изображения}
Код функций для чтения зашифрованных данных из изображения представлен в листинге~\ref{lst:readImg}. Функция \texttt{extractBits} извлекает заданное количество бит из одного байта пикселя. Она принимает число бит на байт и байт пикселя, возвращая список бит. Функция \texttt{extractBitsFromPixel} предназначена для извлечения бит из всех трёх цветовых каналов (\(R, G, B\)) пикселя. Она объединяет списки бит из каждого канала в один общий список. Для извлечения бит из всего изображения используется функция \texttt{extractBitsFromImage}. Она последовательно обрабатывает все пиксели изображения, извлекая биты с помощью \texttt{extractBitsFromPixel}, и объединяет их в общий список.
Функция \texttt{extractShift} извлекает смещения для шифра Цезаря из названия файла изображения.
\begin{lstlisting}[caption={Функции для чтения зашифрованных данных из изображения.}, label={lst:readImg}]
extractBits :: Int -> Pixel8 -> [Int]
extractBits bitsPerByte pixelByte =
[ if testBit pixelByte i then 1 else 0 | i <- [bitsPerByte-1, bitsPerByte-2..0] ]
extractBitsFromPixel :: Int -> PixelRGB8 -> [Int]
extractBitsFromPixel bitsPerByte (PixelRGB8 r g b) =
let bitsR = extractBits bitsPerByte r
bitsG = extractBits bitsPerByte g
bitsB = extractBits bitsPerByte b
in bitsR ++ bitsG ++ bitsB
extractBitsFromImage :: Int -> Image PixelRGB8 -> [Int]
extractBitsFromImage bitsPerByte img =
let width = imageWidth img
height = imageHeight img
pixels = [ pixelAt img x y | y <- [0..height - 1], x <- [0..width - 1] ]
in concatMap (extractBitsFromPixel bitsPerByte) pixels
extractShift :: String -> Maybe Int
extractShift path =
let shift = takeWhile (`elem` ['0'..'9']) (reverse $ takeWhile (/= '_') (reverse path))
in readMaybe shift
\end{lstlisting}
\newpage
\section {Результаты работы программы}
При успешном завершении программа создаёт четыре файла: файл изображения с закодированных текстом, текстовый файл с закодированным текстом, текстовый файл с алфавитом и текстовый файл с декодированным текстом.
\begin{figure}[h]
\centering
\includegraphics[width=0.65\linewidth]{img/results.png}
\caption{Результаты работы программы в консоли.}
\label{fig:results}
\end{figure}
На Рис.~\ref{fig:results} представлены результаты работы программы в консоли.
\begin{figure}[h!]
\centering
\includegraphics[width=0.33\linewidth]{img/david_1_20.jpg}
\caption{Изображение с зашифрованными данными (1 бит).}
\label{fig:david1}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.33\linewidth]{img/david_2_20.jpg}
\caption{Изображение с зашифрованными данными (2 бит).}
\label{fig:david2}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.33\linewidth]{img/david_3_20.jpg}
\caption{Изображение с зашифрованными данными (3 бит).}
\label{fig:david3}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.33\linewidth]{img/david_4_20.jpg}
\caption{Изображение с зашифрованными данными (4 бит).}
\label{fig:david4}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.33\linewidth]{img/david_5_20.jpg}
\caption{Изображение с зашифрованными данными (5 бит).}
\label{fig:david5}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.33\linewidth]{img/david_6_20.jpg}
\caption{Изображение с зашифрованными данными (6 бит).}
\label{fig:david6}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.33\linewidth]{img/david_7_20.jpg}
\caption{Изображение с зашифрованными данными (7 бит).}
\label{fig:david7}
\end{figure}
\begin{figure}[h!]
\centering
\includegraphics[width=0.33\linewidth]{img/david_8_20.jpg}
\caption{Изображение с зашифрованными данными (8 бит).}
\label{fig:david8}
\end{figure}
\newpage
\phantom{text}
\newpage
\phantom{text}
\newpage
На Рис.~\ref{fig:david1}-\ref{fig:david8} представлены результирующие изображения с разным количеством бит, отведённых под зашифрованные данные.
\newpage
\section*{Заключение}
\addcontentsline{toc}{section}{Заключение}
В результате выполнения лабораторной работы была создана программа на языке Haskell, которая способна кодировать текстовые данных из указанного файла с помощью шифра Цезаря и сохранять эти данные внутрь изображения. Причём программа позволяет выбрать как смещение для шифра Цезаря, так и количество бит, которое будет использовано в каждом байте изображения для хранения данных.
\newpage
\section*{Список литературы}
\addcontentsline{toc}{section}{Список литературы}
\vspace{-1.5cm}
\begin{thebibliography}{0}
\bibitem{caesar}
Luciano, D., Prichett, G., Cryptology: From Caesar Ciphers to Public-Key Cryptosystems, The College Mathematics Journal, 1987.
\bibitem{david}
David Deutsch -- personal website, URL: \url{https://www.daviddeutsch.org.uk/}, Дата обращения: 19.11.2024
\bibitem{convertio}
Convertio -- BPM to JPG online converter, URL: \url{https://convertio.co/ru/bmp-jpg/}, Дата обращения: 19.11.2024
\bibitem{JuicyPixels}
Hackage -- JuicyPixels: Picture loading/serialization, URL: \url{https://hackage.haskell.org/package/JuicyPixels}, Дата обращения: 19.11.2024
\end{thebibliography}
\end{document}

View File

@@ -0,0 +1,3 @@
David Elieser Deutsch FRS (DOYTCH; born 18 May 1953) is a British physicist at the University of Oxford. He is a visiting professor in the Department of Atomic and Laser Physics at the Centre for Quantum Computation (CQC) in the Clarendon Laboratory of the University of Oxford. He pioneered the field of quantum computation by formulating a description for a quantum Turing machine, as well as specifying an algorithm designed to run on a quantum computer. He is a proponent of the many-worlds interpretation of quantum mechanics.
Deutsch was born to a Jewish family in Haifa, Israel on 18 May 1953, the son of Oskar and Tikva Deutsch. In London, David attended Geneva House school in Cricklewood (his parents owned and ran the Alma restaurant on Cricklewood Broadway), followed by William Ellis School in Highgate before reading Natural Sciences at Clare College, Cambridge and taking Part III of the Mathematical Tripos. He went on to Wolfson College, Oxford for his doctorate in theoretical physics, about quantum field theory in curved space-time, supervised by Dennis Sciama and Philip Candelas.
His work on quantum algorithms began with a 1985 paper, later expanded in 1992 along with Richard Jozsa, to produce the DeutschJozsa algorithm, one of the first examples of a quantum algorithm that is exponentially faster than any possible deterministic classical algorithm.

BIN
lab3/resources/david.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
lab3/resources/david.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

117
lab3/src/Lib.hs Normal file
View File

@@ -0,0 +1,117 @@
module Lib
(
createAlphabetFromText,
encryptCaesar,
decryptCaesar,
textToBits,
bitsToText,
encodePixel,
extractShift,
extractBitsFromImage
)
where
import Codec.Picture
import Text.Read (readMaybe)
import Data.Word (Word8)
import Data.Char (ord, chr)
import Data.Bits (testBit, shiftL, complement, (.|.), (.&.))
import qualified Data.Vector.Unboxed as VU
createAlphabetFromText :: String -> [Char]
createAlphabetFromText [] = []
createAlphabetFromText (x:xs)
| x `elem` alphabet = alphabet
| otherwise = x : alphabet
where
alphabet = createAlphabetFromText xs
indexOf :: (Eq t) => [t] -> t -> Int
indexOf [] _ = -1
indexOf (x : xs) target
| x == target = 0
| otherwise = 1 + indexOf xs target
encryptCaesar :: [Char] -> Int -> String -> String
encryptCaesar alphabet shift text = map caesarChar text
where
caesarChar c = alphabet !! ((indexOf alphabet c + shift) `mod` length alphabet)
decryptCaesar :: [Char] -> Int -> String -> String
decryptCaesar alphabet shift =
encryptCaesar alphabet (alphabetLength - (shift `mod` alphabetLength))
where
alphabetLength = length alphabet
textToBits :: String -> VU.Vector Int
textToBits text = VU.fromList $ concatMap charToBits text
charToBits :: Char -> [Int]
charToBits c = [if testBit (ord c) i then 1 else 0 | i <- [7,6..0]]
-- intToBits :: Int -> [Int]
-- intToBits n = [if testBit n i then 1 else 0 | i <- [31,30..0]]
bitsToText :: VU.Vector Int -> String
bitsToText bits
| VU.null bits = []
| otherwise = (chr $ bitsToInt (VU.take 8 bits)) : bitsToText (VU.drop 8 bits)
bitsToInt :: VU.Vector Int -> Int
bitsToInt bits =
sum [bit * (2 ^ index) | (bit, index) <- zip (VU.toList bits) [len,(len - 1)..0]]
where
len = VU.length bits - 1
intToWord8 :: Int -> Word8
intToWord8 x = fromIntegral x
word8ToInt :: Word8 -> Int
word8ToInt x = fromIntegral x
createMask :: Int -> Int
createMask shift = shiftL (complement 0) shift .&. complement 0
encodePixel :: Int -> Image PixelRGB8 -> VU.Vector Int -> Int -> Int -> PixelRGB8
encodePixel bitsPerByte img bits x y = PixelRGB8 newR newG newB
where
width = imageWidth img
index = x + y * width
startPos = index * 3 * bitsPerByte
pixelBits = VU.slice startPos (3 * bitsPerByte) bits
bitsIntR = bitsToInt $ VU.slice 0 bitsPerByte pixelBits
bitsIntG = bitsToInt $ VU.slice bitsPerByte bitsPerByte pixelBits
bitsIntB = bitsToInt $ VU.slice (2 * bitsPerByte) bitsPerByte pixelBits
mask = createMask bitsPerByte
PixelRGB8 r g b = pixelAt img x y
newR = intToWord8 $ ((word8ToInt r) .&. mask) .|. bitsIntR
newG = intToWord8 $ ((word8ToInt g) .&. mask) .|. bitsIntG
newB = intToWord8 $ ((word8ToInt b) .&. mask) .|. bitsIntB
extractBits :: Int -> Pixel8 -> [Int]
extractBits bitsPerByte pixelByte =
[ if testBit pixelByte i then 1 else 0 | i <- [bitsPerByte-1, bitsPerByte-2..0] ]
extractBitsFromPixel :: Int -> PixelRGB8 -> [Int]
extractBitsFromPixel bitsPerByte (PixelRGB8 r g b) =
let bitsR = extractBits bitsPerByte r
bitsG = extractBits bitsPerByte g
bitsB = extractBits bitsPerByte b
in bitsR ++ bitsG ++ bitsB
extractBitsFromImage :: Int -> Image PixelRGB8 -> [Int]
extractBitsFromImage bitsPerByte img =
let width = imageWidth img
height = imageHeight img
pixels = [ pixelAt img x y | y <- [0..height - 1], x <- [0..width - 1] ]
in concatMap (extractBitsFromPixel bitsPerByte) pixels
extractShift :: String -> Maybe Int
extractShift path =
let shift = takeWhile (`elem` ['0'..'9']) (reverse $ takeWhile (/= '_') (reverse path))
in readMaybe shift

67
lab3/stack.yaml Normal file
View File

@@ -0,0 +1,67 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# A 'specific' Stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# snapshot: lts-22.28
# snapshot: nightly-2024-07-05
# snapshot: ghc-9.6.6
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# snapshot: ./custom-snapshot.yaml
# snapshot: https://example.com/snapshots/2024-01-01.yaml
snapshot:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/41.yaml
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the snapshot.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
# extra-deps: []
# Override default flag values for project packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of Stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=3.1"
#
# Override the architecture used by Stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by Stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

13
lab3/stack.yaml.lock Normal file
View File

@@ -0,0 +1,13 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages: []
snapshots:
- completed:
sha256: 1e32b51d9082fdf6f3bd92accc9dfffd4ddaf406404427fb10bf76d2bc03cbbb
size: 720263
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/41.yaml
original:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/41.yaml

BIN
lab3/task.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

25
lab3/task.txt Normal file
View File

@@ -0,0 +1,25 @@
Практическое задание 3. Обработка файлов в Haskell
№ 20
Создать проект в stack. Все чистые функции записать в библиотеку Lib.hs и ограничить
доступ к вспомогательным функциям. Использовать do-нотацию для работы с внешними
файлами. Найти портрет указанного человека:
Дойч, Дэвид
Перевести изображение в формат .bmp (24-разрядный), при необходимости изменить
ширину и высоту изображения без искажений. Сохранить в файл формата .txt фрагмент
биографии (не менее 1000 символов без пробелов, текст не должен обрываться на середине
слова или предложения). Закодировать текст в изображение методом:
Шифром Цезаря. Смещение задается пользователем
Ключ к шифру записывается в имя файла. Написать функцию расшифровывающую текст
из изображения используя ключ из имени файла и сохраняющую результат в отдельный
текстовый файл.
Создать функции шифрующие текст в последний бит каждого байта, последние два бита
каждого байта, …, все биты в байте. В отчете привести примеры искажений изображения.
Задача со звездочкой*: Разобрать сложный формат данных с использованием библиотек
доступных в Hackage. Зашифровать и расшифровать данные.
Задача с двумя звездочками**: Разобрать сложный формат данных самостоятельно
используя только стандартные библиотеки. Зашифровать и расшифровать данные.

2
lab3/test/Spec.hs Normal file
View File

@@ -0,0 +1,2 @@
main :: IO ()
main = putStrLn "Test suite not yet implemented"

3
lab4/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.stack-work/
*~
!task.txt

11
lab4/CHANGELOG.md Normal file
View File

@@ -0,0 +1,11 @@
# Changelog for `lab4`
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to the
[Haskell Package Versioning Policy](https://pvp.haskell.org/).
## Unreleased
## 0.1.0.0 - YYYY-MM-DD

26
lab4/LICENSE Normal file
View File

@@ -0,0 +1,26 @@
Copyright 2024 Author name here
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1
lab4/README.md Normal file
View File

@@ -0,0 +1 @@
# lab4

2
lab4/Setup.hs Normal file
View File

@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain

14
lab4/app/Main.hs Normal file
View File

@@ -0,0 +1,14 @@
module Main (main) where
import Lib
main :: IO ()
main = do
putStrLn $ "Примеры работы `isCongruent`"
putStrLn $ "isCongruent 10 12 2: " ++ show (isCongruent 10 12 2)
putStrLn $ "isCongruent 10 11 2: " ++ show (isCongruent 10 11 2)
putStrLn $ "\nПример работы `filterByPredicate`"
let predicate x = x > 5
putStrLn $ "filterByPredicate (>5) [1, 6, 3, 7, 2]: "
++ show (filterByPredicate predicate [1 :: Int, 6, 3, 7, 2])

68
lab4/lab4.cabal Normal file
View File

@@ -0,0 +1,68 @@
cabal-version: 2.2
-- This file has been generated from package.yaml by hpack version 0.37.0.
--
-- see: https://github.com/sol/hpack
name: lab4
version: 0.1.0.0
description: Please see the README on GitHub at <https://github.com/githubuser/lab4#readme>
homepage: https://github.com/githubuser/lab4#readme
bug-reports: https://github.com/githubuser/lab4/issues
author: Author name here
maintainer: example@example.com
copyright: 2024 Author name here
license: BSD-3-Clause
license-file: LICENSE
build-type: Simple
extra-source-files:
README.md
CHANGELOG.md
source-repository head
type: git
location: https://github.com/githubuser/lab4
library
exposed-modules:
Lib
other-modules:
Paths_lab4
autogen-modules:
Paths_lab4
hs-source-dirs:
src
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
build-depends:
base >=4.7 && <5
default-language: Haskell2010
executable lab4-exe
main-is: Main.hs
other-modules:
Paths_lab4
autogen-modules:
Paths_lab4
hs-source-dirs:
app
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
build-depends:
base >=4.7 && <5
, lab4
default-language: Haskell2010
test-suite lab4-test
type: exitcode-stdio-1.0
main-is: Spec.hs
other-modules:
Paths_lab4
autogen-modules:
Paths_lab4
hs-source-dirs:
test
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
build-depends:
QuickCheck
, base >=4.7 && <5
, lab4
default-language: Haskell2010

60
lab4/package.yaml Normal file
View File

@@ -0,0 +1,60 @@
name: lab4
version: 0.1.0.0
github: "githubuser/lab4"
license: BSD-3-Clause
author: "Author name here"
maintainer: "example@example.com"
copyright: "2024 Author name here"
extra-source-files:
- README.md
- CHANGELOG.md
# Metadata used when publishing your package
# synopsis: Short description of your package
# category: Web
# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
# common to point users to the README.md file.
description: Please see the README on GitHub at <https://github.com/githubuser/lab4#readme>
dependencies:
- base >= 4.7 && < 5
ghc-options:
- -Wall
- -Wcompat
- -Widentities
- -Wincomplete-record-updates
- -Wincomplete-uni-patterns
- -Wmissing-export-lists
- -Wmissing-home-modules
- -Wpartial-fields
- -Wredundant-constraints
library:
source-dirs: src
executables:
lab4-exe:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- lab4
tests:
lab4-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- lab4
- QuickCheck

5
lab4/report/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
**/*
!.gitignore
!report.tex
!img
!img/*

BIN
lab4/report/img/main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
lab4/report/img/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

320
lab4/report/report.tex Normal file
View File

@@ -0,0 +1,320 @@
\documentclass[a4paper, final]{article}
%\usepackage{literat} % Нормальные шрифты
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\usepackage{tabularx}
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{amsmath}
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
\usepackage{ragged2e} %для растягивания по ширине
\usepackage{setspace} %для межстрочного интервала
\usepackage{moreverb} %для работы с листингами
\usepackage{indentfirst} % для абзацного отступа
\usepackage{moreverb} %для печати в листинге исходного кода программ
\usepackage{pdfpages} %для вставки других pdf файлов
\usepackage{tikz}
\usepackage{graphicx}
\usepackage{afterpage}
\usepackage{longtable}
\usepackage{float}
% \usepackage[paper=A4,DIV=12]{typearea}
\usepackage{pdflscape}
% \usepackage{lscape}
\usepackage{array}
\usepackage{multirow}
\renewcommand\verbatimtabsize{4\relax}
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
\usepackage{listings} %листинги
\usepackage{xcolor} % цвета
\usepackage{hyperref}% для гиперссылок
\usepackage{enumitem} %для перечислений
% Настраиваем листинги, чтобы они использовали счётчик figure
% \AtBeginDocument{
% \renewcommand{\thelstlisting}{\thefigure} % Листинги используют тот же счетчик, что и рисунки
% \renewcommand{\lstlistingname}{Рис.} % Меняем подпись на "Рисунок"
% }
% Автоматически увеличиваем счетчик figure перед каждым листингом
% \let\oldlstlisting\lstlisting
% \renewcommand{\lstlisting}[1][]{%
% \refstepcounter{figure}% Увеличиваем счетчик figure
% \oldlstlisting[#1]% Вызываем оригинальную команду lstlisting
% }
\newcommand{\specialcell}[2][l]{\begin{tabular}[#1]{@{}l@{}}#2\end{tabular}}
\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях
\hypersetup{colorlinks,
allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)
% подгружаемые языки — подробнее в документации listings (это всё для листингов)
\lstloadlanguages{ Haskell}
% включаем кириллицу и добавляем кое−какие опции
\lstset{tabsize=2,
breaklines,
basicstyle=\footnotesize,
columns=fullflexible,
flexiblecolumns,
numbers=left,
numberstyle={\footnotesize},
keywordstyle=\color{blue},
inputencoding=cp1251,
extendedchars=true
}
\lstdefinelanguage{MyC}{
language=Haskell,
% ndkeywordstyle=\color{darkgray}\bfseries,
% identifierstyle=\color{black},
% morecomment=[n]{/**}{*/},
% commentstyle=\color{blue}\ttfamily,
% stringstyle=\color{red}\ttfamily,
% morestring=[b]",
% showstringspaces=false,
% morecomment=[l][\color{gray}]{//},
keepspaces=true,
escapechar=\%,
texcl=true
}
\textheight=24cm % высота текста
\textwidth=16cm % ширина текста
\oddsidemargin=0pt % отступ от левого края
\topmargin=-1.5cm % отступ от верхнего края
\parindent=24pt % абзацный отступ
\parskip=5pt % интервал между абзацами
\tolerance=2000 % терпимость к "жидким" строкам
\flushbottom % выравнивание высоты страниц
% Настройка листингов
\lstset{
language=Haskell,
extendedchars=\true,
inputencoding=utf8,
keepspaces=true,
captionpos=t,
}
\begin{document} % начало документа
% НАЧАЛО ТИТУЛЬНОГО ЛИСТА
\begin{center}
\hfill \break
\hfill \break
\normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
\normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt]
\normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt]
\normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
\hfill \break
\hfill \break
\hfill \break
\hfill \break
\large{Отчет по лабораторной работе №4}\\
\large{по дисциплине}\\
\large{<<Функциональное программирование>>}\\
\large{Вариант 20}\\
\hfill \break
% \hfill \break
% \hfill \break
\end{center}
\small{
\begin{tabular}{lrrl}
\!\!\!Студент, & \hspace{2cm} & & \\
\!\!\!группы 5130201/20102 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
\!\!\!Преподаватель,\\ \hspace{-5pt}к. т. н., доц. & \hspace{2cm} & \underline{\hspace{3cm}} & Моторин Д. Е. \\\\
&&\hspace{4cm}
\end{tabular}
\begin{flushright}
<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2024г.
\end{flushright}
}
\hfill \break
% \hfill \break
\begin{center} \small{Санкт-Петербург, 2024} \end{center}
\thispagestyle{empty} % выключаем отображение номера для этой страницы
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
\newpage
\tableofcontents
\newpage
\section {Постановка задачи}
Для выполнения лабораторной работы необходимо было сделать следующее. Создать проект в \texttt{stack}. Функции записать в библиотеку \texttt{Lib.hs} и ограничить доступ к вспомогательным функциям. Тесты записать в \texttt{Spec.hs}.
\textbf{Функция 1:} Напишите функцию проверки равенства по модулю \texttt{isCongruent :: Int -> Int -> Int -> Bool}, которая проверяет, равны ли два числа по модулю третьего числа. Используя \texttt{QuickCheck}, проверьте следующие свойства:
\begin{enumerate}
\item Если два числа равны по модулю, то их разность делится на модуль:
\texttt{isCongruent a b m == (modulus (a - b) m == 0)}.
\item Равенство по модулю является симметричным:
\texttt{isCongruent a b m == isCongruent b a m}.
\item Если одно число равно другому, то они равны по любому модулю:
если \texttt{a == b}, то \texttt{isCongruent a b m == True}.
\end{enumerate}
\textbf{Функция 2:} Напишите функцию \texttt{filterByPredicate :: (a -> Bool) -> [a] -> [a]}, которая фильтрует элементы списка по заданному предикату. Используя \texttt{QuickCheck}, проверьте следующие свойства:
\begin{enumerate}
\item Все элементы результата удовлетворяют предикату: для каждого элемента \texttt{x} из результата должно выполняться условие: \texttt{predicate x == True}.
\item Длина результата не превышает длину исходного списка:
\texttt{length (filterByPredicate predicate xs) <= length xs}.
\item Если предикат всегда возвращает \texttt{True}, то результат совпадает с исходным списком:
если \texttt{predicate x == True} для всех \texttt{x}, то \texttt{filterByPredicate predicate xs == xs}.
\end{enumerate}
\newpage
\section {Особенности реализации}
\subsection{Функция isCongruent}
Код функции для проверки числовой конгруэнтности представлен в листинге~\ref{lst:is-congruent}. Функция \texttt{isCongruent} принимает три числа: \texttt{a}, \texttt{b} и \texttt{d}. Она возвращает \texttt{True}, если остатки от деления \texttt{a} и \texttt{b} на \texttt{d} равны, и \texttt{False} в противном случае.
\begin{lstlisting}[caption={Функция для проверки числовой конгруэнтности.}, label={lst:is-congruent}]
isCongruent :: Int -> Int -> Int -> Bool
isCongruent a b d = a `mod` d == b `mod` d
\end{lstlisting}
\subsection{Функция filterByPredicate}
Код функции для фильтрации элементов списка на основе предиката представлен в листинге~\ref{lst:filter-by-predicate}. Функция \texttt{filterByPredicate} принимает предикат (\texttt{predicate}) и список (\texttt{[a]}). Она возвращает новый список, содержащий только те элементы исходного списка, для которых предикат возвращает \texttt{True}.
\begin{lstlisting}[caption={Функция для фильтрации списка по предикату.}, label={lst:filter-by-predicate}]
filterByPredicate :: (a -> Bool) -> [a] -> [a]
filterByPredicate _ [] = []
filterByPredicate predicate (x:xs)
| predicate x = x : filteredTail
| otherwise = filteredTail
where
filteredTail = filterByPredicate predicate xs
\end{lstlisting}
\subsection{Тесты для функции isCongruent}
Для тестирования функции \texttt{isCongruent} использовались свойства, проверяемые с использованием библиотеки QuickCheck. Ниже приведены описания тестов, представленных в листинге~\ref{lst:congruent-tests}.
\begin{itemize}
\item \texttt{propCongruentDifference}: Проверяет, что два числа конгруэнтны по модулю \texttt{m}, если и только если разность этих чисел делится на \texttt{m} без остатка.
\item \texttt{propCongruentSymmetric}: Проверяет симметричность конгруэнтности, то есть, если \texttt{a} конгруэнтно \texttt{b}, то \texttt{b} конгруэнтно \texttt{a}.
\item \texttt{propCongruentEqualNumbers}: Проверяет, что любое число \texttt{a} всегда конгруэнтно самому себе по любому ненулевому модулю.
\end{itemize}
\begin{lstlisting}[caption={Тесты для функции \texttt{isCongruent} с использованием QuickCheck.}, label={lst:congruent-tests}]
propCongruentDifference :: Int -> Int -> Int -> Property
propCongruentDifference a b m =
m /= 0 ==> isCongruent a b m == ((a - b) `mod` m == 0)
propCongruentSymmetric :: Int -> Int -> Int -> Property
propCongruentSymmetric a b m =
m /= 0 ==> isCongruent a b m == isCongruent b a m
propCongruentEqualNumbers :: Int -> Int -> Property
propCongruentEqualNumbers a m =
m /= 0 ==> isCongruent a a m == True
\end{lstlisting}
\subsection{Тесты для функции filterByPredicate}
Для тестирования функции \texttt{filterByPredicate} использовались свойства, проверяемые с использованием библиотеки QuickCheck. Описание тестов приведено в листинге~\ref{lst:filter-tests}.
\begin{itemize}
\item \texttt{propFilterByPredicateSatisfiesPredicate}: Проверяет, что все элементы результирующего списка удовлетворяют переданному предикату.
\item \texttt{propFilterByPredicateLength}: Проверяет, что длина результирующего списка не превышает длину исходного списка.
\item \texttt{propFilterByPredicateAlwaysTrue}: Проверяет, что если предикат всегда возвращает \texttt{True}, результирующий список совпадает с исходным.
\end{itemize}
\begin{lstlisting}[caption={Тесты для функции \texttt{filterByPredicate} с использованием QuickCheck.}, label={lst:filter-tests}]
propFilterByPredicateSatisfiesPredicate :: Fun Int Bool -> [Int] -> Bool
propFilterByPredicateSatisfiesPredicate (Fun _ predicate) xs =
all predicate (filterByPredicate predicate xs)
propFilterByPredicateLength :: Fun Int Bool -> [Int] -> Bool
propFilterByPredicateLength (Fun _ predicate) xs =
length (filterByPredicate predicate xs) <= length xs
propFilterByPredicateAlwaysTrue :: [Int] -> Bool
propFilterByPredicateAlwaysTrue xs =
filterByPredicate (\_ -> True) xs == xs
\end{lstlisting}
\subsection{Запуск тестов}
Для выполнения всех тестов в проекте создан файл \texttt{Spec.hs}, в котором определена функция \texttt{main}. Она последовательно запускает все тесты, используя библиотеку \texttt{QuickCheck}. Код функции \texttt{main} приведён в листинге~\ref{lst:test-main}.
Функция \texttt{quickCheck} используется для автоматического тестирования свойств. Она генерирует случайные входные данные, проверяет выполнение свойства на каждом из них и сообщает о результатах. В случае провала теста \texttt{quickCheck} предоставляет пример данных, на которых свойство не выполняется.
Для сборки проекта и выполнения всех тестов достаточно выполнить команду \texttt{stack test}.
\begin{lstlisting}[caption={Функция \texttt{main} для запуска тестов.}, label={lst:test-main}]
main :: IO ()
main = do
quickCheck propCongruentDifference
quickCheck propCongruentSymmetric
quickCheck propCongruentEqualNumbers
quickCheck propFilterByPredicateSatisfiesPredicate
quickCheck propFilterByPredicateLength
quickCheck propFilterByPredicateAlwaysTrue
\end{lstlisting}
\newpage
\section {Результаты работы программы}
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/main.png}
\caption{Результаты работы программы.}
\label{fig:main}
\end{figure}
Сама программа лишь выводит примеры работы функций \texttt{isCongruent} и \texttt{filterByPredicate}. Результаты её запуска представлены на Рис.~\ref{fig:main}.
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/test.png}
\caption{Результаты запуска тестов.}
\label{fig:test}
\end{figure}
Результаты запуска тестов с помощью команды \texttt{stack test} представлены на Рис.~\ref{fig:test}.
\newpage
\section*{Заключение}
\addcontentsline{toc}{section}{Заключение}
В данной работе был создан проект с использованием \texttt{stack}, включающий разработку и тестирование двух функций: проверки равенства по модулю и фильтрации списка по предикату. Для каждой функции были написаны три теста. Тесты запускаются на сгенерированных данных с помощью \texttt{QuickCheck}. Они подтверждают корректность реализации этих функций. В ходе выполнения лабораторной работы были получены базовые знания об автоматическом тестировании программ, написанных на языке Haskell.
\newpage
\section*{Список литературы}
\addcontentsline{toc}{section}{Список литературы}
\vspace{-1.5cm}
\begin{thebibliography}{0}
\bibitem{JuicyPixels}
Hackage -- QuickCheck: Automatic testing of Haskell programs, URL: \url{https://hackage.haskell.org/package/QuickCheck}, Дата обращения: 19.11.2024
\end{thebibliography}
\end{document}

16
lab4/src/Lib.hs Normal file
View File

@@ -0,0 +1,16 @@
module Lib
( isCongruent,
filterByPredicate
) where
isCongruent :: Int -> Int -> Int -> Bool
isCongruent a b d = a `mod` d + 1 == b `mod` d
filterByPredicate :: (a -> Bool) -> [a] -> [a]
filterByPredicate _ [] = []
filterByPredicate predicate (x:xs)
| predicate x = x : filteredTail
| otherwise = filteredTail
where
filteredTail = filterByPredicate predicate xs

67
lab4/stack.yaml Normal file
View File

@@ -0,0 +1,67 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# A 'specific' Stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# snapshot: lts-22.28
# snapshot: nightly-2024-07-05
# snapshot: ghc-9.6.6
#
# The location of a snapshot can be provided as a file or url. Stack assumes
# a snapshot provided as a file might change, whereas a url resource does not.
#
# snapshot: ./custom-snapshot.yaml
# snapshot: https://example.com/snapshots/2024-01-01.yaml
snapshot:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# subdirs:
# - auto-update
# - wai
packages:
- .
# Dependency packages to be pulled from upstream that are not in the snapshot.
# These entries can reference officially published versions as well as
# forks / in-progress versions pinned to a git hash. For example:
#
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
# extra-deps: []
# Override default flag values for project packages and extra-deps
# flags: {}
# Extra package databases containing global packages
# extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of Stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=3.1"
#
# Override the architecture used by Stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by Stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor

13
lab4/stack.yaml.lock Normal file
View File

@@ -0,0 +1,13 @@
# This file was autogenerated by Stack.
# You should not edit this file by hand.
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files
packages: []
snapshots:
- completed:
sha256: 08bd13ce621b41a8f5e51456b38d5b46d7783ce114a50ab604d6bbab0d002146
size: 720271
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml
original:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml

BIN
lab4/task.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

19
lab4/task.txt Normal file
View File

@@ -0,0 +1,19 @@
Практическое задание 4. Тестирование в Haskell
№ 12
Создать проект в stack. Функции записать в библиотеку Lib.hs и ограничить доступ к вспомогательным функциям. Тесты записать в Spec.hs.
Функция 1: Напишите функцию проверки равенства по модулю isCongruent :: Int -> Int -> Int -> Bool, которая проверяет, равны ли два числа по модулю третьего числа. Используя QuickCheck, проверьте следующие свойства:
1. Если два числа равны по модулю, то их разность делится на модуль:
isCongruent a b m == (modulus (a - b) m == 0).
2. Равенство по модулю является симметричным:
isCongruent a b m == isCongruent b a m.
3. Если одно число равно другому, то они равны по любому модулю:
если a == b, то isCongruent a b m == True.
Функция 2: Напишите функцию filterByPredicate :: (a -> Bool) -> [a] -> [a], которая фильтрует элементы списка по заданному предикату. Используя QuickCheck, проверьте следующие свойства:
1. Все элементы результата удовлетворяют предикату: для каждого элемента x из результата должно выполняться условие: predicate x == True.
2. Длина результата не превышает длину исходного списка: length (filterByPredicate predicate xs) <= length xs.
3. Если предикат всегда возвращает True, то результат совпадает с исходным списком: если predicate x == True для всех x, то filterByPredicate predicate xs == xs.

37
lab4/test/Spec.hs Normal file
View File

@@ -0,0 +1,37 @@
import Test.QuickCheck
import Lib
propCongruentDifference :: Int -> Int -> Int -> Property
propCongruentDifference a b m =
m /= 0 ==> isCongruent a b m == ((a - b) `mod` m == 0)
propCongruentSymmetric :: Int -> Int -> Int -> Property
propCongruentSymmetric a b m =
m /= 0 ==> isCongruent a b m == isCongruent b a m
propCongruentEqualNumbers :: Int -> Int -> Property
propCongruentEqualNumbers a m =
m /= 0 ==> isCongruent a a m == True
propFilterByPredicateSatisfiesPredicate :: Fun Int Bool -> [Int] -> Bool
propFilterByPredicateSatisfiesPredicate (Fun _ predicate) xs =
all predicate (filterByPredicate predicate xs)
propFilterByPredicateLength :: Fun Int Bool -> [Int] -> Bool
propFilterByPredicateLength (Fun _ predicate) xs =
length (filterByPredicate predicate xs) <= length xs
propFilterByPredicateAlwaysTrue :: [Int] -> Bool
propFilterByPredicateAlwaysTrue xs =
filterByPredicate (\_ -> True) xs == xs
main :: IO ()
main = do
quickCheck propCongruentDifference
quickCheck propCongruentSymmetric
quickCheck propCongruentEqualNumbers
quickCheck propFilterByPredicateSatisfiesPredicate
quickCheck propFilterByPredicateLength
quickCheck propFilterByPredicateAlwaysTrue