Программа позволяет выполнить три вида операций над матрицами: сложение двух матриц, транспонирование матриц и умножение двух матриц. Выбор вида операции осуществляется путём выбора нужного переключателя в блоке радио-кнопок «Action». Запуск операции на выполнение осуществляется нажатием кнопки «Process».
Есть вариант сборки программы MTX.exeв консольном формате. Такой вариант сборки не предполагает диалога с пользователем( Рисунок 2).
Рисунок 1 - Вид интерфейса программа сразу после запуска на выполнение
.
Рисунок 2 - Окно в консольном формате
6. Руководство программиста
Сборка программного комплекса осуществляется средствами MicrosoftVisualStudio 2019 с помощью солюшн-файла «MTX.sln». Имеется единственная конфигурация Release/x64, конфигурация для архитектуры x86 может быть добавлена по желанию программиста.
Сборка может быть выполнена в режиме с графическим интерфейсом или без графического интерфейса. Переключение режима осуществляется включением или выключением директивы препроцессора define в первой строке файла MTX.cpp.
Интерфейс программы после запуска выглядит так, как показано на Рисунке 1. Три элемента «textbox» в основной части окна показывают табличное представление матриц a, b и c, которые участвуют в основных операциях, выполняемых программой.
Блок радио-кнопок «Action» позволяет выбрать тип операции над матрицами для осуществления.
Кнопка «Process» в нижней части окна позволяет осуществить выбранную операцию и автоматически вызывает обновление содержимого объектов, отображающих матрицы a, b и c.
Допускается вариант сборки программы MTX.exe в консольном формате. В этом случае программа не выводит диалоговых окон, а только осуществляет ряд тестов матричных операций с выводом результатов на консоль в текстовом виде.
Рисунок 3 показывает пример внешнего вида окна программы после выполнения одной из операций.
Рисунок 3 - Вид интерфейса программа сразу после выполнения операции суммирования двух матриц.
7. Программная реализация
Программная реализация программного комплекса содержит следующие файлы исходного кода:
MTX.cpp - основная единица компиляции, содержит в себе функцию «main()», то есть точку входа для C++-программы. Функция main() содержит набор тестов алгоритмов и код, реализующий графический интерфейс и процесс диалога с пользователем с помощью библиотекиграфического интерфейса пользователя «nana» (https://github.com/cnjinhao/nanaОшибка! Недопустимый объект гиперссылки.
Компонент в составеmain(), отвечающий за графический интерфейс пользователя, может быть отключен на этапе компиляции с помощью устранения символа препроцессораWITH_GUI.
ФайлMTX.cpp включает в себя остальные компоненты программного комплекса с помощью директив #include.
Файл element.h - содержит в себе декларацию структуры хранения элемента матрицы в форматеCOO, то есть триплета из двух координат и значения. Структура определёна с помощью стандартного класса стандартной библиотеки шаблоновC++ (STL) std::tuple. Там же определён вспомогательный классelement_traits, предоставляющий некоторый сервис для упрощения работы с классом элемента. Дополнительно определены несколько функций сравнения элементов друг с другом по координатам.
Файлcoo_mtx.h- содержит декларацию и реализацию класса, инкапсулирующего в себе данные и основной код операций, относящихся к сущности «разреженная матрица в формате COO».
Файлsp_m_algo.h - содержит реализацию трёх матричных операций, которые составляют основу функциональности данного программного комплекса. Это функции:
sp_mm_add(coo_mtx&a, coo_mtx&b, coo_mtx&c);
- выполняет сложение двух матриц aи bодинаковой размерности и помещает результат в пустую матрицу c;
sp_m_transpose(coo_mtx&a);
- выполняет транспонирование матрицы a, не создавая новой матрицы, то есть, путём изменения исходной матрицы;
sp_mm_multiply(coo_mtx&a, coo_mtx&b, coo_mtx&c);
- выполняет перемножение двух матрицaиbи помещает результат в пустую матрицу c. Размерности исходных матриц должны соответствовать требованию для операции матричного умножения.
Файл output.h - реализует операцию вывода заданной матрицы в табличном формате.
Листингпрограммы:
#defineWITH_GUI
#ifdefWITH_GUI
#include<nana/gui.hpp>
#include<nana/gui/widgets/button.hpp>
#include<nana/gui/widgets/group.hpp>
#include<nana/gui/widgets/textbox.hpp>
#include<nana/gui/widgets/label.hpp>
#endif
#include"element.h"// COO matrix element-level structures and helpers
#include"coo_mtx.h"// COO matrix class implementation
#include"sp_m_algo.h"// sp_mm_add(), sp_m_transpose() and sp_mm_multiply() algorithms implementation
#include"output.h"// Matrix pretty print implementation
int main()
{
// Text mode basic tests
{
coo_mtxa(5, 5);
a.add(element_t(0, 0, 1));
a.add(element_t(1, 1, 2));
a.add(element_t(2, 2, 3));
a.add(element_t(3, 3, 4));
a.add(element_t(4, 4, 5));
std::cout<<"|a|:"<<std::endl;
std::cout<< a <<std::endl;
coo_mtx b(5, 5);
b.add(element_t(0, 4, 200));
b.add(element_t(1, 3, 300));
b.add(element_t(2, 2, 400));
b.add(element_t(3, 1, 500));
b.add(element_t(4, 0, 600));
std::cout<<"|b|:"<<std::endl;
std::cout<< b <<std::endl;
coo_mtx c(5, 5);
sp_mm_add(a, b, c);
std::cout<<"|c|=|a|+|b|:"<<std::endl;
std::cout<< c <<std::endl;
sp_m_transpose(c);
std::cout<<"Transpose(|c|):"<<std::endl;
std::cout<< c <<std::endl;
}
{
coo_mtxa(3, 3);
a.add(element_t(0, 0, 1));
a.add(element_t(2, 2, 9));
coo_mtx b(3, 3);
b.add(element_t(0, 0, 1));
b.add(element_t(1, 1, 1));
b.add(element_t(2, 2, 1));
std::cout<<"|a|:"<<std::endl;
std::cout<< a <<std::endl;
std::cout<<"|b|:"<<std::endl;
std::cout<< b <<std::endl;
coo_mtx c(3, 3);
sp_mm_multiply(a, b, c);
std::cout<<"|c|=|a|*|b|:"<<std::endl;
std::cout<< c <<std::endl;
}
{
coo_mtxa(3, 3);
a.add(element_t(0, 0, 1));
a.add(element_t(1, 1, 2));
a.add(element_t(2, 2, 3));
coo_mtx b(3, 3);
b.add(element_t(0, 2, 10));
b.add(element_t(1, 1, 100));
b.dd(element_t(2, 0, 1000));
std::cout<<"|a|:"<<std::endl;
std::cout<< a <<std::endl;
std::cout<<"|b|:"<<std::endl;
std::cout<< b <<std::endl;
coo_mtx c(3, 3);
sp_mm_multiply(a, b, c);
std::cout<<"|c|=|a|*|b|:"<<std::endl;
std::cout<< c <<std::endl;
}
#ifdefWITH_GUI
coo_mtxa(5, 5);
a.add(element_t(0, 0, 1));
a.add(element_t(1, 1, 2));
a.add(element_t(2, 2, 3));
a.add(element_t(3, 3, 4));
a.add(element_t(4, 4, 5));
coo_mtx b(5, 5);
b.add(element_t(0, 4, 200));
b.add(element_t(1, 3, 300));
b.add(element_t(2, 2, 400));
b.add(element_t(3, 1, 500));
b.add(element_t(4, 0, 600));
coo_mtx c(5, 5);
std::stringA_str, B_str, C_str;
{ std::stringstreamss; ss<< a; A_str=ss.str(); }
{ std::stringstreamss; ss<< b; B_str=ss.str(); }
usingnamespace nana;
formfm(API::make_center(900, 600));
fm.caption("MTX -- sparse matrix operations");
placefm_place {fm};
enumaction_t { SUM, TRANS, MULT };
action_t action = SUM;
textboxA_box { fm, A_str };
A_box.multi_lines(true).editable(false);
labelA_lab(fm, "Matrix |A|:");
textboxB_box{ fm, B_str };
B_box.multi_lines(true).editable(false);
labelB_lab(fm, "Matrix |B|:");
textboxC_box{ fm, C_str };
C_box.multi_lines(true).editable(false);
labelC_lab(fm, "Matrix |C|:");
buttonbtn{ fm, "Process" };
btn.tooltip("Sum");
group act { fm, "Actions" };
act.add_option("Sum: |C|=|A|+|B|")
.events().click([&]() { action = SUM; btn.tooltip("Sum"); });
act.add_option("Trans: |X|=Transpose(|X|)")
.events().click([&]() { action = TRANS; btn.tooltip("Transpose"); });
act.add_option("Multiply: |C|=|A|*|B|")
.events().click([&]() { action = MULT; btn.tooltip("Multiply"); });
btn.events().click([&]() {
switch (action) {
caseSUM: c.empty(); sp_mm_add(a, b, c); break;
caseTRANS: sp_m_transpose(a); sp_m_transpose(b); sp_m_transpose(c); break;
caseMULT: c.empty(); sp_mm_multiply(a, b, c); break;
}
{ std::stringstreamss; ss<< c; C_str=ss.str(); C_box.caption(C_str); }
{ std::stringstreamss; ss<< a; A_str=ss.str(); A_box.caption(A_str); }
{ std::stringstreamss; ss<< b; B_str=ss.str(); B_box.caption(B_str); }
return;
});
act.radio_mode(true);
act.option_check(0);
fm_place.div("vertical <weight=8% labels margin=13 gap=5>|<weight=60% boxes margin=13 gap=5>|<actions margin=13>|<weight=10% button margin=15>");
fm_place["labels"]<<A_lab<<B_lab<<C_lab;
fm_place["boxes"]<<A_box<<B_box<<C_box;
fm_place["actions"]<< act;
fm_place["button"]<<btn;
fm_place.collocate();
fm.show();
exec();
#endif
return 0;
}
8. Тестирование
Тестирование выполняется в двух вариантах: ряд тестовых входных данных для трёх тестируемых матричных операций «зашит» в программу по аналогии с концепцией юнит-тестов. Решения этих задач выполняются автоматически при каждом запуске, результат выводится на консоль. Предполагается ручное сравнение выходных данных для определения корректности выполненных решений для каждого из алгоритмов.Для решения задачи в графическом интерфейсе необходимо нажимать кнопку «Process», выбрав в поле «Actons»тестируемый алгоритм.
Рисунок 4 - Автоматическое тестирование
Программа позволяет выполнить три вида операций над матрицами: сложение двух матриц(Рисунок 5), транспонирование матриц(Рисунок 6) и умножение двух матриц.
Рисунок 5 - Сложение
Рисунок 6 - Транспонирование
Рисунок 7 - Умножение
ЗАКЛЮЧЕНИЕ
В данном курсовом проекте при разработке программы были закреплены навыки объектно-ориентированного программирования на языке С++.
При разработке пользовательского интерфейса, были освоены основные объекты и их свойства. При оформлении курсового проекта изучено оформление прикладной документации согласно ГОСТу.
СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ
Основнаялитература
1 Анисимов, А.Е. Сборник заданий по основаниям программирования : учеб. пособие / А.Е. Анисимов, В.В. Пупышев .-- М. : Интернет-ун-т информ. технологий; БИНОМ. Лаборатория знаний, 2006 .-- 348с. <15>
2 Макконелл, Д. Основы современных алгоритмов Техносфера, 2006 .-- 368 с. <7>
3 Подбельский, В.В. Язык Си+ :Учеб. пособие для вузов / В.В. Подбельский .-- 5-е изд. -- М. : Финансы и статистика, 2003 .-- 560с. <13>
4 Павловская, Т.А. C/C++:Программирование на языке высокого уровня : Учебник для вузов / Т.А. Павловская .-- М. и др. : Питер, 2004 .-- 461с.<7>
5 Ганеев, Р.М. Проектирование интерфейса пользователя средствами Win32 API : учеб.пособие для вузов / Р. М. Ганеев .-- 2-е изд., испр. и доп. -- М. : Горячая линия-Телеком, 2007 .-- 358 с.<3>
6 Благодатских В.А. Стандартизация разработки программных средств : учебное пособие для вузов / В.А.Благодатских, В.А.Волнин,
7 К.Ф.Поскакалов;подред.О.С.Разумова .-- М. : Финансы и статистика, 2006 .-- 288с.
Камаев В.А. Технологии программирования : учебник для вузов / В.А.Камаев, В.В.Костерин .-- 2-е изд., перераб.и доп. -- М. : Высш.шк., 2006 .-- 454с.
5 Котляров, В.П. Основы тестирования программного обеспечения: учеб.пособие/ В.П.Котляров, Т.В.Коликова .-- М. : Интернет - Ун-т ин-форм.технологий: Бином ЛЗ, 2006 .-- 285с: учеб.пособие -- М. :
Дополнительнаялитература
1 Вирт Н. Алгоритмы + структуры данных = программы. М.; Mиp, 1985. - 281 с.
2 Шлее, М. Профессиональное программирование на С++ / М. Шлее .-- СПб. : БХВ-Петербург, 2005 .-- 544с. : ил. + 1 CD .-- (В подлиннике). <3>
3 Страуструп, Б. Язык программирования Си++ :Спец.изд. / Б.Страуструп;Пер.сангл.С.Анисимова,М.Кононова;Подред.Ф.Андреева,А.Ушаков .-- М. : Бином, 2004 .-- 1098с. <4>
4 Kernigan B.W. Практика программирования : пер.сангл. / Б.Керниган, Р.Пайк .-- [8-е изд.,испр.и доп.].-- М.;СПб.; Киев: Вильямс, 2004 .-- 287с.
5ТамреTamres L. Введение в тестирование программного обеспечения / Л.Тамре; пер.сангл.иред.В.В.Марченко .-- М.и др. : Вильямс, 2003 .-- 359с.
6Калбертсон, Culbertson R. Быстрое тестирование : пер.с англ. / Р.Калбертсон, К.Браун,Г.Кобб .-- М.и др. : Вильямс, 2002 .-- 384с
7 Винниченко, И.В. Автоматизация процессов тестирования / И.В.Винниченко .-- М. : Питер, 2005 .-- 203с.
8 Стотлемайер, Stottlemyer D. Тестирование Web-приложений: средства и методы для автоматизированного и ручного тестирования программногообеспечения Web-сайтов: пер.с англ. / Д.Стотлемайер .-- М. : КУДИЦ-ОБРАЗ, 2003 .-- 240с.
9 Липаев В.В. Методы обеспечения качества крупномасштабных про-граммных средств / В.В.Липаев;РАН.Ин-т системного программирования .-- М. : СИНТЕГ, 2003 .-- 510с.
10 Макгрегор Д. Тестирование объектно-ориентированного программного обеспечения: Практ.пособие:Пер.с англ. / Д.Макгрегор,Д.Сайкс .-- М.и др.: DiaSoft, 2002 .-- 432c.
Приложение 1
Исходный текст модуля класса матрицы coo_matrix.h
#pragma once
#include <assert.h>
#include <vector>
#include <algorithm>
#include "element.h"
structcoo_mtx {
bool sorted = true;
intnrows = 0, ncols = 0, nnz = 0;
std::vector<element_t>elems;
coo_mtx(int _nrows, int _ncols) : nrows(_nrows), ncols(_ncols) {}
void empty() {
sorted = true;
nrows = ncols = nnz = 0;
elems.resize(0);
}
void add(constelement_t& el, bool ruines_sorting = true) {
assert(element_traits::row(el) <= nrows);
assert(element_traits::col(el) <= ncols);
elems.push_back(el);
nnz++;
if (ruines_sorting)
sorted = false;
}
void check() {
assert(nnz == (int)elems.size());
if (nnz&& sorted) {
assert(element_traits::row(elems.back()) <= element_traits::row_t(nrows));
assert(element_traits::col(elems.back()) <= element_traits::col_t(ncols));
}
}
boolis_empty() {
check();
returnnnz == 0;
}
void sort(bool force = false) {
if (sorted && !force)
return;
std::sort(elems.begin(), elems.end(), [](element_t& a, element_t& b) {
return !is_further_coord(b, element_traits::row(a), element_traits::col(a));
});
sorted = true;
}
void merge(coo_mtx& a, coo_mtx& b) {
std::merge(a.elems.begin(), a.elems.end(), b.elems.begin(), b.elems.end(), std::back_inserter(elems),
[](element_t& a, element_t& b) {
return !is_further_coord(b, element_traits::row(a), element_traits::col(a));
});
sorted = true;
}
voidremove_nonexistents() {
size_tnremoved = elems.size();
elems.erase(std::remove_if(elems.begin(), elems.end(),
[](element_t& el) {
returnelement_traits::row(el) == element_traits::NONEXISTENT_ROW &&
element_traits::col(el) == element_traits::NONEXISTENT_COL; }),
elems.end());
nremoved -= elems.size();
nnz -= (int)nremoved;
}
};
Исходный текст модуля классов элемента матрицы element.h
#pragma once
#include <tuple>
typedefstd::tuple<int, int, double>element_t;
structelement_traits {
usingrow_t = std::tuple_element<0, element_t>::type;
usingcol_t = std::tuple_element<1, element_t>::type;
usingval_t = std::tuple_element<2, element_t>::type;
staticrow_t row(constelement_t& el) { return std::get<0>(el); }
staticcol_t col(constelement_t& el) { return std::get<1>(el); }
staticval_tval(constelement_t& el) { return std::get<2>(el); }
staticrow_t& row(element_t& el) { return std::get<0>(el); }
staticcol_t& col(element_t& el) { return std::get<1>(el); }