From 9384bfcfedcad96af4123b146eb135d8f813153d Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Sat, 15 Oct 2022 18:00:18 +0300 Subject: [PATCH 01/17] Basic functionality of DVector and tests --- .github/workflows/main.yml | 39 ++++++ .gitignore | 4 + CMakeLists.txt | 24 ++++ Makefile | 28 +++++ main.cpp | 18 +++ matrix_lib/CMakeLists.txt | 34 +++++ matrix_lib/include/dvector.h | 39 ++++++ matrix_lib/include/stdafx.h | 7 ++ matrix_lib/src/dvector.cpp | 207 +++++++++++++++++++++++++++++++ matrix_lib/src/stdafx.cpp | 1 + matrix_lib/tests/CMakeLists.txt | 23 ++++ matrix_lib/tests/test_vector.cpp | 145 ++++++++++++++++++++++ 12 files changed, 569 insertions(+) create mode 100644 .github/workflows/main.yml create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 Makefile create mode 100644 main.cpp create mode 100644 matrix_lib/CMakeLists.txt create mode 100644 matrix_lib/include/dvector.h create mode 100644 matrix_lib/include/stdafx.h create mode 100644 matrix_lib/src/dvector.cpp create mode 100644 matrix_lib/src/stdafx.cpp create mode 100644 matrix_lib/tests/CMakeLists.txt create mode 100644 matrix_lib/tests/test_vector.cpp diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..c202c94 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,39 @@ +on: push + +jobs: + build: + runs-on: ubuntu-latest + container: leshiy1295/gcc_linters_valgrind_cmake_gtest + # needs: [check] + steps: + - uses: actions/checkout@v2 + - run: make build + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: executable_file + path: build/fib + test: + runs-on: ubuntu-latest + container: leshiy1295/gcc_linters_valgrind_cmake_gtest + # needs: [build] + steps: + - uses: actions/checkout@v2 + - name: install lcov + run: apt-get install lcov -y + - run: make build TEST_OPT=ON + - run: make run + - run: make test + - name: Test coverage + run: | + cd build && lcov -t "tests_fib" -o coverage.info -c -d fib_lib/CMakeFiles + genhtml -o report coverage.info + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: coverage-info + path: build/report + - name: launch valgrind + run: | + cd build + valgrind --tool=memcheck --leak-check=yes ./fib \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c30609f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/build +_test.cpp +main +/.vscode \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c5a8b2d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.0.0) +project(main) + +set(CMAKE_CXX_STANDARD 17) + +option(TEST_OPT "build test version" OFF) +option(DEBUG_OPT "build debug version" OFF) + +add_subdirectory(matrix_lib) + +add_executable(${PROJECT_NAME} main.cpp) + +if(TEST_OPT) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) +endif() + +if(DEBUG_OPT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") +endif() + + +target_include_directories(${PROJECT_NAME} PUBLIC ${MATRIX_LIB_INCLUDE_DIRS}) +target_link_libraries(${PROJECT_NAME} PRIVATE ${MATRIX_LIB_LIBRARIES}) + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..508ed88 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +# чувствителен к изменению исходных файлов +# игнорирует изменения файла CMakeLists.txt (если make run) + +LIB = matrix_lib +BUILD_DIR = build +TARGET = ./${BUILD_DIR}/main +TEST_OPT = OFF +DEBUG_OPT = OFF + +.PHONY: build rebuild test run + +build: clean + mkdir ${BUILD_DIR} + cd ${BUILD_DIR} && cmake .. -DTEST_OPT=${TEST_OPT} -DDEBUG_OPT=${DEBUG_OPT} && $(MAKE) --no-print-directory + +clean: + (rm -r ${BUILD_DIR} 2>/dev/null) || exit 0 + +# выполняется, если проект собран +run: + cd ${BUILD_DIR} && $(MAKE) --no-print-directory + ${TARGET} + +# выполняется, если проект собран +test: ${TARGET} + ./${BUILD_DIR}/${LIB}/tests/tests +# cd ${BUILD_DIR}/${LIB} && ctest + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..e0d6789 --- /dev/null +++ b/main.cpp @@ -0,0 +1,18 @@ +#include + +#include "dvector.h" + +int main() +{ + DVector dv1{1, 2, 3, 4}; + DVector dv2(dv1); + dv2.PushBack(23); + Print(dv1, "dv1"); + Print(dv2, "dv2"); + + DVector dv3 = std::move(dv1); + // DVector dv3 = dv1; + dv3.PopBack(); + Print(dv1, "dv1"); + Print(dv3, "dv3"); +} diff --git a/matrix_lib/CMakeLists.txt b/matrix_lib/CMakeLists.txt new file mode 100644 index 0000000..00168b3 --- /dev/null +++ b/matrix_lib/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.0.0) +project(matrix_lib) + +set(CMAKE_CXX_STANDARD 17) +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror -fPIC -O0") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -O0") + +if(TEST_OPT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) +endif() + +if(DEBUG_OPT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") +endif() + +file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) +file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h) +file(GLOB INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_library(${PROJECT_NAME} ${SOURCES} ${HEADERS}) +target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIRS}) + +# без PARENT_SCOPE для тестов +# с PARENT_SCOPE для главного CMakeLists.txt +set(MATRIX_LIB_LIBRARIES ${PROJECT_NAME} ) +set(MATRIX_LIB_LIBRARIES ${PROJECT_NAME} PARENT_SCOPE) +set(MATRIX_LIB_INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE) +set(MATRIX_LIB_INCLUDE_DIRS ${INCLUDE_DIRS} ) + +if (TEST_OPT) + enable_testing() + add_subdirectory(tests) +endif() diff --git a/matrix_lib/include/dvector.h b/matrix_lib/include/dvector.h new file mode 100644 index 0000000..5e4febe --- /dev/null +++ b/matrix_lib/include/dvector.h @@ -0,0 +1,39 @@ +#pragma once + +#include "stdafx.h" + +// Vector of doubles number +class DVector +{ +private: + double *m_array = nullptr; + size_t m_capacity = 0; + size_t m_size = 0; + void grow(); +public: + DVector() = default; + explicit DVector(size_t size, double fill_value = 0); + DVector(const double *begin, const double *end); + DVector(std::initializer_list const &init_list); + DVector(DVector const &other); + DVector(DVector &&other); + void Swap(DVector &other); + DVector &operator=(DVector other); + const double *CBegin(); + const double *CEnd(); + bool Empty() const; + size_t Size() const; + void Clear(); + size_t Capacity() const; + void PushBack(double value); + double *Find(double value) const; + double *Erase(double *ptr_value); + void PopBack(); + double Front() const; + double Back() const; + double const &operator[](size_t index) const; + double &operator[](size_t index); + ~DVector(); +}; + +void Print(DVector const &dvector, std::string const &message = std::string{}); \ No newline at end of file diff --git a/matrix_lib/include/stdafx.h b/matrix_lib/include/stdafx.h new file mode 100644 index 0000000..2c79aa8 --- /dev/null +++ b/matrix_lib/include/stdafx.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include +#include +#include +#include diff --git a/matrix_lib/src/dvector.cpp b/matrix_lib/src/dvector.cpp new file mode 100644 index 0000000..d4bd57a --- /dev/null +++ b/matrix_lib/src/dvector.cpp @@ -0,0 +1,207 @@ +#include + +#include "stdafx.h" +#include "dvector.h" + +DVector::DVector(size_t size, double fill_value) : m_size(size), m_capacity(size) +{ + m_array = new double[m_capacity](); + if (fill_value) + { + std::fill_n(m_array, m_size, fill_value); + } +} + +DVector::DVector(std::initializer_list const &init_list) : m_size(init_list.size()), m_capacity(init_list.size()) +{ + m_array = new double[init_list.size()](); + std::copy(init_list.begin(), init_list.end(), m_array); +} + +DVector::DVector(DVector const &other) +{ + if (m_array) + { + delete[] m_array; + } + m_array = new double[other.m_capacity](); + m_capacity = other.m_capacity; + m_size = other.m_size; + std::copy(other.m_array, &other.m_array[other.m_size - 1] + 1, m_array); +} + +DVector::DVector(DVector &&other) : m_array(nullptr), m_capacity(0), m_size(0) +{ + Swap(other); +} + +DVector::DVector(const double *begin, const double *end) +{ + ptrdiff_t length = std::distance(begin, end); + m_array = new double[length](); + m_size = m_capacity = length; + std::copy(begin, end, m_array); +} + +DVector &DVector::operator=(DVector other) +{ + Swap(other); + return *this; +} + +const double *DVector::CBegin() +{ + return m_array; +} + +// указатель на элемент после последнего +const double *DVector::CEnd() +{ + return &m_array[m_size - 1] + 1; +} + +void DVector::Swap(DVector &other) +{ + std::swap(m_array, other.m_array); + std::swap(m_capacity, other.m_capacity); + std::swap(m_size, other.m_size); +} + +double const &DVector::operator[](size_t index) const +{ + if (index > m_size - 1) + { + throw std::runtime_error("Index out of range"); + } + return m_array[index]; +} + +double &DVector::operator[](size_t index) +{ + if (index > m_size - 1) + { + throw std::runtime_error("Index out of range"); + } + return m_array[index]; +} + +void DVector::PushBack(double value) +{ + if (m_size == m_capacity) + { + grow(); + } + m_array[m_size++] = value; +} + +bool DVector::Empty() const +{ + return m_size == 0; +} + +void DVector::PopBack() +{ + if (Empty()) + { + throw std::runtime_error("PopBack() from empty vector"); + } + --m_size; +} + +size_t DVector::Size() const +{ + return m_size; +} + +size_t DVector::Capacity() const +{ + return m_capacity; +} + +void DVector::Clear() +{ + if (m_array) + { + delete[] m_array; + } + m_array = nullptr; + m_size = 0; + m_capacity = 0; +} + +double DVector::Front() const +{ + if (Empty()) + { + throw std::runtime_error("From() from empty vector"); + } + return m_array[0]; +} + +double DVector::Back() const +{ + if (Empty()) + { + throw std::runtime_error("Back() from empty vector"); + } + return m_array[m_size - 1]; +} + +DVector::~DVector() +{ + if (m_array) + { + delete[] m_array; + } +} + +double *DVector::Find(double value) const +{ + double *it_end = &m_array[m_size - 1] + 1; + double *result = std::find(m_array, it_end, value); + if (result == it_end) + { + return nullptr; + } + return result; +} + +// возвращает элемент, следующий за удаленным либо предыдущий, если удаленный был последним +double *DVector::Erase(double *it_value) +{ + ptrdiff_t diff = reinterpret_cast(it_value) - reinterpret_cast(m_array); + if (!it_value || it_value < m_array || it_value > &m_array[m_size - 1] || diff % sizeof(double) != 0) + { + return nullptr; + } + for (double *it = it_value; it < &m_array[m_size - 1]; it++) + { + *it = *(it + 1); + } + --m_size; + return it_value == &m_array[m_size - 1] + 1 ? it_value - 1 : it_value; + +} + +void DVector::grow() +{ + size_t new_capacity = std::max(1, static_cast(m_capacity * 2)); + double *new_array = new double[new_capacity](); + std::copy(m_array, &m_array[m_size - 1] + 1, new_array); + delete[] m_array; + m_array = new_array; + m_capacity = new_capacity; +} + +void Print(DVector const &dvector, std::string const &message) +{ + if (!message.empty()) + { + std::cout << message << std::endl; + } + for (size_t i = 0; i < dvector.Size(); ++i) + { + std::cout << dvector[i] << " "; + } + std::cout << std::endl; +} diff --git a/matrix_lib/src/stdafx.cpp b/matrix_lib/src/stdafx.cpp new file mode 100644 index 0000000..1577c4e --- /dev/null +++ b/matrix_lib/src/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" \ No newline at end of file diff --git a/matrix_lib/tests/CMakeLists.txt b/matrix_lib/tests/CMakeLists.txt new file mode 100644 index 0000000..1fcdda7 --- /dev/null +++ b/matrix_lib/tests/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.0.0) +project(tests) + +set(CMAKE_CXX_STANDARD 17) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O0") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) + + +file(GLOB SOURCES *.cpp) + +find_package(GTest REQUIRED) + +add_executable(${PROJECT_NAME} ${SOURCES}) + +message("MATRIX_LIB_INCLUDE_DIRS = ${MATRIX_LIB_INCLUDE_DIRS}") +message("MATRIX_LIB_LIBRARIES = ${MATRIX_LIB_LIBRARIES}") + +target_link_libraries(${PROJECT_NAME} PRIVATE ${MATRIX_LIB_LIBRARIES} GTest::GTest gtest_main) + +target_include_directories(${PROJECT_NAME} PUBLIC ${MATRIX_LIB_INCLUDE_DIRS}) + +gtest_discover_tests(${PROJECT_NAME}) \ No newline at end of file diff --git a/matrix_lib/tests/test_vector.cpp b/matrix_lib/tests/test_vector.cpp new file mode 100644 index 0000000..7402ea9 --- /dev/null +++ b/matrix_lib/tests/test_vector.cpp @@ -0,0 +1,145 @@ +#include + +#include "dvector.h" + +TEST(TestCreateDVector, TestDefaultConstructor) +{ + DVector dvec1; + dvec1.PushBack(1); + dvec1.PushBack(2); + dvec1.PushBack(3); + dvec1.PushBack(4); + EXPECT_EQ(dvec1.Size(), 4); + EXPECT_EQ(dvec1.Capacity(), 4); + EXPECT_EQ(dvec1[0], 1); + EXPECT_EQ(dvec1[1], 2); + EXPECT_EQ(dvec1[3], 4); +} + +TEST(TestCreateDVector, TestConstructorInitializerList) +{ + DVector dvec2{5, 6, 7, 8, 9}; + EXPECT_EQ(dvec2.Size(), 5); + EXPECT_EQ(dvec2.Capacity(), 5); + EXPECT_EQ(dvec2[0], 5); + EXPECT_EQ(dvec2[1], 6); + EXPECT_EQ(dvec2[4], 9); +} + +TEST(TestCreateDVector, TestConstructorInputSizeAndFillValue) +{ + DVector dvec3(10, 99); + EXPECT_EQ(dvec3.Size(), 10); + EXPECT_EQ(dvec3.Capacity(), 10); + EXPECT_EQ(dvec3[0], 99); + EXPECT_EQ(dvec3[1], 99); + EXPECT_EQ(dvec3[9], 99); +} + +TEST(TestCreateDVector, TestCopyConstructor) +{ + DVector dvec1{5, 6, 7, 8, 9}; + DVector dvec4(dvec1); + EXPECT_NE(dvec4.CBegin(), dvec1.CBegin()); + EXPECT_EQ(dvec4.Size(), dvec1.Size()); + EXPECT_EQ(dvec4.Capacity(), dvec1.Capacity()); + EXPECT_EQ(dvec4[0], dvec1[0]); + EXPECT_EQ(dvec4[3], dvec1[3]); +} + +TEST(TestCreateDVector, TestConstructorPointersBeginEnd) +{ + const size_t size = 5; + double vec[size] = {1, 2, 3, 4, 5}; + // + 1, т.к. end - указатель на элемент после последнего + DVector dvec(vec, &vec[size - 2] + 1); + EXPECT_EQ(dvec.Size(), size - 1); + EXPECT_EQ(dvec[size - 2], vec[size - 2]); + EXPECT_THROW(dvec[size - 1], std::runtime_error); + + DVector dvec1(dvec.CBegin(), dvec.CEnd()); + EXPECT_NE(dvec1.CBegin(), dvec.CBegin()); + EXPECT_EQ(dvec1.Size(), dvec.Size()); +} + +TEST(TestCreateDVector, TestImplicitConstructor) +{ + auto func = [](DVector const &dvec) -> size_t + { return dvec.Size(); }; + + EXPECT_EQ(func({1, 2, 3}), 3); + // func(5); ERROR: no match for call +} + +TEST(TestCreateDVector, TestOperatorAssign) +{ + DVector dvec1 = {5, 6, 7, 8, 9}; + DVector dvec2({1, 2, 3}); + dvec1 = dvec2; + EXPECT_NE(dvec1.CBegin(), dvec2.CBegin()); + EXPECT_EQ(dvec1.Size(), dvec2.Size()); + EXPECT_EQ(dvec1.Capacity(), dvec2.Capacity()); + + dvec1[0] = 10; + dvec1.PushBack(30); + + dvec2 = std::move(dvec1); + EXPECT_EQ(dvec1.CBegin(), nullptr); + EXPECT_EQ(dvec1.Size(), 0); + EXPECT_EQ(dvec1.Capacity(), 0); + + EXPECT_EQ(dvec2.Size(), 4); + + dvec2 = DVector(20, 5); + EXPECT_EQ(dvec2.Size(), 20); + + dvec2.Clear(); + dvec1 = dvec2; + EXPECT_EQ(dvec1.Size(), 0); + EXPECT_EQ(dvec2.Size(), 0); +} + +TEST(TestErrorHandling, TestAccess) +{ + DVector dvec1{5, 6, 7, 8, 9}; + EXPECT_EQ(dvec1[1], 6); + dvec1[1] = 60; + EXPECT_EQ(dvec1[1], 60); + + EXPECT_THROW(dvec1[5], std::runtime_error); + EXPECT_THROW(dvec1[5] = 12, std::runtime_error); + EXPECT_THROW(dvec1[-1], std::runtime_error); + + const DVector dvec2(dvec1); + EXPECT_EQ(dvec2[1], 60); + // dvec2[1] = 600; ERROR: assignment of read-only location +} + +TEST(TestFunctionalityDVector, TestFindErase) +{ + DVector dvec{5, 6, 7, 8, 9}; + DVector dvec1(dvec); + EXPECT_EQ(dvec1.Find(6), &dvec1[1]); + EXPECT_EQ(dvec1.Find(10), nullptr); + + EXPECT_EQ(dvec1.Erase(dvec1.Find(10)), nullptr); + + EXPECT_EQ(dvec1.Erase(dvec1.Find(7)), &dvec1[2]); + EXPECT_EQ(dvec1.Size(), 4); + + dvec1 = dvec; + EXPECT_EQ(dvec1.Erase(dvec1.Find(9)), &dvec1[3]); + EXPECT_EQ(dvec1.Size(), 4); +} + +TEST(TestFunctionalityDVector, TestPushPopFrontBack) +{ + DVector dvec; + EXPECT_THROW(dvec.PopBack(), std::runtime_error); + dvec.PushBack(1); + dvec.PushBack(2); + dvec.PushBack(3); + EXPECT_EQ(dvec.Back(), 3); + EXPECT_EQ(dvec.Front(), 1); +} + From adc7072949f859ddf2a61e96b274252814aa9fe7 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Sat, 15 Oct 2022 18:01:21 +0300 Subject: [PATCH 02/17] change README --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index ac390f9..3fec761 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,25 @@ # techopark_cpp_hw Репозиторий для сдачи домашних работ по С++ в Технопарке + +#### Домашняя работа 1 + +##### Мяделец Михаил WEB-11 + +`Вариант #1` + +Необходимо разработать классы для работы с вещественными числами, векторами (строками размерности 1xN и столбцами размерности Nx1) и матрицами размерности MxN и реализовать операции над ними: +1) обращение по индексам к элементам, извлечение диагонали, строки или столбца - 1б (после модификации исходной матрицы извлечённые элементы меняться не должны); +2) возможность создания матрицы из векторов или чисел, вектора из чисел - 1б; +3) поэлементное сложение/вычитание/умножение объектов одинаковой размерности - 1б; +4) умножение числа на матрицу, вектора на матрицу, матрицы на вектор и матрицы на матрицу - 1б; +5) суммирование/вычитание числа и вектора/матрицы, матрицы и вектора (с возможностью выбора - по строкам/по столбцам) - 1б; +6) получение транспонированной и обратной матриц - 1б; +7) подсчёт определителя матрицы - 1б. + +Все основные операции должны быть реализованы через перегрузку операторов (операторы могут быть модифицирующие (+= и др.) и немодифицирующие (+ и др.)). + +Доп. баллы: +- поддержка "слайсов, как в питоне" (на уровне методов, т.к. операторы такой синтаксис не поддерживают). В качестве примерного интерфейса можно опираться на то, как это сделано в " аналоге numpy на C++" https://github.com/dpilger26/NumCpp -1б; +- размерность матриц может задаваться с помощью шаблонных параметров -2б; + +Для сдачи необходимо развернуть базовый CI, в котором будут осуществляться автоматическая сборка и тестирование проекта (хотя бы один интеграционный тест, показывающий работоспособность всех реализованных пунктов). Без покрытия тестами каждый пункт оценивается в 50% стоимости. From d2f9e437144f50ac4645a385a959cbeba66e2ce9 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Sun, 16 Oct 2022 02:20:06 +0300 Subject: [PATCH 03/17] Basic functionality of DMatrix and tests --- main.cpp | 18 +-- matrix_lib/include/dmatrix.h | 42 +++++ matrix_lib/include/dvector.h | 55 +++++-- matrix_lib/src/dmatrix.cpp | 262 +++++++++++++++++++++++++++++++ matrix_lib/src/dvector.cpp | 168 +++++++++++++++++--- matrix_lib/tests/test_matrix.cpp | 186 ++++++++++++++++++++++ matrix_lib/tests/test_vector.cpp | 34 ++++ 7 files changed, 720 insertions(+), 45 deletions(-) create mode 100644 matrix_lib/include/dmatrix.h create mode 100644 matrix_lib/src/dmatrix.cpp create mode 100644 matrix_lib/tests/test_matrix.cpp diff --git a/main.cpp b/main.cpp index e0d6789..0e20fa8 100644 --- a/main.cpp +++ b/main.cpp @@ -1,18 +1,16 @@ #include #include "dvector.h" +#include "dmatrix.h" int main() { - DVector dv1{1, 2, 3, 4}; - DVector dv2(dv1); - dv2.PushBack(23); - Print(dv1, "dv1"); - Print(dv2, "dv2"); + DMatrix dmat1(3, 10, 4); + DMatrix dmat2{ + {1, 2, 3}, + {4, 5, 6} + }; - DVector dv3 = std::move(dv1); - // DVector dv3 = dv1; - dv3.PopBack(); - Print(dv1, "dv1"); - Print(dv3, "dv3"); + Print(dmat1); + Print(dmat2); } diff --git a/matrix_lib/include/dmatrix.h b/matrix_lib/include/dmatrix.h new file mode 100644 index 0000000..b1315e9 --- /dev/null +++ b/matrix_lib/include/dmatrix.h @@ -0,0 +1,42 @@ +#pragma once + +#include "dvector.h" + +class DMatrix +{ +private: + DVector *m_matrix = nullptr; + size_t m_nRows = 0; + size_t m_nCols = 0; + size_t m_capacity = 0; + void grow(); +public: + DMatrix() = default; + DMatrix(DVector *matrix, size_t nRows); + DMatrix(DVector const &dvec); + DMatrix(size_t rows, size_t cols, double fill_value = 0); + DMatrix(std::initializer_list> const &matrix); + DMatrix(DMatrix const &other); + void Clear(); + bool Empty(); + DMatrix(DMatrix &&other); + + void PushRowBack(DVector const &dvec); + void PushRowBack(std::initializer_list const &init_list); + void PopRowBack(); + + void PushColBack(DVector const &dvec); + void PushColBack(std::initializer_list const &init_list); + void PopColBack(); + + void Swap(DMatrix &other); + DMatrix &operator=(DMatrix other); + size_t nRows() const; + size_t nCols() const; + size_t Capacity() const; + ~DMatrix(); + DVector const &operator[](size_t index) const; + DVector &operator[](size_t index); +}; + +void Print(DMatrix const &matrix, std::string const &msg = std::string{}); \ No newline at end of file diff --git a/matrix_lib/include/dvector.h b/matrix_lib/include/dvector.h index 5e4febe..cad53e4 100644 --- a/matrix_lib/include/dvector.h +++ b/matrix_lib/include/dvector.h @@ -17,23 +17,50 @@ class DVector DVector(std::initializer_list const &init_list); DVector(DVector const &other); DVector(DVector &&other); - void Swap(DVector &other); DVector &operator=(DVector other); - const double *CBegin(); - const double *CEnd(); - bool Empty() const; - size_t Size() const; - void Clear(); - size_t Capacity() const; - void PushBack(double value); + ~DVector(); + +public: + const double *CBegin() const; + const double *CEnd() const; + + void Swap(DVector &other); + void Fill(double fill_value); + + bool Empty() const; + size_t Size() const; + size_t Capacity() const; + void Clear(); + double *Find(double value) const; double *Erase(double *ptr_value); - void PopBack(); - double Front() const; - double Back() const; - double const &operator[](size_t index) const; - double &operator[](size_t index); - ~DVector(); + + void PushBack(double value); + void PopBack(); + + double Front() const; + double Back() const; + + double const &operator[](size_t index) const; + double &operator[](size_t index); + + double Dot(DVector const &other) const; }; +DVector &operator/=(DVector &left, double value); +DVector &operator*=(DVector &left, double value); + +DVector operator/(DVector left, double value); +DVector operator*(DVector left, double value); + +DVector &operator+=(DVector &left, DVector const &right); +DVector &operator-=(DVector &left, DVector const &right); +DVector &operator/=(DVector &left, DVector const &right); +DVector &operator*=(DVector &left, DVector const &right); + +DVector operator+(DVector left, DVector const &right); +DVector operator-(DVector left, DVector const &right); +DVector operator/(DVector left, DVector const &right); +DVector operator*(DVector left, DVector const &right); + void Print(DVector const &dvector, std::string const &message = std::string{}); \ No newline at end of file diff --git a/matrix_lib/src/dmatrix.cpp b/matrix_lib/src/dmatrix.cpp new file mode 100644 index 0000000..f1a8c86 --- /dev/null +++ b/matrix_lib/src/dmatrix.cpp @@ -0,0 +1,262 @@ +#include + +#include "stdafx.h" +#include "dmatrix.h" + +const std::string ERROR_EMPTY = "DMatrix is empty"; + +DMatrix::DMatrix(size_t nRows, size_t nCols, double fill_value) : m_nRows(nRows), m_nCols(nCols), m_capacity(nRows) +{ + // можно ли указать конкретный конструктор для каждого элемента дин. массива? + m_matrix = new DVector[m_nRows](); + for (size_t i = 0; i < m_nRows; ++i) + { + m_matrix[i] = DVector(m_nCols, fill_value); + } +} + +DMatrix::DMatrix(std::initializer_list> const &init_list) : m_nRows(init_list.size()), m_nCols(init_list.begin()->size()), m_capacity(init_list.size()) +{ + if (std::any_of(init_list.begin() + 1, init_list.end(), [n = m_nCols](std::initializer_list const &list) + { + return list.size() != n; + })) + { + throw std::runtime_error("The matrix has rows of different lengths"); + } + m_matrix = new DVector[m_nRows](); + int i = 0; + for (auto row = init_list.begin(); row < init_list.end(); ++row) + { + m_matrix[i] = DVector(row->begin(), row->end()); + ++i; + } +} + +DMatrix::DMatrix(DMatrix const &other) : m_nRows(other.nRows()), m_nCols(other.nCols()), m_capacity(other.nRows()) +{ + m_matrix = new DVector[other.nRows()](); + for (size_t i = 0; i < other.m_nRows; ++i) + { + m_matrix[i] = DVector(other[i].CBegin(), other[i].CEnd()); + } +} + +DMatrix::DMatrix(DMatrix &&other) : m_matrix(other.m_matrix), m_nRows(other.m_nRows), m_nCols(m_nCols), m_capacity(other.m_nRows) +{ + other.Clear(); +} + +DMatrix::DMatrix(DVector *matrix, size_t nRows) : m_matrix(matrix), m_nRows(nRows), m_nCols(matrix[0].Size()), m_capacity(nRows) +{ + // намного читабильнее, чем std::any_of.... + for (size_t i = 1; i < m_nCols; ++i) + { + if (matrix[i].Size() != m_nCols) + { + throw std::runtime_error("The matrix has rows of different lengths"); + } + } +} + +DMatrix::~DMatrix() +{ + if (m_matrix) + { + delete[] m_matrix; + } + m_matrix = nullptr; +} + +void DMatrix::Swap(DMatrix &other) +{ + std::swap(m_matrix, other.m_matrix); + std::swap(m_nRows, other.m_nRows); + std::swap(m_nCols, other.m_nCols); +} + +DMatrix &DMatrix::operator=(DMatrix other) +{ + Swap(other); + return *this; +} + +DMatrix::DMatrix(DVector const &dvec) : m_nRows(1), m_nCols(dvec.Size()) +{ + m_matrix = new DVector[1]{ DVector(dvec) }; +} + +void DMatrix::Clear() +{ + m_matrix = nullptr; + m_nRows = 0; + m_nCols = 0; + m_capacity = 0; +} + +size_t DMatrix::nRows() const +{ + return m_nRows; +} + +size_t DMatrix::nCols() const +{ + return m_nCols; +} + + +DVector const &DMatrix::operator[](size_t index) const +{ + if (index > m_nRows - 1) + { + throw std::runtime_error("Index out of range"); + } + return m_matrix[index]; +} + +DVector &DMatrix::operator[](size_t index) +{ + if (index > m_nRows - 1) + { + throw std::runtime_error("Index out of range"); + } + return m_matrix[index]; +} + +bool DMatrix::Empty() +{ + return m_nRows == 0; +} + +size_t DMatrix::Capacity() const +{ + return m_capacity; +} + +void DMatrix::PushRowBack(DVector const &dvec) +{ + if (m_nRows > 0 && dvec.Size() != m_nCols) + { + throw std::runtime_error("The matrix has rows of different lengths"); + } + m_nCols = dvec.Size(); + if (m_nRows == m_capacity) + { + grow(); + } + m_matrix[m_nRows++] = dvec; +} + +void DMatrix::PushRowBack(std::initializer_list const &init_list) +{ + if (m_nRows > 0 && init_list.size() != m_nCols) + { + throw std::runtime_error("The matrix has rows of different lengths"); + } + m_nCols = init_list.size(); + if (m_nRows == m_capacity) + { + grow(); + } + m_matrix[m_nRows++] = DVector(init_list.begin(), init_list.end()); +} + +void DMatrix::PopRowBack() +{ + if (Empty()) + { + throw std::runtime_error("PopBack(): " + ERROR_EMPTY); + } + m_matrix[--m_nRows].~DVector(); + if (m_nRows == 0) + { + if (m_matrix) + { + delete[] m_matrix; + } + Clear(); + } +} + +void DMatrix::PushColBack(DVector const &dvec) +{ + if (m_nRows > 0 && dvec.Size() != m_nRows) + { + throw std::runtime_error("The matrix has rows of different lengths"); + } + if (m_nRows == 0) + { + m_matrix = new DVector[dvec.Size()](); + m_capacity = dvec.Size(); + } + m_nRows = dvec.Size(); + ++m_nCols; + for (size_t i = 0; i < m_nRows; ++i) + { + m_matrix[i].PushBack(dvec[i]); + } +} + +void DMatrix::PushColBack(std::initializer_list const &init_list) +{ + if (m_nRows > 0 && init_list.size() != m_nRows) + { + throw std::runtime_error("The matrix has rows of different lengths"); + } + if (m_nRows == 0) + { + m_matrix = new DVector[init_list.size()](); + m_capacity = init_list.size(); + } + m_nRows = init_list.size(); + ++m_nCols; + for (size_t i = 0; i < m_nRows; ++i) + { + m_matrix[i].PushBack(*(init_list.begin() + i)); + } +} + +void DMatrix::PopColBack() +{ + if (Empty()) + { + throw std::runtime_error("PopBack(): " + ERROR_EMPTY); + } + --m_nCols; + for (size_t i = 0; i < m_nRows; ++i) + { + m_matrix[i].PopBack(); + } + if (m_nCols == 0) + { + if (m_matrix) + { + delete[] m_matrix; + } + Clear(); + } +} + + +void DMatrix::grow() +{ + size_t new_capacity = std::max(1, static_cast(m_capacity * 2)); + DVector *new_matrix = new DVector[new_capacity](); + std::copy(m_matrix, &m_matrix[m_nRows - 1] + 1, new_matrix); + delete[] m_matrix; + m_matrix = new_matrix; + m_capacity = new_capacity; +} + + +void Print(DMatrix const &matrix, std::string const &msg) +{ + if (!msg.empty()) + { + std::cout << msg << std::endl; + } + for (size_t i = 0; i < matrix.nRows(); ++i) + { + Print(matrix[i]); + } +} \ No newline at end of file diff --git a/matrix_lib/src/dvector.cpp b/matrix_lib/src/dvector.cpp index d4bd57a..1f67110 100644 --- a/matrix_lib/src/dvector.cpp +++ b/matrix_lib/src/dvector.cpp @@ -3,12 +3,38 @@ #include "stdafx.h" #include "dvector.h" +// static + const = const +const std::string ERROR_ARITHMETIC = "Arithmetic operations on vectors of different size"; +const std::string ERROR_RANGE = "Index out of range"; +const std::string ERROR_EMPTY = "DVector is empty"; + +void IsEqualSize(size_t size1, size_t size2, std::string const &msgError = "Exception") +{ + if (size1 != size2) + { + throw std::runtime_error(msgError); + } +} + +void Print(DVector const &dvector, std::string const &message) +{ + if (!message.empty()) + { + std::cout << message << std::endl; + } + for (size_t i = 0; i < dvector.Size(); ++i) + { + std::cout << dvector[i] << " "; + } + std::cout << std::endl; +} + DVector::DVector(size_t size, double fill_value) : m_size(size), m_capacity(size) { m_array = new double[m_capacity](); if (fill_value) { - std::fill_n(m_array, m_size, fill_value); + Fill(fill_value); } } @@ -49,17 +75,22 @@ DVector &DVector::operator=(DVector other) return *this; } -const double *DVector::CBegin() +const double *DVector::CBegin() const { return m_array; } // указатель на элемент после последнего -const double *DVector::CEnd() +const double *DVector::CEnd() const { return &m_array[m_size - 1] + 1; } +void DVector::Fill(double fill_value) +{ + std::fill_n(m_array, m_size, fill_value); +} + void DVector::Swap(DVector &other) { std::swap(m_array, other.m_array); @@ -71,7 +102,7 @@ double const &DVector::operator[](size_t index) const { if (index > m_size - 1) { - throw std::runtime_error("Index out of range"); + throw std::runtime_error(ERROR_RANGE); } return m_array[index]; } @@ -80,7 +111,7 @@ double &DVector::operator[](size_t index) { if (index > m_size - 1) { - throw std::runtime_error("Index out of range"); + throw std::runtime_error(ERROR_RANGE); } return m_array[index]; } @@ -103,7 +134,7 @@ void DVector::PopBack() { if (Empty()) { - throw std::runtime_error("PopBack() from empty vector"); + throw std::runtime_error("PopBack(): " + ERROR_EMPTY); } --m_size; } @@ -133,7 +164,7 @@ double DVector::Front() const { if (Empty()) { - throw std::runtime_error("From() from empty vector"); + throw std::runtime_error("From(): " + ERROR_EMPTY); } return m_array[0]; } @@ -142,7 +173,7 @@ double DVector::Back() const { if (Empty()) { - throw std::runtime_error("Back() from empty vector"); + throw std::runtime_error("Back(): " + ERROR_EMPTY); } return m_array[m_size - 1]; } @@ -153,6 +184,7 @@ DVector::~DVector() { delete[] m_array; } + m_array = nullptr; } double *DVector::Find(double value) const @@ -183,25 +215,119 @@ double *DVector::Erase(double *it_value) } -void DVector::grow() +DVector &operator+=(DVector &left, DVector const &right) { - size_t new_capacity = std::max(1, static_cast(m_capacity * 2)); - double *new_array = new double[new_capacity](); - std::copy(m_array, &m_array[m_size - 1] + 1, new_array); - delete[] m_array; - m_array = new_array; - m_capacity = new_capacity; + IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); + for (size_t i = 0; i < left.Size(); ++i) + { + left[i] += right[i]; + } + return left; } -void Print(DVector const &dvector, std::string const &message) +DVector &operator-=(DVector &left, DVector const &right) { - if (!message.empty()) + IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); + for (size_t i = 0; i < left.Size(); ++i) { - std::cout << message << std::endl; + left[i] -= right[i]; } - for (size_t i = 0; i < dvector.Size(); ++i) + return left; +} + +DVector &operator*=(DVector &left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); + for (size_t i = 0; i < left.Size(); ++i) { - std::cout << dvector[i] << " "; + left[i] *= right[i]; } - std::cout << std::endl; + return left; } + +DVector &operator/=(DVector &left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); + for (size_t i = 0; i < left.Size(); ++i) + { + left[i] /= right[i]; + } + return left; +} + +// ------------------------------------------------------------------------- + +DVector &operator*=(DVector &left, double value) +{ + for (size_t i = 0; i < left.Size(); ++i) + { + left[i] *= value; + } + return left; +} + +DVector &operator/=(DVector &left, double value) +{ + for (size_t i = 0; i < left.Size(); ++i) + { + left[i] /= value; + } + return left; +} + +DVector operator*(DVector left, double value) +{ + return left *= value; +} + +DVector operator/(DVector left, double value) +{ + return left /= value; +} + +// ------------------------------------------------------------------------- + +DVector operator+(DVector left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); + return left += right; +} + +DVector operator-(DVector left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); + return left -= right; +} + +DVector operator*(DVector left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); + return left *= right; +} + +DVector operator/(DVector left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); + return left /= right; +} + +double DVector::Dot(DVector const &other) const +{ + IsEqualSize(m_size, other.Size(), ERROR_ARITHMETIC); + double dotProduct = 0; + for (size_t i = 0; i < m_size; ++i) + { + dotProduct += m_array[i] * other[i]; + } + return dotProduct; +} + +void DVector::grow() +{ + size_t new_capacity = std::max(1, static_cast(m_capacity * 2)); + double *new_array = new double[new_capacity](); + std::copy(m_array, &m_array[m_size - 1] + 1, new_array); + delete[] m_array; + m_array = new_array; + m_capacity = new_capacity; +} \ No newline at end of file diff --git a/matrix_lib/tests/test_matrix.cpp b/matrix_lib/tests/test_matrix.cpp new file mode 100644 index 0000000..09fc259 --- /dev/null +++ b/matrix_lib/tests/test_matrix.cpp @@ -0,0 +1,186 @@ +#include + +#include "dmatrix.h" + +TEST(TestCreateDMatrix, TestConstructorsSpecifySizeAndInitList) +{ + DMatrix dmat1(3, 10, 4); + DMatrix dmat2{ + {1, 2, 3}, + {4, 5, 6} + }; + EXPECT_EQ(dmat1.nCols(), 10); + EXPECT_EQ(dmat1.nRows(), 3); + EXPECT_EQ(dmat1[0][0], 4); + EXPECT_EQ(dmat1[2][9], 4); + + EXPECT_EQ(dmat2.nCols(), 3); + EXPECT_EQ(dmat2.nRows(), 2); + EXPECT_EQ(dmat2[0][0], 1); + EXPECT_EQ(dmat2[0][1], 2); + EXPECT_EQ(dmat2[1][2], 6); +} + +TEST(TestCreateDMatrix, TestConstructorsDVectorsAndCopy) +{ + const size_t ndvecs = 2; + DVector *dvecs = new DVector[ndvecs]{ DVector(2, 7), DVector{3, 8} }; + + DMatrix dmat1(dvecs, ndvecs); + DMatrix dmat2(dmat1); + + EXPECT_NE(dmat1[0].CBegin(), dmat2[0].CBegin()); + EXPECT_EQ(dmat1[1][0], dmat2[1][0]); + + EXPECT_EQ(dmat1[1][0], 3); + EXPECT_EQ(dmat1[0][1], 7); + + DMatrix dmat3(DVector{2, 4, 6, 8}); + EXPECT_EQ(dmat3.nRows(), 1); + EXPECT_EQ(dmat3.nCols(), 4); + EXPECT_EQ(dmat3[0][2], 6); +} + +TEST(TestCreateDMatrix, TestOperatorAssign) +{ + DMatrix dmat1{ + {1, 2, 3}, + {4, 5, 6}, + }; + + DMatrix dmat2 = dmat1; + EXPECT_NE(dmat1[0].CBegin(), dmat2[0].CBegin()); + EXPECT_EQ(dmat1.nRows(), dmat2.nRows()); + EXPECT_EQ(dmat1.nCols(), dmat2.nCols()); + + EXPECT_EQ(dmat1[1][0], dmat2[1][0]); + EXPECT_EQ(dmat1[1][0], 4); +} + +TEST(TestErrorHandling, TestAccessAndCreateNotRectangleMatrix) +{ + EXPECT_THROW( DMatrix dmat({ {1, 2}, {4, 5, 6} }), std::runtime_error); + EXPECT_THROW( DMatrix dmat({ {1}, {} }), std::runtime_error); + + DVector *dvecs = new DVector[2]{ DVector{1, 2}, DVector{3, 4, 5} }; + EXPECT_THROW(DMatrix dmat(dvecs, 2), std::runtime_error); + + DMatrix dmat{ {1, 2, 3}, {4, 5, 6} }; + + EXPECT_THROW(dmat[2][1], std::runtime_error); + EXPECT_THROW(dmat[0][5], std::runtime_error); +} + +TEST(TestErrorHandling, TestPushPopRow) +{ + DMatrix dmat; + EXPECT_THROW(dmat.PopRowBack(), std::runtime_error); + dmat.PushRowBack({1, 2, 3}); + + DVector dvec{4, 5, 6}; + dmat.PushRowBack(dvec); + + EXPECT_THROW(dmat.PushRowBack({20, 20}), std::runtime_error); + DVector dvec2{4, 4, 4, 4}; + EXPECT_THROW(dmat.PushRowBack(dvec2), std::runtime_error); + + + EXPECT_EQ(dmat[0][1], 2); + EXPECT_EQ(dmat[1][2], 6); + EXPECT_EQ(dmat.nCols(), 3); + EXPECT_EQ(dmat.nRows(), 2); + + dmat.PushRowBack({0, 0, 7}); + dmat.PushRowBack({0, 0, 7}); + dmat.PushRowBack({0, 0, 7}); + + + dmat.PopRowBack(); + dmat.PopRowBack(); + EXPECT_EQ(dmat.nRows(), 3); + + EXPECT_EQ(dmat.Capacity(), 8); +} + +// размер матрицы зависит от ее содержимого +// без содержимого матрица не имеет размера и может в будущем принимать любые формы +TEST(TestErrorHandling, TestPushPopRow_WithChangeDimensity) +{ + DMatrix dmat; + dmat.PushRowBack({0, 0, 7}); + dmat.PushRowBack({0, 0, 7}); + dmat.PushRowBack({0, 0, 7}); + EXPECT_EQ(dmat.nCols(), 3); + EXPECT_EQ(dmat.nRows(), 3); + EXPECT_EQ(dmat.Capacity(), 4); + + dmat.PopRowBack(); + dmat.PopRowBack(); + dmat.PopRowBack(); + EXPECT_THROW(dmat.PopRowBack(), std::runtime_error); + + dmat.PushRowBack({1}); + + EXPECT_EQ(dmat.nCols(), 1); + EXPECT_EQ(dmat.nRows(), 1); + EXPECT_EQ(dmat.Capacity(), 1); +} + +TEST(TestErrorHandling, TestPushPopCol) +{ + DMatrix dmat; + dmat.PushColBack({1, 2, 3}); + EXPECT_EQ(dmat.nCols(), 1); + EXPECT_EQ(dmat.nRows(), 3); + + EXPECT_THROW(dmat.PushColBack({1, 1}), std::runtime_error); + + DVector dvec{4, 5, 6}; + dmat.PushColBack(dvec); + + EXPECT_EQ(dmat.nCols(), 2); + EXPECT_EQ(dmat.nRows(), 3); + + dmat.PopColBack(); + dmat.PopColBack(); + EXPECT_THROW(dmat.PopColBack(), std::runtime_error); + + dmat.PushColBack({1, 2}); + dmat.PushColBack({3, 4}); + + EXPECT_EQ(dmat.nCols(), 2); + EXPECT_EQ(dmat.nRows(), 2); +} + +TEST(TestErrorHandling, TestPushPopMix) +{ + DMatrix dmat{ + {1, 2, 3}, + {4, 5, 6}, + }; + dmat.PushColBack({7, 7}); + dmat.PushRowBack({8, 8, 8, 100}); + + EXPECT_EQ(dmat[2][3], 100); + + EXPECT_EQ(dmat.nCols(), 4); + EXPECT_EQ(dmat.nRows(), 3); + + dmat.PopColBack(); + dmat.PopRowBack(); + dmat.PopRowBack(); + + EXPECT_EQ(dmat.nCols(), 3); + EXPECT_EQ(dmat.nRows(), 1); + + dmat.PopRowBack(); + EXPECT_THROW(dmat.PopRowBack(), std::runtime_error); + + EXPECT_EQ(dmat.nCols(), 0); + EXPECT_EQ(dmat.nRows(), 0); + + dmat = {{1, 2, 3, 4, 5, 6, 7}}; + dmat.PushColBack({8}); + EXPECT_EQ(dmat[0][0], 1); + EXPECT_EQ(dmat[0][7], 8); +} \ No newline at end of file diff --git a/matrix_lib/tests/test_vector.cpp b/matrix_lib/tests/test_vector.cpp index 7402ea9..8c46b91 100644 --- a/matrix_lib/tests/test_vector.cpp +++ b/matrix_lib/tests/test_vector.cpp @@ -143,3 +143,37 @@ TEST(TestFunctionalityDVector, TestPushPopFrontBack) EXPECT_EQ(dvec.Front(), 1); } +TEST(TestFunctionalityDVector, TestArithmeticOperators) +{ + DVector dvec1{1, 2, 3}; + DVector dvec2{5, 6, 7}; + (dvec1 *= dvec2) += dvec1; + EXPECT_EQ(dvec1[0], 10); + EXPECT_EQ(dvec1[1], 24); + EXPECT_EQ(dvec1[2], 42); + + DVector dvec3{2, 4, 8}; + DVector dvec4{4, 5, 6}; + + DVector dvec5 = (dvec3 * 2 * dvec4) + dvec3 / 2; + + /* + { 4 * 4; 8 * 5; 16 * 6 } + + + { 1; 2; 4 } + = + { 17; 42; 100 } + */ + + dvec5 *= 2; + + EXPECT_EQ(dvec5[0], 17 * 2); + EXPECT_EQ(dvec5[1], 42 * 2); + EXPECT_EQ(dvec5[2], 100 * 2); + + DVector dvec6{3, 4}; + DVector dvec7{10, 2}; + double resDot = dvec6.Dot(dvec7); + EXPECT_EQ(resDot, 38); +} + From 6f434b371efc833b833e21cc0e1e303df6c0ada2 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Sun, 16 Oct 2022 09:35:05 +0300 Subject: [PATCH 04/17] fix test coverage in ci --- .github/workflows/main.yml | 5 ++++- matrix_lib/include/dmatrix.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c202c94..dd7d9c1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,8 @@ on: push +env: + LIB_NAME: matrix_lib + jobs: build: runs-on: ubuntu-latest @@ -26,7 +29,7 @@ jobs: - run: make test - name: Test coverage run: | - cd build && lcov -t "tests_fib" -o coverage.info -c -d fib_lib/CMakeFiles + cd build && lcov -t "tests_matrix" -o coverage.info -c -d env.LIB_NAME/CMakeFiles genhtml -o report coverage.info - name: Upload artifacts uses: actions/upload-artifact@v2 diff --git a/matrix_lib/include/dmatrix.h b/matrix_lib/include/dmatrix.h index b1315e9..464df34 100644 --- a/matrix_lib/include/dmatrix.h +++ b/matrix_lib/include/dmatrix.h @@ -29,6 +29,8 @@ class DMatrix void PushColBack(std::initializer_list const &init_list); void PopColBack(); + // void Erase(Dvector *dvec); + void Swap(DMatrix &other); DMatrix &operator=(DMatrix other); size_t nRows() const; From 4c184d2c90c71ba2b8c944769e251d25247050e6 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Sun, 16 Oct 2022 09:37:15 +0300 Subject: [PATCH 05/17] fix test coverage in ci 2 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dd7d9c1..5f973d1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,7 +29,7 @@ jobs: - run: make test - name: Test coverage run: | - cd build && lcov -t "tests_matrix" -o coverage.info -c -d env.LIB_NAME/CMakeFiles + cd build && lcov -t "tests_matrix" -o coverage.info -c -d ${LIB_NAME}/CMakeFiles genhtml -o report coverage.info - name: Upload artifacts uses: actions/upload-artifact@v2 From 9360115d949c7b92b31adfd8027520566e510ea1 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Sun, 16 Oct 2022 09:39:25 +0300 Subject: [PATCH 06/17] fix test coverage in ci 3 --- .github/workflows/main.yml | 3 ++- matrix_lib/include/dmatrix.h | 2 ++ matrix_lib/src/dmatrix.cpp | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5f973d1..8e68fa8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,6 +2,7 @@ on: push env: LIB_NAME: matrix_lib + EXE_FILE: main jobs: build: @@ -39,4 +40,4 @@ jobs: - name: launch valgrind run: | cd build - valgrind --tool=memcheck --leak-check=yes ./fib \ No newline at end of file + valgrind --tool=memcheck --leak-check=yes ./${EXE_FILE} \ No newline at end of file diff --git a/matrix_lib/include/dmatrix.h b/matrix_lib/include/dmatrix.h index 464df34..879290e 100644 --- a/matrix_lib/include/dmatrix.h +++ b/matrix_lib/include/dmatrix.h @@ -31,6 +31,8 @@ class DMatrix // void Erase(Dvector *dvec); + DVector GetDiag() const; + void Swap(DMatrix &other); DMatrix &operator=(DMatrix other); size_t nRows() const; diff --git a/matrix_lib/src/dmatrix.cpp b/matrix_lib/src/dmatrix.cpp index f1a8c86..414a91c 100644 --- a/matrix_lib/src/dmatrix.cpp +++ b/matrix_lib/src/dmatrix.cpp @@ -237,6 +237,11 @@ void DMatrix::PopColBack() } } +DVector DMatrix::GetDiag() const +{ + +} + void DMatrix::grow() { From 466b687d9cefb0ce738ef26df7c79f90856bbe59 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Sun, 16 Oct 2022 09:42:18 +0300 Subject: [PATCH 07/17] fix test coverage in ci 4 --- .github/workflows/main.yml | 2 +- matrix_lib/src/dmatrix.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8e68fa8..ad5762f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: executable_file - path: build/fib + path: build/${EXE_FILE} test: runs-on: ubuntu-latest container: leshiy1295/gcc_linters_valgrind_cmake_gtest diff --git a/matrix_lib/src/dmatrix.cpp b/matrix_lib/src/dmatrix.cpp index 414a91c..4b8bffa 100644 --- a/matrix_lib/src/dmatrix.cpp +++ b/matrix_lib/src/dmatrix.cpp @@ -239,7 +239,12 @@ void DMatrix::PopColBack() DVector DMatrix::GetDiag() const { + size_t nElemsDiag = std::min(m_nRows, m_nCols); + DVector dvec(nElemsDiag); + for (size_t i = 0; i < nElemsDiag; ++i) + { + } } From e7ee27e3f6277884dadf2e125e6a27527039a9ba Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Sun, 16 Oct 2022 16:07:04 +0300 Subject: [PATCH 08/17] All tasks are ready except for slices and multidimensionality --- main.cpp | 4 + matrix_lib/include/dmatrix.h | 91 +++++-- matrix_lib/include/dvector.h | 12 +- matrix_lib/src/dmatrix.cpp | 398 ++++++++++++++++++++++++++++- matrix_lib/src/dvector.cpp | 37 ++- matrix_lib/tests/test_matrix.cpp | 412 +++++++++++++++++++++++++++++-- matrix_lib/tests/test_vector.cpp | 21 ++ 7 files changed, 933 insertions(+), 42 deletions(-) diff --git a/main.cpp b/main.cpp index 0e20fa8..54e26e1 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,10 @@ #include "dvector.h" #include "dmatrix.h" +// static IsEqualSize +// мб разделить реализацию на разные файлы +// создание матрицы из вектора с указание строки или столбца + int main() { DMatrix dmat1(3, 10, 4); diff --git a/matrix_lib/include/dmatrix.h b/matrix_lib/include/dmatrix.h index 879290e..20a3331 100644 --- a/matrix_lib/include/dmatrix.h +++ b/matrix_lib/include/dmatrix.h @@ -2,45 +2,94 @@ #include "dvector.h" +enum class ORIENT { ROW = 0, COL }; + class DMatrix { private: - DVector *m_matrix = nullptr; - size_t m_nRows = 0; - size_t m_nCols = 0; - size_t m_capacity = 0; + DVector *m_matrix = nullptr; + size_t m_nRows = 0; + size_t m_nCols = 0; + size_t m_capacity = 0; void grow(); public: DMatrix() = default; DMatrix(DVector *matrix, size_t nRows); - DMatrix(DVector const &dvec); + // Создание матрицы как вектор-строку или вектор-столбец + DMatrix(DVector const &dvec, ORIENT orientation = ORIENT::ROW); DMatrix(size_t rows, size_t cols, double fill_value = 0); DMatrix(std::initializer_list> const &matrix); DMatrix(DMatrix const &other); - void Clear(); - bool Empty(); DMatrix(DMatrix &&other); - - void PushRowBack(DVector const &dvec); - void PushRowBack(std::initializer_list const &init_list); - void PopRowBack(); + DMatrix &operator=(DMatrix other); + ~DMatrix(); +public: + void Clear(); + bool Empty(); + void Swap(DMatrix &other); + // Удаление / добавление последних строк / столбцов + void PushRowBack(DVector const &dvec); + void PushRowBack(std::initializer_list const &init_list); + void PopRowBack(); - void PushColBack(DVector const &dvec); - void PushColBack(std::initializer_list const &init_list); - void PopColBack(); + void PushColBack(DVector const &dvec); + void PushColBack(std::initializer_list const &init_list); + void PopColBack(); - // void Erase(Dvector *dvec); + void EraseByIndex(size_t index, ORIENT orientation = ORIENT::ROW); DVector GetDiag() const; + DVector GetRow(size_t index) const; + DVector GetCol(size_t index) const; - void Swap(DMatrix &other); - DMatrix &operator=(DMatrix other); - size_t nRows() const; - size_t nCols() const; - size_t Capacity() const; - ~DMatrix(); + DMatrix Dot(DMatrix const &other) const; + DVector Dot(DVector const &dvec) const; + + size_t nRows() const; + size_t nCols() const; + size_t Capacity() const; + + // модифицирующие операции + void AddNum(double value); + void SubNum(double value); + void AddVec(DVector const &dvec, ORIENT orientation = ORIENT::ROW); + void SubVec(DVector const &dvec, ORIENT orientation = ORIENT::ROW); + + DMatrix T() const; + // DMatrix GetMatrix + double Det() const; + double Minor(size_t iIndex, size_t jIndex) const; + DMatrix Adj(); + DMatrix Inv(); + DVector const &operator[](size_t index) const; DVector &operator[](size_t index); }; +DMatrix &operator/=(DMatrix &matrix, double value); +DMatrix &operator*=(DMatrix &matrix, double value); + +DMatrix operator/(DMatrix matrix, double value); +DMatrix operator*(DMatrix matrix, double value); + +// ----- + +DMatrix &operator/=(double value, DMatrix &matrix); +DMatrix &operator*=(double value, DMatrix &matrix); + +DMatrix operator/(double value, DMatrix matrix); +DMatrix operator*(double value, DMatrix matrix); + +// ----- + +DMatrix &operator+=(DMatrix &left, DMatrix const &right); +DMatrix &operator-=(DMatrix &left, DMatrix const &right); +DMatrix &operator/=(DMatrix &left, DMatrix const &right); +DMatrix &operator*=(DMatrix &left, DMatrix const &right); + +DMatrix operator+(DMatrix left, DMatrix const &right); +DMatrix operator-(DMatrix left, DMatrix const &right); +DMatrix operator/(DMatrix left, DMatrix const &right); +DMatrix operator*(DMatrix left, DMatrix const &right); + void Print(DMatrix const &matrix, std::string const &msg = std::string{}); \ No newline at end of file diff --git a/matrix_lib/include/dvector.h b/matrix_lib/include/dvector.h index cad53e4..ff0b805 100644 --- a/matrix_lib/include/dvector.h +++ b/matrix_lib/include/dvector.h @@ -2,6 +2,8 @@ #include "stdafx.h" +class DMatrix; + // Vector of doubles number class DVector { @@ -43,8 +45,14 @@ class DVector double const &operator[](size_t index) const; double &operator[](size_t index); - - double Dot(DVector const &other) const; + + // немодифицирующие операции + double Dot(DVector const &other) const; + DVector Dot(DMatrix const &matrix) const; + + // модифицирующие операции + void AddNum(double value); + void SubNum(double value); }; DVector &operator/=(DVector &left, double value); diff --git a/matrix_lib/src/dmatrix.cpp b/matrix_lib/src/dmatrix.cpp index 4b8bffa..7581d52 100644 --- a/matrix_lib/src/dmatrix.cpp +++ b/matrix_lib/src/dmatrix.cpp @@ -4,6 +4,16 @@ #include "dmatrix.h" const std::string ERROR_EMPTY = "DMatrix is empty"; +const std::string ERROR_ARITHMETIC = "Arithmetic operations on matrix of different size"; + +// проверка на равный размер, иначе исключение +static void IsEqualSize(size_t size1, size_t size2, std::string const &msgError = "Exception") +{ + if (size1 != size2) + { + throw std::runtime_error(msgError); + } +} DMatrix::DMatrix(size_t nRows, size_t nCols, double fill_value) : m_nRows(nRows), m_nCols(nCols), m_capacity(nRows) { @@ -17,6 +27,7 @@ DMatrix::DMatrix(size_t nRows, size_t nCols, double fill_value) : m_nRows(nRows) DMatrix::DMatrix(std::initializer_list> const &init_list) : m_nRows(init_list.size()), m_nCols(init_list.begin()->size()), m_capacity(init_list.size()) { + // проверка на прямоугольность init_list if (std::any_of(init_list.begin() + 1, init_list.end(), [n = m_nCols](std::initializer_list const &list) { return list.size() != n; @@ -42,13 +53,15 @@ DMatrix::DMatrix(DMatrix const &other) : m_nRows(other.nRows()), m_nCols(other.n } } -DMatrix::DMatrix(DMatrix &&other) : m_matrix(other.m_matrix), m_nRows(other.m_nRows), m_nCols(m_nCols), m_capacity(other.m_nRows) +DMatrix::DMatrix(DMatrix &&other) : m_matrix(other.m_matrix), m_nRows(other.m_nRows), m_nCols(other.nCols()), m_capacity(other.m_nRows) { - other.Clear(); + // обнуление + other.Clear(); } DMatrix::DMatrix(DVector *matrix, size_t nRows) : m_matrix(matrix), m_nRows(nRows), m_nCols(matrix[0].Size()), m_capacity(nRows) { + // проверка на прямоугольность DVector * // намного читабильнее, чем std::any_of.... for (size_t i = 1; i < m_nCols; ++i) { @@ -81,9 +94,26 @@ DMatrix &DMatrix::operator=(DMatrix other) return *this; } -DMatrix::DMatrix(DVector const &dvec) : m_nRows(1), m_nCols(dvec.Size()) +DMatrix::DMatrix(DVector const &dvec, ORIENT orientation) { - m_matrix = new DVector[1]{ DVector(dvec) }; + if (orientation == ORIENT::ROW) + { + m_matrix = new DVector[1]{ DVector(dvec) }; + m_nRows = 1; + m_nCols = dvec.Size(); + m_capacity = m_nRows; + } + else + { + m_matrix = new DVector[dvec.Size()](); + for (size_t i = 0; i < dvec.Size(); ++i) + { + m_matrix[i] = DVector(1, dvec[i]); + } + m_nRows = dvec.Size(); + m_nCols = 1; + m_capacity = m_nRows; + } } void DMatrix::Clear() @@ -243,10 +273,238 @@ DVector DMatrix::GetDiag() const DVector dvec(nElemsDiag); for (size_t i = 0; i < nElemsDiag; ++i) { + dvec[i] = m_matrix[i][i]; + } + return dvec; +} + +DVector DMatrix::GetRow(size_t index) const +{ + DVector dvec(m_nCols); + for (size_t i = 0; i < m_nCols; ++i) + { + dvec[i] = m_matrix[index][i]; + } + return dvec; +} + +DVector DMatrix::GetCol(size_t index) const +{ + DVector dvec(m_nRows); + for (size_t i = 0; i < m_nRows; ++i) + { + dvec[i] = m_matrix[i][index]; + } + return dvec; +} + +DMatrix DMatrix::Dot(DMatrix const &other) const +{ + IsEqualSize(m_nCols, other.nRows(), ERROR_ARITHMETIC); + + DMatrix dmat(m_nRows, other.nCols()); + for (size_t i = 0; i < m_nRows; ++i) + { + for (size_t j = 0; j < other.nCols(); ++j) + { + double elem_i_j = 0; + for (size_t k = 0; k < other.nRows(); ++k) + { + elem_i_j += m_matrix[i][k] * other.m_matrix[k][j]; + } + dmat[i][j] = elem_i_j; + } + } + return dmat; +} +// подразуемевается что матрица умножается на вектор-столбец +// результат - DVector +DVector DMatrix::Dot(DVector const &dvec) const +{ + IsEqualSize(m_nCols, dvec.Size(), ERROR_ARITHMETIC); + + DVector dvecRes(m_nRows); + for (size_t i = 0; i < m_nRows; ++i) + { + double elem_i_j = 0; + for (size_t j = 0; j < m_nCols; ++j) + { + elem_i_j += m_matrix[i][j] * dvec[j]; + } + dvecRes[i] = elem_i_j; } + return dvecRes; +} + +void DMatrix::AddNum(double value) +{ + std::for_each(m_matrix, &m_matrix[m_nRows - 1] + 1, [value](DVector &vec) + { + vec.AddNum(value); + }); } +void DMatrix::SubNum(double value) +{ + std::for_each(m_matrix, &m_matrix[m_nRows - 1] + 1, [value](DVector &vec) + { + vec.SubNum(value); + }); +} + +void DMatrix::AddVec(DVector const &dvec, ORIENT orientation) +{ + if (orientation == ORIENT::ROW) + { + IsEqualSize(dvec.Size(), m_nCols, ERROR_ARITHMETIC); + // почему capture принимает по ссылке, хотя в сигнатуре const? + std::for_each(m_matrix, &m_matrix[m_nRows - 1] + 1, [&dvec](DVector &vec) + { + vec += dvec; + }); + } + else + { + IsEqualSize(dvec.Size(), m_nRows, ERROR_ARITHMETIC); + for (size_t i = 0; i < dvec.Size(); ++i) + { + m_matrix[i].AddNum(dvec[i]); + } + } +} + +void DMatrix::SubVec(DVector const &dvec, ORIENT orientation) +{ + if (orientation == ORIENT::ROW) + { + IsEqualSize(dvec.Size(), m_nCols, ERROR_ARITHMETIC); + std::for_each(m_matrix, &m_matrix[m_nRows - 1] + 1, [&dvec](DVector &vec) + { + vec -= dvec; + }); + } + else + { + IsEqualSize(dvec.Size(), m_nRows, ERROR_ARITHMETIC); + for (size_t i = 0; i < dvec.Size(); ++i) + { + m_matrix[i].SubNum(dvec[i]); + } + } +} + +DMatrix DMatrix::T() const +{ + IsEqualSize(m_nRows, m_nCols, "Matrix is not square"); + DMatrix dmatRes(m_nRows, m_nCols); + for (size_t i = 0; i < m_nRows; ++i) + { + for (size_t j = 0; j < m_nCols; ++j) + { + dmatRes[j][i] = m_matrix[i][j]; + } + } + return dmatRes; +} + +double DMatrix::Det() const +{ + IsEqualSize(m_nRows, m_nCols, "Matrix is not square"); + if (m_nRows == 2) + { + return m_matrix[0][0] * m_matrix[1][1] - m_matrix[0][1] * m_matrix[1][0]; + } + else + { + double res = 0; + DMatrix *dmats = new DMatrix[m_nCols](); + // определитель матрицы через разложение по первой строке + for (size_t i = 0; i < m_nCols; ++i) + { + dmats[i] = *this; + dmats[i].EraseByIndex(0, ORIENT::ROW); + dmats[i].EraseByIndex(i, ORIENT::COL); + int8_t sign = i % 2 == 0 ? 1 : -1; + res += sign * m_matrix[0][i] * dmats[i].Det(); + } + delete[] dmats; + return res; + } +} + +double DMatrix::Minor(size_t iIndex, size_t jIndex) const +{ + DMatrix dmat = *this; + dmat.EraseByIndex(iIndex, ORIENT::ROW); + dmat.EraseByIndex(jIndex, ORIENT::COL); + return dmat.Det(); +} + +DMatrix DMatrix::Adj() +{ + DMatrix adjMat(m_nRows, m_nCols); + for (size_t i = 0; i < m_nRows; ++i) + { + for (size_t j = 0; j < m_nCols; ++j) + { + int8_t sign = (i + j) % 2 == 0 ? 1 : -1; + adjMat[i][j] = sign * Minor(i, j); + } + } + return adjMat; +} + +DMatrix DMatrix::Inv() +{ + double det = Det(); + if (det == 0) + { + return DMatrix{}; + } + DMatrix invMat = (1 / det) * Adj().T(); + return invMat; +} + +void DMatrix::EraseByIndex(size_t index, ORIENT orientation) +{ + if (m_nRows == 0) + { + throw std::runtime_error("Can't erase by index, Matrix is Empty"); + } + if (orientation == ORIENT::ROW) + { + if (index > m_nRows - 1) + { + throw std::runtime_error("Can't erase row by index"); + } + for (size_t i = index; i < m_nRows - 1; ++i) + { + m_matrix[i] = m_matrix[i + 1]; + } + m_matrix[--m_nRows].~DVector(); + if (m_nRows == 0) + { + Clear(); + } + } + else + { + if (index > m_nCols - 1) + { + throw std::runtime_error("Can't erase col by index"); + } + for (size_t i = 0; i < m_nRows; ++i) + { + m_matrix[i].Erase(&m_matrix[i][index]); + } + m_nCols--; + if (m_nCols == 0) + { + Clear(); + } + } +} void DMatrix::grow() { @@ -258,6 +516,138 @@ void DMatrix::grow() m_capacity = new_capacity; } +// ------------------------------------------------------------- + +DMatrix &operator*=(DMatrix &matrix, double value) +{ + for (size_t i = 0; i < matrix.nRows(); ++i) + { + matrix[i] *= value; + } + return matrix; +} + +DMatrix &operator/=(DMatrix &matrix, double value) +{ + for (size_t i = 0; i < matrix.nRows(); ++i) + { + matrix[i] /= value; + } + return matrix; +} + + +DMatrix operator*(DMatrix matrix, double value) +{ + return matrix *= value; +} + +DMatrix operator/(DMatrix matrix, double value) +{ + return matrix /= value; +} + +// ---------- --------------- ------------- + +DMatrix &operator*=(double value, DMatrix &matrix) +{ + return matrix *= value; +} + +DMatrix &operator/=(double value, DMatrix &matrix) +{ + return matrix /= value; +} + + +DMatrix operator*(double value, DMatrix matrix) +{ + return matrix *= value; +} + +DMatrix operator/(double value, DMatrix matrix) +{ + return matrix /= value; +} + +// ------------------------------------------------------------- + +DMatrix &operator+=(DMatrix &left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); + IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); + for (size_t i = 0; i < left.nRows(); ++i) + { + left[i] += right[i]; + } + return left; +} + +DMatrix &operator-=(DMatrix &left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); + IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); + for (size_t i = 0; i < left.nRows(); ++i) + { + left[i] -= right[i]; + } + return left; +} + +DMatrix &operator*=(DMatrix &left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); + IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); + for (size_t i = 0; i < left.nRows(); ++i) + { + left[i] *= right[i]; + } + return left; +} + +DMatrix &operator/=(DMatrix &left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); + IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); + for (size_t i = 0; i < left.nRows(); ++i) + { + left[i] /= right[i]; + } + return left; +} + +// -------------------------------------------------------- + +DMatrix operator+(DMatrix left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); + IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); + return left += right; +} + +DMatrix operator-(DMatrix left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); + IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); + return left -= right; +} + +DMatrix operator*(DMatrix left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); + IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); + return left *= right; +} + +DMatrix operator/(DMatrix left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); + IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); + return left /= right; +} + +// -------------------------------------------------------- + void Print(DMatrix const &matrix, std::string const &msg) { diff --git a/matrix_lib/src/dvector.cpp b/matrix_lib/src/dvector.cpp index 1f67110..e7fcff3 100644 --- a/matrix_lib/src/dvector.cpp +++ b/matrix_lib/src/dvector.cpp @@ -2,13 +2,14 @@ #include "stdafx.h" #include "dvector.h" +#include "dmatrix.h" // static + const = const const std::string ERROR_ARITHMETIC = "Arithmetic operations on vectors of different size"; const std::string ERROR_RANGE = "Index out of range"; const std::string ERROR_EMPTY = "DVector is empty"; -void IsEqualSize(size_t size1, size_t size2, std::string const &msgError = "Exception") +static void IsEqualSize(size_t size1, size_t size2, std::string const &msgError = "Exception") { if (size1 != size2) { @@ -198,6 +199,21 @@ double *DVector::Find(double value) const return result; } +void DVector::AddNum(double value) +{ + // можно сделать Begin() и End() приватными + std::for_each(m_array, &m_array[m_size - 1] + 1, [value](double &elem){ + elem += value; + }); +} + +void DVector::SubNum(double value) +{ + std::for_each(m_array, &m_array[m_size - 1] + 1, [value](double &elem){ + elem -= value; + }); +} + // возвращает элемент, следующий за удаленным либо предыдущий, если удаленный был последним double *DVector::Erase(double *it_value) { @@ -322,6 +338,25 @@ double DVector::Dot(DVector const &other) const return dotProduct; } +// подразуемевается что вектор-строка умножается на матрицу +// результат - DVector +DVector DVector::Dot(DMatrix const &matrix) const +{ + IsEqualSize(m_size, matrix.nRows(), ERROR_ARITHMETIC); + + DVector dvecRes(matrix.nCols()); + for (size_t i = 0; i < matrix.nCols(); ++i) + { + double elem_i_j = 0; + for (size_t j = 0; j < m_size; ++j) + { + elem_i_j += matrix[j][i] * m_array[j]; + } + dvecRes[i] = elem_i_j; + } + return dvecRes; +} + void DVector::grow() { size_t new_capacity = std::max(1, static_cast(m_capacity * 2)); diff --git a/matrix_lib/tests/test_matrix.cpp b/matrix_lib/tests/test_matrix.cpp index 09fc259..ae59a73 100644 --- a/matrix_lib/tests/test_matrix.cpp +++ b/matrix_lib/tests/test_matrix.cpp @@ -2,6 +2,34 @@ #include "dmatrix.h" +bool CheckMatrix(DMatrix const &matrix, std::initializer_list> const &init_list) +{ + for (size_t i = 0; i < matrix.nRows(); ++i) + { + for (size_t j = 0; j < matrix.nCols(); ++j) + { + if (matrix[i][j] - *((init_list.begin() + i)->begin() + j) > 0.000001) + { + return false; + } + } + } + return true; +} + +static bool CheckVector(DVector const &dvec, std::initializer_list const &init_list) +{ + for (size_t i = 0; i < dvec.Size(); ++i) + { + if (dvec[i] - *(init_list.begin() + i) > 0.000001) + { + return false; + } + } + return true; +} + + TEST(TestCreateDMatrix, TestConstructorsSpecifySizeAndInitList) { DMatrix dmat1(3, 10, 4); @@ -34,11 +62,28 @@ TEST(TestCreateDMatrix, TestConstructorsDVectorsAndCopy) EXPECT_EQ(dmat1[1][0], 3); EXPECT_EQ(dmat1[0][1], 7); +} + +TEST(TestCreateDMatrix, TestConstructorsSpecifyRowOrCol) +{ + DMatrix dmat(DVector{2, 4, 6, 8}); // ORIENT::ROW by default - DMatrix dmat3(DVector{2, 4, 6, 8}); - EXPECT_EQ(dmat3.nRows(), 1); - EXPECT_EQ(dmat3.nCols(), 4); - EXPECT_EQ(dmat3[0][2], 6); + EXPECT_EQ(dmat.nRows(), 1); + EXPECT_EQ(dmat.nCols(), 4); + + EXPECT_TRUE(CheckMatrix(dmat, { + {2, 4, 6, 8} + })); + + dmat = DMatrix(DVector{2, 4, 6, 8}, ORIENT::COL); + EXPECT_EQ(dmat.nRows(), 4); + EXPECT_EQ(dmat.nCols(), 1); + EXPECT_TRUE(CheckMatrix(dmat, { + {2}, + {4}, + {6}, + {8} + })); } TEST(TestCreateDMatrix, TestOperatorAssign) @@ -71,7 +116,7 @@ TEST(TestErrorHandling, TestAccessAndCreateNotRectangleMatrix) EXPECT_THROW(dmat[0][5], std::runtime_error); } -TEST(TestErrorHandling, TestPushPopRow) +TEST(TestFunctionalityDMatrix, TestPushPopRow) { DMatrix dmat; EXPECT_THROW(dmat.PopRowBack(), std::runtime_error); @@ -85,8 +130,11 @@ TEST(TestErrorHandling, TestPushPopRow) EXPECT_THROW(dmat.PushRowBack(dvec2), std::runtime_error); - EXPECT_EQ(dmat[0][1], 2); - EXPECT_EQ(dmat[1][2], 6); + EXPECT_TRUE(CheckMatrix(dmat, { + {1, 2, 3}, + {4, 5, 6} + })); + EXPECT_EQ(dmat.nCols(), 3); EXPECT_EQ(dmat.nRows(), 2); @@ -104,7 +152,7 @@ TEST(TestErrorHandling, TestPushPopRow) // размер матрицы зависит от ее содержимого // без содержимого матрица не имеет размера и может в будущем принимать любые формы -TEST(TestErrorHandling, TestPushPopRow_WithChangeDimensity) +TEST(TestFunctionalityDMatrix, TestPushPopRow_WithChangeDimensity) { DMatrix dmat; dmat.PushRowBack({0, 0, 7}); @@ -126,7 +174,7 @@ TEST(TestErrorHandling, TestPushPopRow_WithChangeDimensity) EXPECT_EQ(dmat.Capacity(), 1); } -TEST(TestErrorHandling, TestPushPopCol) +TEST(TestFunctionalityDMatrix, TestPushPopCol) { DMatrix dmat; dmat.PushColBack({1, 2, 3}); @@ -152,7 +200,7 @@ TEST(TestErrorHandling, TestPushPopCol) EXPECT_EQ(dmat.nRows(), 2); } -TEST(TestErrorHandling, TestPushPopMix) +TEST(TestFunctionalityDMatrix, TestPushPopMix) { DMatrix dmat{ {1, 2, 3}, @@ -161,7 +209,12 @@ TEST(TestErrorHandling, TestPushPopMix) dmat.PushColBack({7, 7}); dmat.PushRowBack({8, 8, 8, 100}); - EXPECT_EQ(dmat[2][3], 100); + EXPECT_TRUE(CheckMatrix(dmat, { + {1, 2, 3, 7}, + {4, 5, 6, 7}, + {8, 8, 8, 100}, + })); + EXPECT_EQ(dmat.nCols(), 4); EXPECT_EQ(dmat.nRows(), 3); @@ -181,6 +234,337 @@ TEST(TestErrorHandling, TestPushPopMix) dmat = {{1, 2, 3, 4, 5, 6, 7}}; dmat.PushColBack({8}); - EXPECT_EQ(dmat[0][0], 1); - EXPECT_EQ(dmat[0][7], 8); -} \ No newline at end of file + + EXPECT_TRUE(CheckMatrix(dmat, { + {1, 2, 3, 4, 5, 6, 7, 8} + })); + +} + +TEST(TestFunctionalityDMatrix, TestGetRowColDiag) +{ + // GetCol + DMatrix dmat{ + {1, 2, 3, 4, 5}, + {6, 7, 8, 9, 10} + }; + + DVector dvec1 = dmat.GetCol(0); + EXPECT_EQ(dvec1[0], dmat[0][0]); + EXPECT_EQ(dvec1[1], dmat[1][0]); + + dvec1[0] = 100; + EXPECT_NE(dvec1[0], dmat[0][0]); + + dmat[1][0] = 600; + EXPECT_NE(dvec1[1], dmat[1][0]); + + DVector dvec2 = dmat.GetCol(4); + EXPECT_EQ(dvec2.Size(), 2); + EXPECT_EQ(dvec2[0], dmat[0][4]); + EXPECT_EQ(dvec2[1], dmat[1][4]); + + // GetRow + DVector dvec3 = dmat.GetRow(1); + EXPECT_EQ(dvec3.Size(), 5); + EXPECT_EQ(dvec3[0], dmat[1][0]); + EXPECT_EQ(dvec3[4], dmat[1][4]); + + // GetDiag + DVector dvec4 = dmat.GetDiag(); + EXPECT_EQ(dvec4.Size(), 2); + EXPECT_EQ(dvec4[0], dmat[0][0]); + EXPECT_EQ(dvec4[1], dmat[1][1]); + + DMatrix dmat2{ + {10}, + {20} + }; + + DVector dvec5 = dmat2.GetDiag(); + EXPECT_EQ(dvec5.Size(), 1); + EXPECT_EQ(dvec5[0], dmat2[0][0]); + + DMatrix dmat3{ + {3, 5}, + {7, 9} + }; + + DVector dvec6 = dmat3.GetDiag(); + EXPECT_EQ(dvec6.Size(), 2); + EXPECT_EQ(dvec6[0], dmat3[0][0]); + EXPECT_EQ(dvec6[1], dmat3[1][1]); +} + +TEST(TestFunctionalityDMatrix, TestArithmeticOperators) +{ + DMatrix dmat1{ + {1, 2, 3}, + {6, 7, 8} + }; + DMatrix dmat2{ + {11, 12, 13}, + {14, 15, 16} + }; + DMatrix dmatErr1{ + {1, 1}, + {1, 1} + }; + + DMatrix dmatErr2; + DMatrix dmatErr3{ + {2, 4, 6} + }; + DMatrix dmat3 = dmat1 * 2 + dmat2 / 1; + + EXPECT_THROW(dmat3 + dmatErr1, std::runtime_error); + EXPECT_THROW(dmat3 *= dmatErr1, std::runtime_error); + EXPECT_THROW(dmat3 -= dmatErr2, std::runtime_error); + EXPECT_THROW(dmat3 / dmatErr3, std::runtime_error); + + EXPECT_TRUE(CheckMatrix(dmat3, { + {13, 16, 19}, + {26, 29, 32} + })); + +} + +TEST(TestFunctionalityDMatrix, TestDotProductOfMatrices) +{ + DMatrix dmat1{ + {1, 2, 3}, + {4, 5, 6} + }; + + DMatrix dmat2{ + {2, 3}, + {4, 5}, + {6, 7} + }; + + DMatrix dmatRes = dmat1.Dot(dmat2); + EXPECT_EQ(dmatRes.nRows(), 2); + EXPECT_EQ(dmatRes.nCols(), 2); + + EXPECT_TRUE(CheckMatrix(dmatRes, { {28, 34}, {64, 79} })); +} + + +TEST(TestFunctionalityDMatrix, TestDotProductBetweenMatrixAndVector) +{ + // matrix * vector + + DMatrix dmat1{ + {1, 2, 3}, + {4, 5, 6} + }; + + DVector dvec1{1, 2, 3}; + DVector dvecErr{1, 2, 3, 4}; + + EXPECT_TRUE(CheckVector(dmat1.Dot(dvec1), { 14, 32 })); + EXPECT_THROW(dmat1.Dot(dvecErr), std::runtime_error); + + // vector * matrix + + DVector dvec2{1, 2}; + EXPECT_TRUE(CheckVector(dvec2.Dot(dmat1), { 9, 12, 15 })); + + DMatrix dmatErr{ + {1, 2}, + {3, 4}, + {5, 6} + }; + EXPECT_THROW(dvec2.Dot(dmatErr), std::runtime_error); +} + +TEST(TestFunctionalityDMatrix, TestAddSubVectorAndNum) +{ + DMatrix dmat{ + {1, 2, 3}, + {4, 5, 6} + }; + + dmat.AddNum(1); + EXPECT_TRUE(CheckMatrix(dmat, { + {2, 3, 4}, + {5, 6, 7} + })); + + DVector dvec1{10, 15}; + dmat.AddVec(dvec1, ORIENT::COL); + EXPECT_TRUE(CheckMatrix(dmat, { + {12, 13, 14}, + {20, 21, 22} + })); + + DVector dvec2{10, 10, 0}; + dmat.SubVec(dvec2, ORIENT::ROW); // but ORIENT::ROW by default + EXPECT_TRUE(CheckMatrix(dmat, { + {2, 3, 14}, + {10, 11, 22} + })); + + EXPECT_THROW(dmat.AddVec({1}, ORIENT::ROW), std::runtime_error); + EXPECT_THROW(dmat.AddVec({1}, ORIENT::COL), std::runtime_error); +} + +TEST(TestFunctionalityDMatrix, TestTransponse) +{ + DMatrix dmat{ + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9} + }; + DMatrix dmatT = dmat.T(); + + EXPECT_TRUE(CheckMatrix(dmatT, { + {1, 4, 7}, + {2, 5, 8}, + {3, 6, 9} + })); + + EXPECT_THROW(DMatrix({{1, 2}}).T(), std::runtime_error); +} + +TEST(TestFunctionalityDMatrix, TestEraseByIndexRow) +{ + // Erase row + DMatrix dmat{ + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9} + }; + dmat.EraseByIndex(0); + EXPECT_TRUE(CheckMatrix(dmat, { + {4, 5, 6}, + {7, 8, 9} + })); + dmat.EraseByIndex(1); + EXPECT_TRUE(CheckMatrix(dmat, { + {4, 5, 6} + })); + + + EXPECT_EQ(dmat.nRows(), 1); + EXPECT_EQ(dmat.nCols(), 3); + + EXPECT_THROW(dmat.EraseByIndex(1), std::runtime_error); + dmat.EraseByIndex(0); + EXPECT_THROW(dmat.EraseByIndex(0), std::runtime_error); + + EXPECT_EQ(dmat.nRows(), 0); + EXPECT_EQ(dmat.nCols(), 0); + EXPECT_EQ(dmat.Capacity(), 0); +} + +TEST(TestFunctionalityDMatrix, TestEraseByIndexCol) +{ + DMatrix dmat = { + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9} + }; + + dmat.EraseByIndex(1, ORIENT::COL); + EXPECT_TRUE(CheckMatrix(dmat, { + {1, 3}, + {4, 6}, + {7, 9} + })); + + EXPECT_EQ(dmat.nRows(), 3); + EXPECT_EQ(dmat.nCols(), 2); + + dmat.EraseByIndex(0, ORIENT::COL); + EXPECT_TRUE(CheckMatrix(dmat, { + {3}, + {6}, + {9} + })); + + dmat.EraseByIndex(0, ORIENT::COL); + EXPECT_TRUE(CheckMatrix(dmat, {{}})); + + EXPECT_THROW(dmat.EraseByIndex(0, ORIENT::COL), std::runtime_error); + EXPECT_THROW(dmat.EraseByIndex(200, ORIENT::COL), std::runtime_error); +} + +TEST(TestFunctionalityDMatrix, TestDeterminant) +{ + DMatrix dmat1 = { + {3, 5}, + {1, 5} + }; + EXPECT_EQ(dmat1.Det(), 10); + + DMatrix dmat2 = { + {3, 5, 2}, + {1, 5, 6}, + {5, 7, 2} + }; + EXPECT_EQ(dmat2.Det(), 8); + + DMatrix dmat3 = { + {3, 5, 2, 7}, + {1, 5, 6, 4}, + {5, 7, 2, 9}, + {5, 7, 2, 5} + }; + EXPECT_EQ(dmat3.Det(), -32); +} + +TEST(TestFunctionalityDMatrix, TestInvertibleMatrix) +{ + DMatrix dmat1 = { + {1, -2, 1}, + {2, 1, -1}, + {3, 2, -2} + }; + + DMatrix dmatInv = dmat1.Inv(); + + EXPECT_EQ(dmatInv.nRows(), 3); + EXPECT_EQ(dmatInv.nCols(), 3); + + EXPECT_TRUE(CheckMatrix(dmatInv, { + {0, 2, -1}, + {-1, 5, -3}, + {-1, 8, -5} + })); + + DMatrix dmat2 = { + {1, 1, 1, -1}, + {1, -2, 1, -1}, + {1, 1, 3, 1}, + {1, 1, 1, -4} + }; + + dmatInv = dmat2.Inv(); + + EXPECT_TRUE(CheckMatrix(dmatInv, { + {11./6, 1./3, -1./2, -2./3}, + {1./3, -1./3, 0, 0}, + {-5./6, 0, 1./2, 1./3}, + {1./3, 0, 0, -1./3} + })); + + DMatrix dmatErr1 = { + {1, -2, 1}, + {2, 1, -1}, + }; + + // определитель = 0, обратной матрицы не существует + DMatrix dmatErr2 = { + {1, 2}, + {2, 4}, + }; + + EXPECT_THROW(dmatErr1.Inv(), std::runtime_error); + EXPECT_TRUE(dmatErr2.Inv().Empty()); + + +} + + + diff --git a/matrix_lib/tests/test_vector.cpp b/matrix_lib/tests/test_vector.cpp index 8c46b91..2e60cc4 100644 --- a/matrix_lib/tests/test_vector.cpp +++ b/matrix_lib/tests/test_vector.cpp @@ -2,6 +2,18 @@ #include "dvector.h" +static bool CheckVector(DVector const &dvec, std::initializer_list const &init_list) +{ + for (size_t i = 0; i < dvec.Size(); ++i) + { + if (dvec[i] != *(init_list.begin() + i)) + { + return false; + } + } + return true; +} + TEST(TestCreateDVector, TestDefaultConstructor) { DVector dvec1; @@ -177,3 +189,12 @@ TEST(TestFunctionalityDVector, TestArithmeticOperators) EXPECT_EQ(resDot, 38); } +TEST(TestFunctionalityDVector, TestAddSubNum) +{ + DVector dvec{1, 2, 3}; + dvec.AddNum(2); + EXPECT_TRUE(CheckVector(dvec, {3, 4, 5})); + dvec.SubNum(3); + EXPECT_TRUE(CheckVector(dvec, {0, 1, 2})); +} + From 7a1bcb144e38b6c04614d934b024b8c63d8e216b Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Mon, 17 Oct 2022 20:16:00 +0300 Subject: [PATCH 09/17] refactoring of code, slices, template static function Create() --- matrix_lib/include/dmatrix.h | 45 ++++- matrix_lib/include/dvector.h | 11 +- matrix_lib/src/dmatrix.cpp | 235 +++++++++++---------------- matrix_lib/src/dmatrix_operators.cpp | 147 +++++++++++++++++ matrix_lib/src/dvector.cpp | 163 +++++-------------- matrix_lib/src/dvector_operators.cpp | 114 +++++++++++++ matrix_lib/tests/test_matrix.cpp | 211 +++++++++++++++++++++--- matrix_lib/tests/test_vector.cpp | 55 ++++--- 8 files changed, 659 insertions(+), 322 deletions(-) create mode 100644 matrix_lib/src/dmatrix_operators.cpp create mode 100644 matrix_lib/src/dvector_operators.cpp diff --git a/matrix_lib/include/dmatrix.h b/matrix_lib/include/dmatrix.h index 20a3331..fa84444 100644 --- a/matrix_lib/include/dmatrix.h +++ b/matrix_lib/include/dmatrix.h @@ -2,7 +2,8 @@ #include "dvector.h" -enum class ORIENT { ROW = 0, COL }; +enum class ORIENT { ROW = 0, COL }; +enum SLICE { ROW = 0, COL }; class DMatrix { @@ -23,11 +24,18 @@ class DMatrix DMatrix(DMatrix &&other); DMatrix &operator=(DMatrix other); ~DMatrix(); + + template + static DMatrix Create(double fill_value = 0) + { + return DMatrix(rows, cols, fill_value); + } + public: void Clear(); bool Empty(); void Swap(DMatrix &other); - // Удаление / добавление последних строк / столбцов + void PushRowBack(DVector const &dvec); void PushRowBack(std::initializer_list const &init_list); void PopRowBack(); @@ -38,10 +46,13 @@ class DMatrix void EraseByIndex(size_t index, ORIENT orientation = ORIENT::ROW); + + /* ****** ЗАДАНИЕ 1 ****** */ DVector GetDiag() const; DVector GetRow(size_t index) const; DVector GetCol(size_t index) const; + /* ****** ЗАДАНИЕ 4 ****** */ DMatrix Dot(DMatrix const &other) const; DVector Dot(DVector const &dvec) const; @@ -49,44 +60,64 @@ class DMatrix size_t nCols() const; size_t Capacity() const; + /* ****** ЗАДАНИЕ 5 ****** */ // модифицирующие операции void AddNum(double value); void SubNum(double value); void AddVec(DVector const &dvec, ORIENT orientation = ORIENT::ROW); void SubVec(DVector const &dvec, ORIENT orientation = ORIENT::ROW); + /* ****** ЗАДАНИЯ 6 и 7 ****** */ DMatrix T() const; - // DMatrix GetMatrix - double Det() const; - double Minor(size_t iIndex, size_t jIndex) const; + double Det() const; + double Minor(size_t iIndex, size_t jIndex) const; DMatrix Adj(); DMatrix Inv(); DVector const &operator[](size_t index) const; DVector &operator[](size_t index); + + /* + Slicing как в NumPy C++ + matrix({1, 4}, {2, 5}) - нельзя отдельно по столбцам + + enum SLICE {ROW = 0, COL}, чтобы + 1. не писать класс, если в параметрах ROW / COL + 2. кастилось к enum SLICE, если в параметрах 0 / 1 + */ + + /* ****** Slices ****** */ + DMatrix operator()(size_t begin, size_t end, int step = 1, uint8_t sliceType = SLICE::ROW) const; + + DMatrix SliceRow(size_t begin, size_t end, int step = 1) const; + DMatrix SliceCol(size_t begin, size_t end, int step = 1) const; }; +// matrix *= value DMatrix &operator/=(DMatrix &matrix, double value); DMatrix &operator*=(DMatrix &matrix, double value); +// matrix * value DMatrix operator/(DMatrix matrix, double value); DMatrix operator*(DMatrix matrix, double value); -// ----- +// value *= matrix DMatrix &operator/=(double value, DMatrix &matrix); DMatrix &operator*=(double value, DMatrix &matrix); +// value * matrix DMatrix operator/(double value, DMatrix matrix); DMatrix operator*(double value, DMatrix matrix); -// ----- +// matrix += matrix DMatrix &operator+=(DMatrix &left, DMatrix const &right); DMatrix &operator-=(DMatrix &left, DMatrix const &right); DMatrix &operator/=(DMatrix &left, DMatrix const &right); DMatrix &operator*=(DMatrix &left, DMatrix const &right); +// matrix + matrix DMatrix operator+(DMatrix left, DMatrix const &right); DMatrix operator-(DMatrix left, DMatrix const &right); DMatrix operator/(DMatrix left, DMatrix const &right); diff --git a/matrix_lib/include/dvector.h b/matrix_lib/include/dvector.h index ff0b805..ab828ef 100644 --- a/matrix_lib/include/dvector.h +++ b/matrix_lib/include/dvector.h @@ -46,26 +46,35 @@ class DVector double const &operator[](size_t index) const; double &operator[](size_t index); - // немодифицирующие операции + /* ****** ЗАДАНИЕ 4 ****** */ double Dot(DVector const &other) const; DVector Dot(DMatrix const &matrix) const; + + /* ****** ЗАДАНИЕ 5 ****** */ // модифицирующие операции void AddNum(double value); void SubNum(double value); + + /* ****** Slices ****** */ + DVector operator()(size_t begin, size_t end, int step = 1) const; }; +// vector *= value DVector &operator/=(DVector &left, double value); DVector &operator*=(DVector &left, double value); +// vector * value DVector operator/(DVector left, double value); DVector operator*(DVector left, double value); +// vector += vector DVector &operator+=(DVector &left, DVector const &right); DVector &operator-=(DVector &left, DVector const &right); DVector &operator/=(DVector &left, DVector const &right); DVector &operator*=(DVector &left, DVector const &right); +// vector + vector DVector operator+(DVector left, DVector const &right); DVector operator-(DVector left, DVector const &right); DVector operator/(DVector left, DVector const &right); diff --git a/matrix_lib/src/dmatrix.cpp b/matrix_lib/src/dmatrix.cpp index 7581d52..326bced 100644 --- a/matrix_lib/src/dmatrix.cpp +++ b/matrix_lib/src/dmatrix.cpp @@ -1,13 +1,15 @@ -#include - #include "stdafx.h" #include "dmatrix.h" -const std::string ERROR_EMPTY = "DMatrix is empty"; -const std::string ERROR_ARITHMETIC = "Arithmetic operations on matrix of different size"; +// т.к. const имеет внутреннее связывание, добавляем extern, чтобы можно было включить в другой .cpp файл +extern const std::string ERROR_EMPTY = "Data structure is empty"; +extern const std::string ERROR_SIZE = "An arithmetic operation is not possible because of different sizes"; +extern const std::string ERROR_RANGE = "Index out of range"; +const std::string ERROR_LENGTH = "In a matrix, all row and column lengths must be the same"; +const std::string ERROR_RECT_MATRIX = "Matrix is not square"; // проверка на равный размер, иначе исключение -static void IsEqualSize(size_t size1, size_t size2, std::string const &msgError = "Exception") +void IsEqualSize(size_t size1, size_t size2, std::string const &msgError = "Exception") { if (size1 != size2) { @@ -33,7 +35,7 @@ DMatrix::DMatrix(std::initializer_list> const &ini return list.size() != n; })) { - throw std::runtime_error("The matrix has rows of different lengths"); + throw std::runtime_error("DMatrix: " + ERROR_LENGTH); } m_matrix = new DVector[m_nRows](); int i = 0; @@ -67,7 +69,7 @@ DMatrix::DMatrix(DVector *matrix, size_t nRows) : m_matrix(matrix), m_nRows(nRow { if (matrix[i].Size() != m_nCols) { - throw std::runtime_error("The matrix has rows of different lengths"); + throw std::runtime_error("DMatrix: " + ERROR_LENGTH); } } } @@ -139,7 +141,7 @@ DVector const &DMatrix::operator[](size_t index) const { if (index > m_nRows - 1) { - throw std::runtime_error("Index out of range"); + throw std::runtime_error("operator[]: " + ERROR_RANGE); } return m_matrix[index]; } @@ -148,7 +150,7 @@ DVector &DMatrix::operator[](size_t index) { if (index > m_nRows - 1) { - throw std::runtime_error("Index out of range"); + throw std::runtime_error("operator[]: " + ERROR_RANGE); } return m_matrix[index]; } @@ -167,7 +169,7 @@ void DMatrix::PushRowBack(DVector const &dvec) { if (m_nRows > 0 && dvec.Size() != m_nCols) { - throw std::runtime_error("The matrix has rows of different lengths"); + throw std::runtime_error("PushRowBack: " + ERROR_LENGTH); } m_nCols = dvec.Size(); if (m_nRows == m_capacity) @@ -181,7 +183,7 @@ void DMatrix::PushRowBack(std::initializer_list const &init_list) { if (m_nRows > 0 && init_list.size() != m_nCols) { - throw std::runtime_error("The matrix has rows of different lengths"); + throw std::runtime_error("PushRowBack: " + ERROR_LENGTH); } m_nCols = init_list.size(); if (m_nRows == m_capacity) @@ -195,7 +197,7 @@ void DMatrix::PopRowBack() { if (Empty()) { - throw std::runtime_error("PopBack(): " + ERROR_EMPTY); + throw std::runtime_error("PopRowBack: " + ERROR_EMPTY); } m_matrix[--m_nRows].~DVector(); if (m_nRows == 0) @@ -212,7 +214,7 @@ void DMatrix::PushColBack(DVector const &dvec) { if (m_nRows > 0 && dvec.Size() != m_nRows) { - throw std::runtime_error("The matrix has rows of different lengths"); + throw std::runtime_error("PushColBack: " + ERROR_LENGTH); } if (m_nRows == 0) { @@ -231,7 +233,7 @@ void DMatrix::PushColBack(std::initializer_list const &init_list) { if (m_nRows > 0 && init_list.size() != m_nRows) { - throw std::runtime_error("The matrix has rows of different lengths"); + throw std::runtime_error("PushColBack: " + ERROR_LENGTH); } if (m_nRows == 0) { @@ -250,7 +252,7 @@ void DMatrix::PopColBack() { if (Empty()) { - throw std::runtime_error("PopBack(): " + ERROR_EMPTY); + throw std::runtime_error("PopColBack: " + ERROR_EMPTY); } --m_nCols; for (size_t i = 0; i < m_nRows; ++i) @@ -280,6 +282,10 @@ DVector DMatrix::GetDiag() const DVector DMatrix::GetRow(size_t index) const { + if (index >= m_nRows) + { + throw std::runtime_error("GetRow: " + ERROR_RANGE); + } DVector dvec(m_nCols); for (size_t i = 0; i < m_nCols; ++i) { @@ -290,6 +296,10 @@ DVector DMatrix::GetRow(size_t index) const DVector DMatrix::GetCol(size_t index) const { + if (index >= m_nCols) + { + throw std::runtime_error("GetCol: " + ERROR_RANGE); + } DVector dvec(m_nRows); for (size_t i = 0; i < m_nRows; ++i) { @@ -300,7 +310,7 @@ DVector DMatrix::GetCol(size_t index) const DMatrix DMatrix::Dot(DMatrix const &other) const { - IsEqualSize(m_nCols, other.nRows(), ERROR_ARITHMETIC); + IsEqualSize(m_nCols, other.nRows(), "Dot: " + ERROR_SIZE); DMatrix dmat(m_nRows, other.nCols()); for (size_t i = 0; i < m_nRows; ++i) @@ -322,7 +332,7 @@ DMatrix DMatrix::Dot(DMatrix const &other) const // результат - DVector DVector DMatrix::Dot(DVector const &dvec) const { - IsEqualSize(m_nCols, dvec.Size(), ERROR_ARITHMETIC); + IsEqualSize(m_nCols, dvec.Size(), "Dot: " + ERROR_SIZE); DVector dvecRes(m_nRows); for (size_t i = 0; i < m_nRows; ++i) @@ -357,7 +367,7 @@ void DMatrix::AddVec(DVector const &dvec, ORIENT orientation) { if (orientation == ORIENT::ROW) { - IsEqualSize(dvec.Size(), m_nCols, ERROR_ARITHMETIC); + IsEqualSize(dvec.Size(), m_nCols, "AddVec: " + ERROR_SIZE); // почему capture принимает по ссылке, хотя в сигнатуре const? std::for_each(m_matrix, &m_matrix[m_nRows - 1] + 1, [&dvec](DVector &vec) { @@ -366,7 +376,7 @@ void DMatrix::AddVec(DVector const &dvec, ORIENT orientation) } else { - IsEqualSize(dvec.Size(), m_nRows, ERROR_ARITHMETIC); + IsEqualSize(dvec.Size(), m_nRows, "AddVec: " + ERROR_SIZE); for (size_t i = 0; i < dvec.Size(); ++i) { m_matrix[i].AddNum(dvec[i]); @@ -378,7 +388,7 @@ void DMatrix::SubVec(DVector const &dvec, ORIENT orientation) { if (orientation == ORIENT::ROW) { - IsEqualSize(dvec.Size(), m_nCols, ERROR_ARITHMETIC); + IsEqualSize(dvec.Size(), m_nCols, "SubVec: " + ERROR_SIZE); std::for_each(m_matrix, &m_matrix[m_nRows - 1] + 1, [&dvec](DVector &vec) { vec -= dvec; @@ -386,7 +396,7 @@ void DMatrix::SubVec(DVector const &dvec, ORIENT orientation) } else { - IsEqualSize(dvec.Size(), m_nRows, ERROR_ARITHMETIC); + IsEqualSize(dvec.Size(), m_nRows, "SubVec: " + ERROR_SIZE); for (size_t i = 0; i < dvec.Size(); ++i) { m_matrix[i].SubNum(dvec[i]); @@ -396,7 +406,7 @@ void DMatrix::SubVec(DVector const &dvec, ORIENT orientation) DMatrix DMatrix::T() const { - IsEqualSize(m_nRows, m_nCols, "Matrix is not square"); + IsEqualSize(m_nRows, m_nCols, "Transponse: " + ERROR_RECT_MATRIX); DMatrix dmatRes(m_nRows, m_nCols); for (size_t i = 0; i < m_nRows; ++i) { @@ -410,7 +420,7 @@ DMatrix DMatrix::T() const double DMatrix::Det() const { - IsEqualSize(m_nRows, m_nCols, "Matrix is not square"); + IsEqualSize(m_nRows, m_nCols, "Determinant: " + ERROR_RECT_MATRIX); if (m_nRows == 2) { return m_matrix[0][0] * m_matrix[1][1] - m_matrix[0][1] * m_matrix[1][0]; @@ -470,13 +480,13 @@ void DMatrix::EraseByIndex(size_t index, ORIENT orientation) { if (m_nRows == 0) { - throw std::runtime_error("Can't erase by index, Matrix is Empty"); + throw std::runtime_error("EraseByIndex: " + ERROR_RANGE); } if (orientation == ORIENT::ROW) { if (index > m_nRows - 1) { - throw std::runtime_error("Can't erase row by index"); + throw std::runtime_error("EraseByIndex: " + ERROR_RANGE); } for (size_t i = index; i < m_nRows - 1; ++i) { @@ -492,7 +502,7 @@ void DMatrix::EraseByIndex(size_t index, ORIENT orientation) { if (index > m_nCols - 1) { - throw std::runtime_error("Can't erase col by index"); + throw std::runtime_error("EraseByIndex: " + ERROR_RANGE); } for (size_t i = 0; i < m_nRows; ++i) { @@ -506,148 +516,85 @@ void DMatrix::EraseByIndex(size_t index, ORIENT orientation) } } -void DMatrix::grow() +DMatrix DMatrix::operator()(size_t begin, size_t end, int step, uint8_t sliceType) const { - size_t new_capacity = std::max(1, static_cast(m_capacity * 2)); - DVector *new_matrix = new DVector[new_capacity](); - std::copy(m_matrix, &m_matrix[m_nRows - 1] + 1, new_matrix); - delete[] m_matrix; - m_matrix = new_matrix; - m_capacity = new_capacity; -} - -// ------------------------------------------------------------- - -DMatrix &operator*=(DMatrix &matrix, double value) -{ - for (size_t i = 0; i < matrix.nRows(); ++i) + if (sliceType == SLICE::ROW) { - matrix[i] *= value; + return SliceRow(begin, end, step); } - return matrix; -} - -DMatrix &operator/=(DMatrix &matrix, double value) -{ - for (size_t i = 0; i < matrix.nRows(); ++i) + else { - matrix[i] /= value; + return SliceCol(begin, end, step); } - return matrix; -} - - -DMatrix operator*(DMatrix matrix, double value) -{ - return matrix *= value; -} - -DMatrix operator/(DMatrix matrix, double value) -{ - return matrix /= value; -} - -// ---------- --------------- ------------- - -DMatrix &operator*=(double value, DMatrix &matrix) -{ - return matrix *= value; -} - -DMatrix &operator/=(double value, DMatrix &matrix) -{ - return matrix /= value; -} - - -DMatrix operator*(double value, DMatrix matrix) -{ - return matrix *= value; -} - -DMatrix operator/(double value, DMatrix matrix) -{ - return matrix /= value; } -// ------------------------------------------------------------- - -DMatrix &operator+=(DMatrix &left, DMatrix const &right) +DMatrix DMatrix::SliceRow(size_t begin, size_t end, int step) const { - IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); - IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); - for (size_t i = 0; i < left.nRows(); ++i) + if (begin >= end) { - left[i] += right[i]; + throw std::runtime_error("operator(): " + ERROR_RANGE); } - return left; -} - -DMatrix &operator-=(DMatrix &left, DMatrix const &right) -{ - IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); - IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); - for (size_t i = 0; i < left.nRows(); ++i) + if (begin >= m_nRows || end > m_nRows) { - left[i] -= right[i]; + throw std::runtime_error("operator(): " + ERROR_RANGE); } - return left; -} - -DMatrix &operator*=(DMatrix &left, DMatrix const &right) -{ - IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); - IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); - for (size_t i = 0; i < left.nRows(); ++i) + // auto cmp = [](size_t i, size_t end) -> bool {} + DMatrix dmatSlice; + if (step > 0) { - left[i] *= right[i]; + for (int i = begin; i < (int)end; i += step) + { + dmatSlice.PushRowBack(m_matrix[i]); + } } - return left; -} - -DMatrix &operator/=(DMatrix &left, DMatrix const &right) -{ - IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); - IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); - for (size_t i = 0; i < left.nRows(); ++i) + else if (step < 0) { - left[i] /= right[i]; + for (int i = end - 1; i >= (int)begin; i += step) + { + dmatSlice.PushRowBack(m_matrix[i]); + } } - return left; -} - -// -------------------------------------------------------- - -DMatrix operator+(DMatrix left, DMatrix const &right) -{ - IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); - IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); - return left += right; -} - -DMatrix operator-(DMatrix left, DMatrix const &right) -{ - IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); - IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); - return left -= right; + return dmatSlice; } -DMatrix operator*(DMatrix left, DMatrix const &right) +DMatrix DMatrix::SliceCol(size_t begin, size_t end, int step) const { - IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); - IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); - return left *= right; + if (begin >= end) + { + throw std::runtime_error("operator(): " + ERROR_RANGE); + } + if (begin >= m_nCols || end > m_nCols) + { + throw std::runtime_error("operator(): " + ERROR_RANGE); + } + DMatrix dmatSlice; + if (step > 0) + { + for (int i = begin; i < (int)end; i += step) + { + dmatSlice.PushColBack(GetCol(i)); + } + } + else if (step < 0) + { + for (int i = end - 1; i >= (int)begin; i += step) + { + dmatSlice.PushColBack(GetCol(i)); + } + } + return dmatSlice; } -DMatrix operator/(DMatrix left, DMatrix const &right) +void DMatrix::grow() { - IsEqualSize(left.nRows(), right.nRows(), ERROR_ARITHMETIC); - IsEqualSize(left.nCols(), right.nCols(), ERROR_ARITHMETIC); - return left /= right; + size_t new_capacity = std::max(1, static_cast(m_capacity * 2)); + DVector *new_matrix = new DVector[new_capacity](); + std::copy(m_matrix, &m_matrix[m_nRows - 1] + 1, new_matrix); + delete[] m_matrix; + m_matrix = new_matrix; + m_capacity = new_capacity; } -// -------------------------------------------------------- - void Print(DMatrix const &matrix, std::string const &msg) { diff --git a/matrix_lib/src/dmatrix_operators.cpp b/matrix_lib/src/dmatrix_operators.cpp new file mode 100644 index 0000000..db3c565 --- /dev/null +++ b/matrix_lib/src/dmatrix_operators.cpp @@ -0,0 +1,147 @@ +#include "stdafx.h" +#include "dmatrix.h" + +extern const std::string ERROR_EMPTY; +extern const std::string ERROR_SIZE; + +extern void IsEqualSize(size_t size1, size_t size2, std::string const &msgError); + +// --------------------------------------------------- +// value *= matrix + +DMatrix &operator*=(double value, DMatrix &matrix) +{ + return matrix *= value; +} + +DMatrix &operator/=(double value, DMatrix &matrix) +{ + return matrix /= value; +} + +// --------------------------------------------------- +// value * matrix + +DMatrix operator*(double value, DMatrix matrix) +{ + return matrix *= value; +} + +DMatrix operator/(double value, DMatrix matrix) +{ + return matrix /= value; +} + +// --------------------------------------------------- +// matrix += matrix + +DMatrix &operator+=(DMatrix &left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), "operator+= :" + ERROR_SIZE); + IsEqualSize(left.nCols(), right.nCols(), "operator+= :" + ERROR_SIZE); + for (size_t i = 0; i < left.nRows(); ++i) + { + left[i] += right[i]; + } + return left; +} + +DMatrix &operator-=(DMatrix &left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), "operator-= :" + ERROR_SIZE); + IsEqualSize(left.nCols(), right.nCols(), "operator-= :" + ERROR_SIZE); + for (size_t i = 0; i < left.nRows(); ++i) + { + left[i] -= right[i]; + } + return left; +} + +DMatrix &operator*=(DMatrix &left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), "operator*= :" + ERROR_SIZE); + IsEqualSize(left.nCols(), right.nCols(), "operator*= :" + ERROR_SIZE); + for (size_t i = 0; i < left.nRows(); ++i) + { + left[i] *= right[i]; + } + return left; +} + +DMatrix &operator/=(DMatrix &left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), "operator/= :" + ERROR_SIZE); + IsEqualSize(left.nCols(), right.nCols(), "operator/= :" + ERROR_SIZE); + for (size_t i = 0; i < left.nRows(); ++i) + { + left[i] /= right[i]; + } + return left; +} + +// --------------------------------------------------- +// matrix + matrix + +DMatrix operator+(DMatrix left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), "operator+ :" + ERROR_SIZE); + IsEqualSize(left.nCols(), right.nCols(), "operator+ :" + ERROR_SIZE); + return left += right; +} + +DMatrix operator-(DMatrix left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), "operator- :" + ERROR_SIZE); + IsEqualSize(left.nCols(), right.nCols(), "operator-:" + ERROR_SIZE); + return left -= right; +} + +DMatrix operator*(DMatrix left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), "operator* :" + ERROR_SIZE); + IsEqualSize(left.nCols(), right.nCols(), "operator* :" + ERROR_SIZE); + return left *= right; +} + +DMatrix operator/(DMatrix left, DMatrix const &right) +{ + IsEqualSize(left.nRows(), right.nRows(), "operator/ :" + ERROR_SIZE); + IsEqualSize(left.nCols(), right.nCols(), "operator/ :" + ERROR_SIZE); + return left /= right; +} + +// --------------------------------------------------- +// matrix *= value + +DMatrix &operator*=(DMatrix &matrix, double value) +{ + for (size_t i = 0; i < matrix.nRows(); ++i) + { + matrix[i] *= value; + } + return matrix; +} + +DMatrix &operator/=(DMatrix &matrix, double value) +{ + for (size_t i = 0; i < matrix.nRows(); ++i) + { + matrix[i] /= value; + } + return matrix; +} + +// --------------------------------------------------- +// matrix * value + +DMatrix operator*(DMatrix matrix, double value) +{ + return matrix *= value; +} + +DMatrix operator/(DMatrix matrix, double value) +{ + return matrix /= value; +} + +// -------------------------------------------------------- \ No newline at end of file diff --git a/matrix_lib/src/dvector.cpp b/matrix_lib/src/dvector.cpp index e7fcff3..1d760f2 100644 --- a/matrix_lib/src/dvector.cpp +++ b/matrix_lib/src/dvector.cpp @@ -4,18 +4,11 @@ #include "dvector.h" #include "dmatrix.h" -// static + const = const -const std::string ERROR_ARITHMETIC = "Arithmetic operations on vectors of different size"; -const std::string ERROR_RANGE = "Index out of range"; -const std::string ERROR_EMPTY = "DVector is empty"; +extern const std::string ERROR_SIZE; +extern const std::string ERROR_RANGE; +extern const std::string ERROR_EMPTY; -static void IsEqualSize(size_t size1, size_t size2, std::string const &msgError = "Exception") -{ - if (size1 != size2) - { - throw std::runtime_error(msgError); - } -} +extern void IsEqualSize(size_t size1, size_t size2, std::string const &msgError); void Print(DVector const &dvector, std::string const &message) { @@ -103,7 +96,7 @@ double const &DVector::operator[](size_t index) const { if (index > m_size - 1) { - throw std::runtime_error(ERROR_RANGE); + throw std::runtime_error("operator[] : " + ERROR_RANGE); } return m_array[index]; } @@ -112,7 +105,7 @@ double &DVector::operator[](size_t index) { if (index > m_size - 1) { - throw std::runtime_error(ERROR_RANGE); + throw std::runtime_error("operator[] : " + ERROR_RANGE); } return m_array[index]; } @@ -135,7 +128,7 @@ void DVector::PopBack() { if (Empty()) { - throw std::runtime_error("PopBack(): " + ERROR_EMPTY); + throw std::runtime_error("PopBack: " + ERROR_EMPTY); } --m_size; } @@ -165,7 +158,7 @@ double DVector::Front() const { if (Empty()) { - throw std::runtime_error("From(): " + ERROR_EMPTY); + throw std::runtime_error("From: " + ERROR_EMPTY); } return m_array[0]; } @@ -174,7 +167,7 @@ double DVector::Back() const { if (Empty()) { - throw std::runtime_error("Back(): " + ERROR_EMPTY); + throw std::runtime_error("Back: " + ERROR_EMPTY); } return m_array[m_size - 1]; } @@ -231,105 +224,28 @@ double *DVector::Erase(double *it_value) } -DVector &operator+=(DVector &left, DVector const &right) -{ - IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); - for (size_t i = 0; i < left.Size(); ++i) - { - left[i] += right[i]; - } - return left; -} - -DVector &operator-=(DVector &left, DVector const &right) -{ - IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); - for (size_t i = 0; i < left.Size(); ++i) - { - left[i] -= right[i]; - } - return left; -} - -DVector &operator*=(DVector &left, DVector const &right) -{ - IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); - for (size_t i = 0; i < left.Size(); ++i) - { - left[i] *= right[i]; - } - return left; -} - -DVector &operator/=(DVector &left, DVector const &right) -{ - IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); - for (size_t i = 0; i < left.Size(); ++i) - { - left[i] /= right[i]; - } - return left; -} - -// ------------------------------------------------------------------------- - -DVector &operator*=(DVector &left, double value) +// подразуемевается что вектор-строка умножается на матрицу +// результат - DVector +DVector DVector::Dot(DMatrix const &matrix) const { - for (size_t i = 0; i < left.Size(); ++i) - { - left[i] *= value; - } - return left; -} + IsEqualSize(m_size, matrix.nRows(), ERROR_SIZE); -DVector &operator/=(DVector &left, double value) -{ - for (size_t i = 0; i < left.Size(); ++i) + DVector dvecRes(matrix.nCols()); + for (size_t i = 0; i < matrix.nCols(); ++i) { - left[i] /= value; + double elem_i_j = 0; + for (size_t j = 0; j < m_size; ++j) + { + elem_i_j += matrix[j][i] * m_array[j]; + } + dvecRes[i] = elem_i_j; } - return left; -} - -DVector operator*(DVector left, double value) -{ - return left *= value; -} - -DVector operator/(DVector left, double value) -{ - return left /= value; -} - -// ------------------------------------------------------------------------- - -DVector operator+(DVector left, DVector const &right) -{ - IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); - return left += right; -} - -DVector operator-(DVector left, DVector const &right) -{ - IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); - return left -= right; -} - -DVector operator*(DVector left, DVector const &right) -{ - IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); - return left *= right; -} - -DVector operator/(DVector left, DVector const &right) -{ - IsEqualSize(left.Size(), right.Size(), ERROR_ARITHMETIC); - return left /= right; + return dvecRes; } double DVector::Dot(DVector const &other) const { - IsEqualSize(m_size, other.Size(), ERROR_ARITHMETIC); + IsEqualSize(m_size, other.Size(), "Dot:" + ERROR_SIZE); double dotProduct = 0; for (size_t i = 0; i < m_size; ++i) { @@ -338,23 +254,32 @@ double DVector::Dot(DVector const &other) const return dotProduct; } -// подразуемевается что вектор-строка умножается на матрицу -// результат - DVector -DVector DVector::Dot(DMatrix const &matrix) const +DVector DVector::operator()(size_t begin, size_t end, int step) const { - IsEqualSize(m_size, matrix.nRows(), ERROR_ARITHMETIC); - - DVector dvecRes(matrix.nCols()); - for (size_t i = 0; i < matrix.nCols(); ++i) + if (begin >= end) { - double elem_i_j = 0; - for (size_t j = 0; j < m_size; ++j) + throw std::runtime_error("operator(): " + ERROR_RANGE); + } + if (begin >= m_size || end > m_size) + { + throw std::runtime_error("operator(): " + ERROR_RANGE); + } + DVector dvecSlice; + if (step > 0) + { + for (int i = begin; i < (int)end; i += step) { - elem_i_j += matrix[j][i] * m_array[j]; + dvecSlice.PushBack(m_array[i]); } - dvecRes[i] = elem_i_j; } - return dvecRes; + else if (step < 0) + { + for (int i = end - 1; i >= (int)begin; i += step) + { + dvecSlice.PushBack(m_array[i]); + } + } + return dvecSlice; } void DVector::grow() diff --git a/matrix_lib/src/dvector_operators.cpp b/matrix_lib/src/dvector_operators.cpp new file mode 100644 index 0000000..a4263b1 --- /dev/null +++ b/matrix_lib/src/dvector_operators.cpp @@ -0,0 +1,114 @@ +#include + +#include "stdafx.h" +#include "dvector.h" +#include "dmatrix.h" + +extern const std::string ERROR_SIZE; + +extern void IsEqualSize(size_t size1, size_t size2, std::string const &msgError); + +// --------------------------------------------------- +// vector += vector + +DVector &operator+=(DVector &left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), "operator+= :" + ERROR_SIZE); + for (size_t i = 0; i < left.Size(); ++i) + { + left[i] += right[i]; + } + return left; +} + +DVector &operator-=(DVector &left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), "operator-= :" + ERROR_SIZE); + for (size_t i = 0; i < left.Size(); ++i) + { + left[i] -= right[i]; + } + return left; +} + +DVector &operator*=(DVector &left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), "operator*= :" + ERROR_SIZE); + for (size_t i = 0; i < left.Size(); ++i) + { + left[i] *= right[i]; + } + return left; +} + +DVector &operator/=(DVector &left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), "operator/= :" + ERROR_SIZE); + for (size_t i = 0; i < left.Size(); ++i) + { + left[i] /= right[i]; + } + return left; +} + +// --------------------------------------------------- +// vector + vector + +DVector operator+(DVector left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), "operator+ :" + ERROR_SIZE); + return left += right; +} + +DVector operator-(DVector left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), "operator- :" + ERROR_SIZE); + return left -= right; +} + +DVector operator*(DVector left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), "operator* :" + ERROR_SIZE); + return left *= right; +} + +DVector operator/(DVector left, DVector const &right) +{ + IsEqualSize(left.Size(), right.Size(), "operator/ :" + ERROR_SIZE); + return left /= right; +} + + +// --------------------------------------------------- +// vector *= value + +DVector &operator*=(DVector &left, double value) +{ + for (size_t i = 0; i < left.Size(); ++i) + { + left[i] *= value; + } + return left; +} + +DVector &operator/=(DVector &left, double value) +{ + for (size_t i = 0; i < left.Size(); ++i) + { + left[i] /= value; + } + return left; +} + +// --------------------------------------------------- +// vector * value + +DVector operator*(DVector left, double value) +{ + return left *= value; +} + +DVector operator/(DVector left, double value) +{ + return left /= value; +} diff --git a/matrix_lib/tests/test_matrix.cpp b/matrix_lib/tests/test_matrix.cpp index ae59a73..791e243 100644 --- a/matrix_lib/tests/test_matrix.cpp +++ b/matrix_lib/tests/test_matrix.cpp @@ -2,13 +2,15 @@ #include "dmatrix.h" -bool CheckMatrix(DMatrix const &matrix, std::initializer_list> const &init_list) +const double EPS = 0.000001; + +bool CompareMatrices(DMatrix const &matrix, std::initializer_list> const &init_list) { for (size_t i = 0; i < matrix.nRows(); ++i) { for (size_t j = 0; j < matrix.nCols(); ++j) { - if (matrix[i][j] - *((init_list.begin() + i)->begin() + j) > 0.000001) + if (matrix[i][j] - *((init_list.begin() + i)->begin() + j) > EPS) { return false; } @@ -17,11 +19,11 @@ bool CheckMatrix(DMatrix const &matrix, std::initializer_list const &init_list) +bool CompareVectors(DVector const &dvec, std::initializer_list const &init_list) { for (size_t i = 0; i < dvec.Size(); ++i) { - if (dvec[i] - *(init_list.begin() + i) > 0.000001) + if (dvec[i] - *(init_list.begin() + i) > EPS) { return false; } @@ -71,14 +73,14 @@ TEST(TestCreateDMatrix, TestConstructorsSpecifyRowOrCol) EXPECT_EQ(dmat.nRows(), 1); EXPECT_EQ(dmat.nCols(), 4); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {2, 4, 6, 8} })); dmat = DMatrix(DVector{2, 4, 6, 8}, ORIENT::COL); EXPECT_EQ(dmat.nRows(), 4); EXPECT_EQ(dmat.nCols(), 1); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {2}, {4}, {6}, @@ -86,6 +88,18 @@ TEST(TestCreateDMatrix, TestConstructorsSpecifyRowOrCol) })); } +TEST(TestCreateDMatrix, TestConstructorsTemplate) +{ + DMatrix dmat = DMatrix::Create<2, 3>(3); + EXPECT_EQ(dmat.nRows(), 2); + EXPECT_EQ(dmat.nCols(), 3); + + EXPECT_TRUE(CompareMatrices(dmat, { + {3, 3, 3}, + {3, 3, 3} + })); +} + TEST(TestCreateDMatrix, TestOperatorAssign) { DMatrix dmat1{ @@ -130,7 +144,7 @@ TEST(TestFunctionalityDMatrix, TestPushPopRow) EXPECT_THROW(dmat.PushRowBack(dvec2), std::runtime_error); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {1, 2, 3}, {4, 5, 6} })); @@ -209,7 +223,7 @@ TEST(TestFunctionalityDMatrix, TestPushPopMix) dmat.PushColBack({7, 7}); dmat.PushRowBack({8, 8, 8, 100}); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {1, 2, 3, 7}, {4, 5, 6, 7}, {8, 8, 8, 100}, @@ -235,7 +249,7 @@ TEST(TestFunctionalityDMatrix, TestPushPopMix) dmat = {{1, 2, 3, 4, 5, 6, 7}}; dmat.PushColBack({8}); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {1, 2, 3, 4, 5, 6, 7, 8} })); @@ -322,7 +336,7 @@ TEST(TestFunctionalityDMatrix, TestArithmeticOperators) EXPECT_THROW(dmat3 -= dmatErr2, std::runtime_error); EXPECT_THROW(dmat3 / dmatErr3, std::runtime_error); - EXPECT_TRUE(CheckMatrix(dmat3, { + EXPECT_TRUE(CompareMatrices(dmat3, { {13, 16, 19}, {26, 29, 32} })); @@ -346,7 +360,7 @@ TEST(TestFunctionalityDMatrix, TestDotProductOfMatrices) EXPECT_EQ(dmatRes.nRows(), 2); EXPECT_EQ(dmatRes.nCols(), 2); - EXPECT_TRUE(CheckMatrix(dmatRes, { {28, 34}, {64, 79} })); + EXPECT_TRUE(CompareMatrices(dmatRes, { {28, 34}, {64, 79} })); } @@ -362,13 +376,13 @@ TEST(TestFunctionalityDMatrix, TestDotProductBetweenMatrixAndVector) DVector dvec1{1, 2, 3}; DVector dvecErr{1, 2, 3, 4}; - EXPECT_TRUE(CheckVector(dmat1.Dot(dvec1), { 14, 32 })); + EXPECT_TRUE(CompareVectors(dmat1.Dot(dvec1), { 14, 32 })); EXPECT_THROW(dmat1.Dot(dvecErr), std::runtime_error); // vector * matrix DVector dvec2{1, 2}; - EXPECT_TRUE(CheckVector(dvec2.Dot(dmat1), { 9, 12, 15 })); + EXPECT_TRUE(CompareVectors(dvec2.Dot(dmat1), { 9, 12, 15 })); DMatrix dmatErr{ {1, 2}, @@ -386,21 +400,21 @@ TEST(TestFunctionalityDMatrix, TestAddSubVectorAndNum) }; dmat.AddNum(1); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {2, 3, 4}, {5, 6, 7} })); DVector dvec1{10, 15}; dmat.AddVec(dvec1, ORIENT::COL); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {12, 13, 14}, {20, 21, 22} })); DVector dvec2{10, 10, 0}; dmat.SubVec(dvec2, ORIENT::ROW); // but ORIENT::ROW by default - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {2, 3, 14}, {10, 11, 22} })); @@ -418,7 +432,7 @@ TEST(TestFunctionalityDMatrix, TestTransponse) }; DMatrix dmatT = dmat.T(); - EXPECT_TRUE(CheckMatrix(dmatT, { + EXPECT_TRUE(CompareMatrices(dmatT, { {1, 4, 7}, {2, 5, 8}, {3, 6, 9} @@ -436,12 +450,12 @@ TEST(TestFunctionalityDMatrix, TestEraseByIndexRow) {7, 8, 9} }; dmat.EraseByIndex(0); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {4, 5, 6}, {7, 8, 9} })); dmat.EraseByIndex(1); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {4, 5, 6} })); @@ -467,7 +481,7 @@ TEST(TestFunctionalityDMatrix, TestEraseByIndexCol) }; dmat.EraseByIndex(1, ORIENT::COL); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {1, 3}, {4, 6}, {7, 9} @@ -477,14 +491,14 @@ TEST(TestFunctionalityDMatrix, TestEraseByIndexCol) EXPECT_EQ(dmat.nCols(), 2); dmat.EraseByIndex(0, ORIENT::COL); - EXPECT_TRUE(CheckMatrix(dmat, { + EXPECT_TRUE(CompareMatrices(dmat, { {3}, {6}, {9} })); dmat.EraseByIndex(0, ORIENT::COL); - EXPECT_TRUE(CheckMatrix(dmat, {{}})); + EXPECT_TRUE(CompareMatrices(dmat, {{}})); EXPECT_THROW(dmat.EraseByIndex(0, ORIENT::COL), std::runtime_error); EXPECT_THROW(dmat.EraseByIndex(200, ORIENT::COL), std::runtime_error); @@ -527,7 +541,7 @@ TEST(TestFunctionalityDMatrix, TestInvertibleMatrix) EXPECT_EQ(dmatInv.nRows(), 3); EXPECT_EQ(dmatInv.nCols(), 3); - EXPECT_TRUE(CheckMatrix(dmatInv, { + EXPECT_TRUE(CompareMatrices(dmatInv, { {0, 2, -1}, {-1, 5, -3}, {-1, 8, -5} @@ -542,7 +556,7 @@ TEST(TestFunctionalityDMatrix, TestInvertibleMatrix) dmatInv = dmat2.Inv(); - EXPECT_TRUE(CheckMatrix(dmatInv, { + EXPECT_TRUE(CompareMatrices(dmatInv, { {11./6, 1./3, -1./2, -2./3}, {1./3, -1./3, 0, 0}, {-5./6, 0, 1./2, 1./3}, @@ -562,9 +576,158 @@ TEST(TestFunctionalityDMatrix, TestInvertibleMatrix) EXPECT_THROW(dmatErr1.Inv(), std::runtime_error); EXPECT_TRUE(dmatErr2.Inv().Empty()); +} + +TEST(TestFunctionalityDMatrix, TestSliceOperatorRow) +{ + DMatrix dmat = { + {1, 2, 3, 4, 5}, + {6, 7, 8, 9, 10}, + {11, 12, 13, 14, 15}, + {16, 17, 18, 19, 20}, + {21, 22, 23, 24, 25} + }; + + DMatrix dmatSlice1 = dmat(1, 3); + EXPECT_TRUE(CompareMatrices(dmatSlice1, { + {6, 7, 8, 9, 10}, + {11, 12, 13, 14, 15} + })); + + DMatrix dmatSlice2 = dmat(0, dmat.nRows()); + + EXPECT_TRUE(CompareMatrices(dmatSlice2, { + {1, 2, 3, 4, 5}, + {6, 7, 8, 9, 10}, + {11, 12, 13, 14, 15}, + {16, 17, 18, 19, 20}, + {21, 22, 23, 24, 25} + })); + + DMatrix dmatSlice3 = dmat(0, dmat.nRows(), 2); + + EXPECT_TRUE(CompareMatrices(dmatSlice3, { + {1, 2, 3, 4, 5}, + {11, 12, 13, 14, 15}, + {21, 22, 23, 24, 25} + })); + + DMatrix dmatSlice4 = dmat(0, dmat.nRows(), -2); + + EXPECT_TRUE(CompareMatrices(dmatSlice4, { + {21, 22, 23, 24, 25}, + {11, 12, 13, 14, 15}, + {1, 2, 3, 4, 5} + })); + + EXPECT_THROW(dmat(4, 1), std::runtime_error); + EXPECT_THROW(dmat(2, 2), std::runtime_error); + EXPECT_THROW(dmat(100, 103), std::runtime_error); + EXPECT_THROW(dmat(0, 100), std::runtime_error); + + DMatrix dmatSlice5 = dmat(0, 4, 0); + EXPECT_TRUE(CompareMatrices(dmatSlice5, { {} })); +} + +TEST(TestFunctionalityDMatrix, TestSliceOperatorCol) +{ + DMatrix dmat = { + {1, 2, 3, 4, 5}, + {6, 7, 8, 9, 10}, + {11, 12, 13, 14, 15}, + {16, 17, 18, 19, 20}, + {21, 22, 23, 24, 25} + }; + + DMatrix dmatSlice1 = dmat(1, 3, 1, COL); + EXPECT_TRUE(CompareMatrices(dmatSlice1, { + {2, 3 }, + {7, 8 }, + {12, 13 }, + {17, 18 }, + {22, 23 } + })); + + DMatrix dmatSlice2 = dmat(1, 4, 2, COL); + + EXPECT_TRUE(CompareMatrices(dmatSlice2, { + {2, 4 }, + {7, 9 }, + {12, 14 }, + {17, 19 }, + {22, 24 } + })); + + DMatrix dmatSlice3 = dmat(0, dmat.nCols(), -1, COL); + + EXPECT_TRUE(CompareMatrices(dmatSlice3, { + {5, 4, 3, 2, 1}, + {10, 9, 8, 7, 6}, + {15, 14, 13, 12, 11}, + {20, 19, 18, 17, 16}, + {25, 24, 23, 22, 21} + })); + + DMatrix dmatSlice4 = dmat(4, dmat.nCols(), 1, COL); + + EXPECT_TRUE(CompareMatrices(dmatSlice4, { + {5}, + {10}, + {15}, + {20}, + {25} + })); +} + +TEST(TestFunctionalityDMatrix, TestSliceOperatorRowColMix) +{ + DMatrix dmat = { + {1, 2, 3, 4, 5}, + {6, 7, 8, 9, 10}, + {11, 12, 13, 14, 15}, + {16, 17, 18, 19, 20}, + {21, 22, 23, 24, 25} + }; + + DMatrix dmatSlice1 = dmat(0, 3)(1, 3); + EXPECT_TRUE(CompareMatrices(dmatSlice1, { + {6, 7, 8, 9, 10}, + {11, 12, 13, 14, 15} + })); + + // ROW = 0, COL = 1 + DMatrix dmatSlice2 = dmat(0, 4, 1, 0)(1, 3, 1, 1); + EXPECT_TRUE(CompareMatrices(dmatSlice2, { + {2, 3}, + {7, 8}, + {12, 13}, + {17, 18} + })); + DMatrix dmatSlice3 = dmat(1, 2, 1, COL)(3, 4); + EXPECT_TRUE(CompareMatrices(dmatSlice2, { + {17} + })); } +TEST(TestFunctionalityDMatrix, TestSliceCallMethod) +{ + DMatrix dmat = { + {1, 2, 3, 4, 5}, + {6, 7, 8, 9, 10}, + {11, 12, 13, 14, 15}, + {16, 17, 18, 19, 20}, + {21, 22, 23, 24, 25} + }; + DMatrix dmatSlice1 = dmat.SliceRow(0, 4).SliceCol(1, 5, 2); + + EXPECT_TRUE(CompareMatrices(dmatSlice1, { + {2, 4 }, + {7, 9 }, + {12, 14}, + {17, 19} + })); +} diff --git a/matrix_lib/tests/test_vector.cpp b/matrix_lib/tests/test_vector.cpp index 2e60cc4..4c6d67d 100644 --- a/matrix_lib/tests/test_vector.cpp +++ b/matrix_lib/tests/test_vector.cpp @@ -2,17 +2,7 @@ #include "dvector.h" -static bool CheckVector(DVector const &dvec, std::initializer_list const &init_list) -{ - for (size_t i = 0; i < dvec.Size(); ++i) - { - if (dvec[i] != *(init_list.begin() + i)) - { - return false; - } - } - return true; -} +extern bool CompareVectors(DVector const &dvec, std::initializer_list const &init_list); TEST(TestCreateDVector, TestDefaultConstructor) { @@ -22,10 +12,8 @@ TEST(TestCreateDVector, TestDefaultConstructor) dvec1.PushBack(3); dvec1.PushBack(4); EXPECT_EQ(dvec1.Size(), 4); - EXPECT_EQ(dvec1.Capacity(), 4); - EXPECT_EQ(dvec1[0], 1); - EXPECT_EQ(dvec1[1], 2); - EXPECT_EQ(dvec1[3], 4); + EXPECT_EQ(dvec1.Capacity(), 4); + EXPECT_TRUE(CompareVectors(dvec1, {1, 2, 3, 4})); } TEST(TestCreateDVector, TestConstructorInitializerList) @@ -33,9 +21,7 @@ TEST(TestCreateDVector, TestConstructorInitializerList) DVector dvec2{5, 6, 7, 8, 9}; EXPECT_EQ(dvec2.Size(), 5); EXPECT_EQ(dvec2.Capacity(), 5); - EXPECT_EQ(dvec2[0], 5); - EXPECT_EQ(dvec2[1], 6); - EXPECT_EQ(dvec2[4], 9); + EXPECT_TRUE(CompareVectors(dvec2, {5, 6, 7, 8, 9})); } TEST(TestCreateDVector, TestConstructorInputSizeAndFillValue) @@ -43,9 +29,7 @@ TEST(TestCreateDVector, TestConstructorInputSizeAndFillValue) DVector dvec3(10, 99); EXPECT_EQ(dvec3.Size(), 10); EXPECT_EQ(dvec3.Capacity(), 10); - EXPECT_EQ(dvec3[0], 99); - EXPECT_EQ(dvec3[1], 99); - EXPECT_EQ(dvec3[9], 99); + EXPECT_TRUE(CompareVectors(dvec3, {99, 99, 99, 99, 99, 99, 99, 99, 99, 99})); } TEST(TestCreateDVector, TestCopyConstructor) @@ -72,6 +56,8 @@ TEST(TestCreateDVector, TestConstructorPointersBeginEnd) DVector dvec1(dvec.CBegin(), dvec.CEnd()); EXPECT_NE(dvec1.CBegin(), dvec.CBegin()); EXPECT_EQ(dvec1.Size(), dvec.Size()); + + EXPECT_TRUE(CompareVectors(dvec1, {1, 2, 3, 4})); } TEST(TestCreateDVector, TestImplicitConstructor) @@ -160,10 +146,9 @@ TEST(TestFunctionalityDVector, TestArithmeticOperators) DVector dvec1{1, 2, 3}; DVector dvec2{5, 6, 7}; (dvec1 *= dvec2) += dvec1; - EXPECT_EQ(dvec1[0], 10); - EXPECT_EQ(dvec1[1], 24); - EXPECT_EQ(dvec1[2], 42); + EXPECT_TRUE(CompareVectors(dvec1, {10, 24, 42})); + DVector dvec3{2, 4, 8}; DVector dvec4{4, 5, 6}; @@ -177,7 +162,7 @@ TEST(TestFunctionalityDVector, TestArithmeticOperators) { 17; 42; 100 } */ - dvec5 *= 2; + dvec5 *= 2; EXPECT_EQ(dvec5[0], 17 * 2); EXPECT_EQ(dvec5[1], 42 * 2); @@ -193,8 +178,24 @@ TEST(TestFunctionalityDVector, TestAddSubNum) { DVector dvec{1, 2, 3}; dvec.AddNum(2); - EXPECT_TRUE(CheckVector(dvec, {3, 4, 5})); + EXPECT_TRUE(CompareVectors(dvec, {3, 4, 5})); dvec.SubNum(3); - EXPECT_TRUE(CheckVector(dvec, {0, 1, 2})); + EXPECT_TRUE(CompareVectors(dvec, {0, 1, 2})); +} + +TEST(TestFunctionalityDVector, TestSliceOperator) +{ + DVector dvec{1, 2, 3, 4, 5, 6, 7}; + + EXPECT_TRUE(CompareVectors(dvec(0, 5), {1, 2, 3, 4, 5})); + EXPECT_TRUE(CompareVectors(dvec(0, dvec.Size(), -1), {7, 6, 5, 4, 3, 2, 1})); + + EXPECT_TRUE(CompareVectors(dvec(3, 4), {4})); + + EXPECT_THROW(dvec(4, 4), std::runtime_error); + EXPECT_THROW(dvec(5, 4), std::runtime_error); + EXPECT_THROW(dvec(1, 400), std::runtime_error); + EXPECT_THROW(dvec(20, 22), std::runtime_error); + } From 87e26930a377caf9a061b5b40cf379fe49bb2b65 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Mon, 17 Oct 2022 20:54:08 +0300 Subject: [PATCH 10/17] fix bag in tests --- matrix_lib/tests/test_matrix.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/matrix_lib/tests/test_matrix.cpp b/matrix_lib/tests/test_matrix.cpp index 791e243..036cbca 100644 --- a/matrix_lib/tests/test_matrix.cpp +++ b/matrix_lib/tests/test_matrix.cpp @@ -1,4 +1,5 @@ #include +#include #include "dmatrix.h" @@ -10,7 +11,7 @@ bool CompareMatrices(DMatrix const &matrix, std::initializer_listbegin() + j) > EPS) + if (std::abs(matrix[i][j] - *((init_list.begin() + i)->begin() + j)) > EPS) { return false; } @@ -23,7 +24,7 @@ bool CompareVectors(DVector const &dvec, std::initializer_list const &in { for (size_t i = 0; i < dvec.Size(); ++i) { - if (dvec[i] - *(init_list.begin() + i) > EPS) + if (std::abs(dvec[i] - *(init_list.begin() + i)) > EPS) { return false; } @@ -706,7 +707,7 @@ TEST(TestFunctionalityDMatrix, TestSliceOperatorRowColMix) })); DMatrix dmatSlice3 = dmat(1, 2, 1, COL)(3, 4); - EXPECT_TRUE(CompareMatrices(dmatSlice2, { + EXPECT_TRUE(CompareMatrices(dmatSlice3, { {17} })); } From 2348a0fed68dcd2ed9e4a7e38d0a5824f9edabbb Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Wed, 19 Oct 2022 00:25:11 +0300 Subject: [PATCH 11/17] fix lcov in CMakeLists.txt - tests --- .github/workflows/main.yml | 11 ++-- main.cpp | 13 +---- matrix_lib/CMakeLists.txt | 1 - matrix_lib/include/dmatrix.h | 25 +++++---- matrix_lib/src/dmatrix.cpp | 92 ++++++++++++++++++++++++++++---- matrix_lib/src/dvector.cpp | 51 ++++++++++++++++-- matrix_lib/tests/CMakeLists.txt | 4 -- matrix_lib/tests/test_matrix.cpp | 7 +++ 8 files changed, 159 insertions(+), 45 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ad5762f..f80586e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,6 @@ jobs: build: runs-on: ubuntu-latest container: leshiy1295/gcc_linters_valgrind_cmake_gtest - # needs: [check] steps: - uses: actions/checkout@v2 - run: make build @@ -20,14 +19,16 @@ jobs: test: runs-on: ubuntu-latest container: leshiy1295/gcc_linters_valgrind_cmake_gtest - # needs: [build] + needs: [build] steps: - uses: actions/checkout@v2 - name: install lcov run: apt-get install lcov -y - - run: make build TEST_OPT=ON - - run: make run - - run: make test + - name: Build, run and test + run: | + make build TEST_OPT=ON + make run + make test - name: Test coverage run: | cd build && lcov -t "tests_matrix" -o coverage.info -c -d ${LIB_NAME}/CMakeFiles diff --git a/main.cpp b/main.cpp index 54e26e1..4d5ea39 100644 --- a/main.cpp +++ b/main.cpp @@ -3,18 +3,7 @@ #include "dvector.h" #include "dmatrix.h" -// static IsEqualSize -// мб разделить реализацию на разные файлы -// создание матрицы из вектора с указание строки или столбца - int main() { - DMatrix dmat1(3, 10, 4); - DMatrix dmat2{ - {1, 2, 3}, - {4, 5, 6} - }; - - Print(dmat1); - Print(dmat2); + std::cout << "Hello!" << std::endl; } diff --git a/matrix_lib/CMakeLists.txt b/matrix_lib/CMakeLists.txt index 00168b3..2faa6d6 100644 --- a/matrix_lib/CMakeLists.txt +++ b/matrix_lib/CMakeLists.txt @@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.0.0) project(matrix_lib) set(CMAKE_CXX_STANDARD 17) -# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror -fPIC -O0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -O0") if(TEST_OPT) diff --git a/matrix_lib/include/dmatrix.h b/matrix_lib/include/dmatrix.h index fa84444..d5f2b43 100644 --- a/matrix_lib/include/dmatrix.h +++ b/matrix_lib/include/dmatrix.h @@ -5,6 +5,7 @@ enum class ORIENT { ROW = 0, COL }; enum SLICE { ROW = 0, COL }; +// Matrix of doubles number class DMatrix { private: @@ -25,11 +26,9 @@ class DMatrix DMatrix &operator=(DMatrix other); ~DMatrix(); - template - static DMatrix Create(double fill_value = 0) - { - return DMatrix(rows, cols, fill_value); - } + /* ****** Задание размера через шаблон *******/ + template + static DMatrix Create(double fill_value = 0); public: void Clear(); @@ -78,9 +77,7 @@ class DMatrix DVector &operator[](size_t index); /* - Slicing как в NumPy C++ - matrix({1, 4}, {2, 5}) - нельзя отдельно по столбцам - + Пояснение: enum SLICE {ROW = 0, COL}, чтобы 1. не писать класс, если в параметрах ROW / COL 2. кастилось к enum SLICE, если в параметрах 0 / 1 @@ -123,4 +120,14 @@ DMatrix operator-(DMatrix left, DMatrix const &right); DMatrix operator/(DMatrix left, DMatrix const &right); DMatrix operator*(DMatrix left, DMatrix const &right); -void Print(DMatrix const &matrix, std::string const &msg = std::string{}); \ No newline at end of file +void Print(DMatrix const &matrix, std::string const &msg = std::string{}); + +template +DMatrix DMatrix::Create(double fill_value) +{ + if ((rows == 0) ^ (cols == 0)) + { + throw std::runtime_error("Creation is impossible"); + } + return DMatrix(rows, cols, fill_value); +} \ No newline at end of file diff --git a/matrix_lib/src/dmatrix.cpp b/matrix_lib/src/dmatrix.cpp index 326bced..9120b85 100644 --- a/matrix_lib/src/dmatrix.cpp +++ b/matrix_lib/src/dmatrix.cpp @@ -20,7 +20,15 @@ void IsEqualSize(size_t size1, size_t size2, std::string const &msgError = "Exce DMatrix::DMatrix(size_t nRows, size_t nCols, double fill_value) : m_nRows(nRows), m_nCols(nCols), m_capacity(nRows) { // можно ли указать конкретный конструктор для каждого элемента дин. массива? - m_matrix = new DVector[m_nRows](); + try + { + m_matrix = new DVector[m_nRows](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } for (size_t i = 0; i < m_nRows; ++i) { m_matrix[i] = DVector(m_nCols, fill_value); @@ -37,7 +45,15 @@ DMatrix::DMatrix(std::initializer_list> const &ini { throw std::runtime_error("DMatrix: " + ERROR_LENGTH); } - m_matrix = new DVector[m_nRows](); + try + { + m_matrix = new DVector[m_nRows](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } int i = 0; for (auto row = init_list.begin(); row < init_list.end(); ++row) { @@ -48,7 +64,15 @@ DMatrix::DMatrix(std::initializer_list> const &ini DMatrix::DMatrix(DMatrix const &other) : m_nRows(other.nRows()), m_nCols(other.nCols()), m_capacity(other.nRows()) { - m_matrix = new DVector[other.nRows()](); + try + { + m_matrix = new DVector[other.nRows()](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } for (size_t i = 0; i < other.m_nRows; ++i) { m_matrix[i] = DVector(other[i].CBegin(), other[i].CEnd()); @@ -100,14 +124,30 @@ DMatrix::DMatrix(DVector const &dvec, ORIENT orientation) { if (orientation == ORIENT::ROW) { - m_matrix = new DVector[1]{ DVector(dvec) }; + try + { + m_matrix = new DVector[1]{ DVector(dvec) }; + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } m_nRows = 1; m_nCols = dvec.Size(); m_capacity = m_nRows; } else { - m_matrix = new DVector[dvec.Size()](); + try + { + m_matrix = new DVector[dvec.Size()](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } for (size_t i = 0; i < dvec.Size(); ++i) { m_matrix[i] = DVector(1, dvec[i]); @@ -218,7 +258,15 @@ void DMatrix::PushColBack(DVector const &dvec) } if (m_nRows == 0) { - m_matrix = new DVector[dvec.Size()](); + try + { + m_matrix = new DVector[dvec.Size()](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } m_capacity = dvec.Size(); } m_nRows = dvec.Size(); @@ -237,7 +285,15 @@ void DMatrix::PushColBack(std::initializer_list const &init_list) } if (m_nRows == 0) { - m_matrix = new DVector[init_list.size()](); + try + { + m_matrix = new DVector[init_list.size()](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } m_capacity = init_list.size(); } m_nRows = init_list.size(); @@ -428,7 +484,16 @@ double DMatrix::Det() const else { double res = 0; - DMatrix *dmats = new DMatrix[m_nCols](); + DMatrix *dmats = nullptr; + try + { + dmats = new DMatrix[m_nCols](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } // определитель матрицы через разложение по первой строке for (size_t i = 0; i < m_nCols; ++i) { @@ -588,7 +653,16 @@ DMatrix DMatrix::SliceCol(size_t begin, size_t end, int step) const void DMatrix::grow() { size_t new_capacity = std::max(1, static_cast(m_capacity * 2)); - DVector *new_matrix = new DVector[new_capacity](); + DVector *new_matrix = nullptr; + try + { + new_matrix = new DVector[new_capacity](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } std::copy(m_matrix, &m_matrix[m_nRows - 1] + 1, new_matrix); delete[] m_matrix; m_matrix = new_matrix; diff --git a/matrix_lib/src/dvector.cpp b/matrix_lib/src/dvector.cpp index 1d760f2..38a2dfc 100644 --- a/matrix_lib/src/dvector.cpp +++ b/matrix_lib/src/dvector.cpp @@ -25,7 +25,15 @@ void Print(DVector const &dvector, std::string const &message) DVector::DVector(size_t size, double fill_value) : m_size(size), m_capacity(size) { - m_array = new double[m_capacity](); + try + { + m_array = new double[m_capacity](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } if (fill_value) { Fill(fill_value); @@ -34,7 +42,15 @@ DVector::DVector(size_t size, double fill_value) : m_size(size), m_capacity(size DVector::DVector(std::initializer_list const &init_list) : m_size(init_list.size()), m_capacity(init_list.size()) { - m_array = new double[init_list.size()](); + try + { + m_array = new double[init_list.size()](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } std::copy(init_list.begin(), init_list.end(), m_array); } @@ -44,7 +60,15 @@ DVector::DVector(DVector const &other) { delete[] m_array; } - m_array = new double[other.m_capacity](); + try + { + m_array = new double[other.m_capacity](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } m_capacity = other.m_capacity; m_size = other.m_size; std::copy(other.m_array, &other.m_array[other.m_size - 1] + 1, m_array); @@ -58,7 +82,15 @@ DVector::DVector(DVector &&other) : m_array(nullptr), m_capacity(0), m_size(0) DVector::DVector(const double *begin, const double *end) { ptrdiff_t length = std::distance(begin, end); - m_array = new double[length](); + try + { + m_array = new double[length](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } m_size = m_capacity = length; std::copy(begin, end, m_array); } @@ -285,7 +317,16 @@ DVector DVector::operator()(size_t begin, size_t end, int step) const void DVector::grow() { size_t new_capacity = std::max(1, static_cast(m_capacity * 2)); - double *new_array = new double[new_capacity](); + double *new_array = nullptr; + try + { + new_array = new double[new_capacity](); + } + catch(const std::bad_alloc& e) + { + std::cout << "Allocation failed: " << e.what() << std::endl; + throw; + } std::copy(m_array, &m_array[m_size - 1] + 1, new_array); delete[] m_array; m_array = new_array; diff --git a/matrix_lib/tests/CMakeLists.txt b/matrix_lib/tests/CMakeLists.txt index 1fcdda7..58b797d 100644 --- a/matrix_lib/tests/CMakeLists.txt +++ b/matrix_lib/tests/CMakeLists.txt @@ -3,10 +3,6 @@ project(tests) set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O0") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) - - file(GLOB SOURCES *.cpp) find_package(GTest REQUIRED) diff --git a/matrix_lib/tests/test_matrix.cpp b/matrix_lib/tests/test_matrix.cpp index 036cbca..57cdd07 100644 --- a/matrix_lib/tests/test_matrix.cpp +++ b/matrix_lib/tests/test_matrix.cpp @@ -99,6 +99,13 @@ TEST(TestCreateDMatrix, TestConstructorsTemplate) {3, 3, 3}, {3, 3, 3} })); + + EXPECT_THROW((DMatrix::Create<0, 3>()), std::runtime_error); + EXPECT_THROW((DMatrix::Create<1, 0>(10)), std::runtime_error); + + DMatrix dmat2 = DMatrix::Create<0, 0>(); + EXPECT_EQ(dmat2.nRows(), 0); + EXPECT_EQ(dmat2.nCols(), 0); } TEST(TestCreateDMatrix, TestOperatorAssign) From 468a1eeb1c4233c455a624c1a9e76be23189a7b4 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Wed, 19 Oct 2022 00:29:36 +0300 Subject: [PATCH 12/17] fix ci --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f80586e..38d49d4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,6 +2,7 @@ on: push env: LIB_NAME: matrix_lib +env: EXE_FILE: main jobs: From 6120b269d9c50e2ba1df88c780578e5a61b0e6ef Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Wed, 19 Oct 2022 00:32:00 +0300 Subject: [PATCH 13/17] fix ci 2 --- .github/workflows/main.yml | 57 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 38d49d4..c490114 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,9 +1,8 @@ on: push -env: - LIB_NAME: matrix_lib env: EXE_FILE: main + LIB_NAME: matrix_lib jobs: build: @@ -12,34 +11,36 @@ jobs: steps: - uses: actions/checkout@v2 - run: make build + - run: ls + - run: ls build/ - name: Upload artifacts uses: actions/upload-artifact@v2 with: name: executable_file path: build/${EXE_FILE} - test: - runs-on: ubuntu-latest - container: leshiy1295/gcc_linters_valgrind_cmake_gtest - needs: [build] - steps: - - uses: actions/checkout@v2 - - name: install lcov - run: apt-get install lcov -y - - name: Build, run and test - run: | - make build TEST_OPT=ON - make run - make test - - name: Test coverage - run: | - cd build && lcov -t "tests_matrix" -o coverage.info -c -d ${LIB_NAME}/CMakeFiles - genhtml -o report coverage.info - - name: Upload artifacts - uses: actions/upload-artifact@v2 - with: - name: coverage-info - path: build/report - - name: launch valgrind - run: | - cd build - valgrind --tool=memcheck --leak-check=yes ./${EXE_FILE} \ No newline at end of file + # test: + # runs-on: ubuntu-latest + # container: leshiy1295/gcc_linters_valgrind_cmake_gtest + # needs: [build] + # steps: + # - uses: actions/checkout@v2 + # - name: install lcov + # run: apt-get install lcov -y + # - name: Build, run and test + # run: | + # make build TEST_OPT=ON + # make run + # make test + # - name: Test coverage + # run: | + # cd build && lcov -t "tests_matrix" -o coverage.info -c -d ${LIB_NAME}/CMakeFiles + # genhtml -o report coverage.info + # - name: Upload artifacts + # uses: actions/upload-artifact@v2 + # with: + # name: coverage-info + # path: build/report + # - name: launch valgrind + # run: | + # cd build + # valgrind --tool=memcheck --leak-check=yes ./${EXE_FILE} \ No newline at end of file From c6adc9bbb3d7fd608622d7b2bd18a788bb366959 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Wed, 19 Oct 2022 00:33:55 +0300 Subject: [PATCH 14/17] fix ci 3 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c490114..e0e7737 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: executable_file - path: build/${EXE_FILE} + path: build/main # test: # runs-on: ubuntu-latest # container: leshiy1295/gcc_linters_valgrind_cmake_gtest From ed016ecc40fed899cf00a95d3aca5f0661f9fcd3 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Wed, 19 Oct 2022 00:37:57 +0300 Subject: [PATCH 15/17] fix ci 4 --- .github/workflows/main.yml | 55 ++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e0e7737..826ede1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,7 +1,6 @@ on: push env: - EXE_FILE: main LIB_NAME: matrix_lib jobs: @@ -11,36 +10,34 @@ jobs: steps: - uses: actions/checkout@v2 - run: make build - - run: ls - - run: ls build/ - name: Upload artifacts uses: actions/upload-artifact@v2 with: name: executable_file path: build/main - # test: - # runs-on: ubuntu-latest - # container: leshiy1295/gcc_linters_valgrind_cmake_gtest - # needs: [build] - # steps: - # - uses: actions/checkout@v2 - # - name: install lcov - # run: apt-get install lcov -y - # - name: Build, run and test - # run: | - # make build TEST_OPT=ON - # make run - # make test - # - name: Test coverage - # run: | - # cd build && lcov -t "tests_matrix" -o coverage.info -c -d ${LIB_NAME}/CMakeFiles - # genhtml -o report coverage.info - # - name: Upload artifacts - # uses: actions/upload-artifact@v2 - # with: - # name: coverage-info - # path: build/report - # - name: launch valgrind - # run: | - # cd build - # valgrind --tool=memcheck --leak-check=yes ./${EXE_FILE} \ No newline at end of file + test: + runs-on: ubuntu-latest + container: leshiy1295/gcc_linters_valgrind_cmake_gtest + needs: [build] + steps: + - uses: actions/checkout@v2 + - name: install lcov + run: apt-get install lcov -y + - name: Build, run and test + run: | + make build TEST_OPT=ON + make run + make test + - name: Test coverage + run: | + cd build && lcov -t "tests_matrix" -o coverage.info -c -d ${LIB_NAME}/CMakeFiles + genhtml -o report coverage.info + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: coverage-info + path: build/report + - name: launch valgrind + run: | + cd build + valgrind --tool=memcheck --leak-check=yes ./main \ No newline at end of file From 7d242426401566ea4e01dc9787776f18f44bfc6c Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Thu, 20 Oct 2022 19:35:01 +0300 Subject: [PATCH 16/17] Compile-time Matrix implemented --- main.cpp | 3 +- matrix_lib/CMakeLists.txt | 12 ++ matrix_lib/include/dmatrix_compile.h | 142 +++++++++++++++++++++++ matrix_lib/tests/test_matrix_compile.cpp | 118 +++++++++++++++++++ 4 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 matrix_lib/include/dmatrix_compile.h create mode 100644 matrix_lib/tests/test_matrix_compile.cpp diff --git a/main.cpp b/main.cpp index 4d5ea39..a4501c9 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,10 @@ #include #include "dvector.h" +#include "dmatrix_compile.h" #include "dmatrix.h" int main() { - std::cout << "Hello!" << std::endl; + std::cout << "Hello!\n"; } diff --git a/matrix_lib/CMakeLists.txt b/matrix_lib/CMakeLists.txt index 2faa6d6..9594fa9 100644 --- a/matrix_lib/CMakeLists.txt +++ b/matrix_lib/CMakeLists.txt @@ -17,7 +17,19 @@ file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h) file(GLOB INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include) +# find_package(Boost COMPONENTS system REQUIRED) + +# if(NOT Boost_FOUND) +# message("Not found Boost") +# return() +# endif() + +# Boost_VERSION_MACRO +# Boost_LIBRARY_DIR +# Boost_INCLUDE_DIR + add_library(${PROJECT_NAME} ${SOURCES} ${HEADERS}) + target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIRS}) # без PARENT_SCOPE для тестов diff --git a/matrix_lib/include/dmatrix_compile.h b/matrix_lib/include/dmatrix_compile.h new file mode 100644 index 0000000..f45e66e --- /dev/null +++ b/matrix_lib/include/dmatrix_compile.h @@ -0,0 +1,142 @@ +#include "dmatrix.h" +#include "dvector.h" + +#define ERROR_LENGTH "In a matrix, all row and column lengths must be the same" +#define ERROR_RANGE "Index out of range" +#define ERROR_SIZE "An arithmetic operation is not possible because of different sizes" + +template +class DMatrixCompile +{ +private: + DMatrix dmatRuntime; +public: + DMatrixCompile(double fill_value = 0); + + size_t nRows() { return rows; } + size_t nCols() { return cols; } + + DMatrix GetDynamicMatrix() const { return dmatRuntime; } + + template + DMatrix operator+(DMatrixCompile const &dmatCompile); + + template + DMatrix operator-(DMatrixCompile const &dmatCompile); + + template + DMatrix operator*(DMatrixCompile const &dmatCompile); + + template + DMatrix operator/(DMatrixCompile const &dmatCompile); + + template + DVector const &At() const; + + template + DVector GetRow() const; + + template + DVector GetCol() const; + + template + DVector &At(); + + template + DMatrix Dot(DMatrixCompile const &dmatCompile) const; + + DMatrix T() const; +}; + +template +DMatrixCompile::DMatrixCompile(double fill_value) : dmatRuntime(rows, cols, fill_value) +{ + // pass +} + + +template +template +DVector const &DMatrixCompile::At() const +{ + static_assert(index < rows, ERROR_RANGE); + return dmatRuntime[index]; +} + +template +template +DVector &DMatrixCompile::At() +{ + static_assert(index < rows, ERROR_RANGE); + return dmatRuntime[index]; +} + +template +template +DVector DMatrixCompile::GetRow() const +{ + static_assert(index < rows, ERROR_RANGE); + return dmatRuntime.GetRow(index); +} + +template +template +DVector DMatrixCompile::GetCol() const +{ + static_assert(index < cols, ERROR_RANGE); + return dmatRuntime.GetCol(index); +} + +template +template +DMatrix DMatrixCompile::operator+(DMatrixCompile const &dmatCompile) +{ + static_assert(rows == rowsOther, ERROR_LENGTH); + static_assert(cols == colsOther, ERROR_LENGTH); + return dmatRuntime + dmatCompile.dmatRuntime; +} + +template +template +DMatrix DMatrixCompile::operator-(DMatrixCompile const &dmatCompile) +{ + static_assert(rows == rowsOther, ERROR_LENGTH); + static_assert(cols == colsOther, ERROR_LENGTH); + return dmatRuntime - dmatCompile.dmatRuntime; +} + +template +template +DMatrix DMatrixCompile::operator*(DMatrixCompile const &dmatCompile) +{ + static_assert(rows == rowsOther, ERROR_LENGTH); + static_assert(cols == colsOther, ERROR_LENGTH); + return dmatRuntime * dmatCompile.dmatRuntime; +} + +template +template +DMatrix DMatrixCompile::operator/(DMatrixCompile const &dmatCompile) +{ + static_assert(rows == rowsOther, ERROR_LENGTH); + static_assert(cols == colsOther, ERROR_LENGTH); + return dmatRuntime / dmatCompile.dmatRuntime; +} + +template +template +DMatrix DMatrixCompile::Dot(DMatrixCompile const &dmatCompile) const +{ + static_assert(cols == rowsOther, ERROR_SIZE); + /* + нельзя обратиться напрямую к приватному полю, потому класс, инстанцированный с другими шаблонными параметрами, уже является другим + */ + return dmatRuntime.Dot(dmatCompile.GetDynamicMatrix()); +} + +template +DMatrix DMatrixCompile::T() const +{ + static_assert(cols == rows, ERROR_LENGTH); + return dmatRuntime.T(); +} \ No newline at end of file diff --git a/matrix_lib/tests/test_matrix_compile.cpp b/matrix_lib/tests/test_matrix_compile.cpp new file mode 100644 index 0000000..25370b7 --- /dev/null +++ b/matrix_lib/tests/test_matrix_compile.cpp @@ -0,0 +1,118 @@ +#include +#include + +#include "dmatrix_compile.h" + +extern bool CompareMatrices(DMatrix const &matrix, std::initializer_list> const &init_list); + +extern bool CompareVectors(DVector const &dvec, std::initializer_list const &init_list); + + +TEST(TestFunctionalityDMatrixCompile, TestMatrixArithmeticOperator) +{ + auto dmatSum = DMatrixCompile<3, 2>(1) + DMatrixCompile<3, 2>(2); + + /* + Размерности не совпадают: + DMatrixCompile<3, 2>(1) + DMatrixCompile<10, 10>(2); + ERROR: static assertion failed + */ + + EXPECT_TRUE(CompareMatrices(dmatSum, { + {3, 3}, + {3, 3}, + {3, 3} + })); +} + +TEST(TestFunctionalityDMatrixCompile, TestMatrixAccess) +{ + + DMatrixCompile<3, 2> dmatCompile1(3); + + EXPECT_EQ(dmatCompile1.At<0>()[0], 3); + + /* + Доступ к строке за пределами матрицы: + dmatCompile1.At<5>()[0] + ERROR: static assertion failed + */ + + dmatCompile1.At<0>()[0] = 5; + EXPECT_EQ(dmatCompile1.At<0>()[0], 5); +} + +TEST(TestFunctionalityDMatrixCompile, TestMatrixDotProduct) +{ + + DMatrixCompile<3, 2> dmat1(1); + DMatrixCompile<2, 5> dmat2(1); + + // 3x2 * 2x5 - 3x5 + auto dmatProd = dmat1.Dot(dmat2); + + /* + Несоответствие размеров при матричном умножении: + DMatrixCompile<3, 3> dmat1(1); + ... + ERROR: static assertion failed + */ + + EXPECT_TRUE(CompareMatrices(dmatProd, { + {2, 2, 2, 2, 2}, + {2, 2, 2, 2, 2}, + {2, 2, 2, 2, 2} + })); + +} + +TEST(TestFunctionalityDMatrixCompile, TestMatrixTransponse) +{ + + DMatrixCompile<3, 3> dmat1(1); + dmat1.At<0>()[2] = 0; + + EXPECT_TRUE(CompareMatrices(dmat1.GetDynamicMatrix(), { + {1, 1, 0}, + {1, 1, 1}, + {1, 1, 1} + })); + + auto dmatTransponse = dmat1.T(); + + /* + Транспонирование неквадратной матрицы: + DMatrixCompile<5, 3> dmat1(1); + ... + ERROR: static assertion failed + */ + + EXPECT_TRUE(CompareMatrices(dmatTransponse, { + {1, 1, 1}, + {1, 1, 1}, + {0, 1, 1} + })); +} + +TEST(TestFunctionalityDMatrixCompile, TestGetRowAndCol) +{ + + DMatrixCompile<3, 4> dmat1(1); + dmat1.At<2>()[1] = 0; + + auto vec1 = dmat1.GetRow<2>(); + + EXPECT_TRUE(CompareVectors(vec1, { 1, 0, 1, 1 })); + + vec1 = dmat1.GetCol<1>(); + + /* + Изъятие строки или столбца за пределами матрицы: + dmat1.GetRow<5>(); + dmat1.GetCol<5>(); + ERROR: static assertion failed + */ + + EXPECT_TRUE(CompareVectors(vec1, { 1, 1, 0 })); +} + From daa02ba0a89f57c33744a1168fe02ebbe71fd3e0 Mon Sep 17 00:00:00 2001 From: Mikhail_Myadelets Date: Sun, 23 Oct 2022 01:04:06 +0300 Subject: [PATCH 17/17] fixed comments from PR --- .github/workflows/main.yml | 8 +- Makefile | 24 +++-- README.md | 4 +- main.cpp | 9 +- matrix_lib/include/dmatrix.h | 4 +- matrix_lib/include/dmatrix_compile.h | 2 +- matrix_lib/include/dvector.h | 6 +- matrix_lib/src/dmatrix.cpp | 39 ++++--- matrix_lib/src/dmatrix_operators.cpp | 36 +++---- matrix_lib/src/dvector.cpp | 132 ++++++++++++----------- matrix_lib/src/dvector_operators.cpp | 18 ++-- matrix_lib/src/stdafx.cpp | 2 +- matrix_lib/tests/test_matrix.cpp | 15 ++- matrix_lib/tests/test_matrix_compile.cpp | 1 - matrix_lib/tests/test_vector.cpp | 1 - 15 files changed, 170 insertions(+), 131 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 826ede1..ed82eaa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,15 +29,11 @@ jobs: make run make test - name: Test coverage - run: | - cd build && lcov -t "tests_matrix" -o coverage.info -c -d ${LIB_NAME}/CMakeFiles - genhtml -o report coverage.info + run: make coverage - name: Upload artifacts uses: actions/upload-artifact@v2 with: name: coverage-info path: build/report - name: launch valgrind - run: | - cd build - valgrind --tool=memcheck --leak-check=yes ./main \ No newline at end of file + run: make valgrind_tests \ No newline at end of file diff --git a/Makefile b/Makefile index 508ed88..ac94323 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,10 @@ -# чувствителен к изменению исходных файлов -# игнорирует изменения файла CMakeLists.txt (если make run) - -LIB = matrix_lib +LIB_DIR = matrix_lib BUILD_DIR = build + TARGET = ./${BUILD_DIR}/main +TESTS_EXE = tests +TESTS_DIR = tests + TEST_OPT = OFF DEBUG_OPT = OFF @@ -16,13 +17,18 @@ build: clean clean: (rm -r ${BUILD_DIR} 2>/dev/null) || exit 0 -# выполняется, если проект собран run: cd ${BUILD_DIR} && $(MAKE) --no-print-directory ${TARGET} -# выполняется, если проект собран -test: ${TARGET} - ./${BUILD_DIR}/${LIB}/tests/tests -# cd ${BUILD_DIR}/${LIB} && ctest +test: + ./${BUILD_DIR}/${LIB_DIR}/tests/tests + +coverage: + cd ${BUILD_DIR} && lcov -t "testing_${LIB_DIR}" -o coverage.info -c -d ${LIB_DIR}/CMakeFiles \ + && lcov --remove coverage.info -o coverage.info '/usr/include/*' '/usr/lib/*' \ + && genhtml -o report coverage.info + +valgrind_tests: + valgrind --tool=memcheck --leak-check=yes --error-exitcode=1 ./${BUILD_DIR}/${LIB_DIR}/${TESTS_DIR}/${TESTS_EXE} diff --git a/README.md b/README.md index 3fec761..29d7185 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ #### Домашняя работа 1 -##### Мяделец Михаил WEB-11 +##### Студент: Михаил Мяделец WEB-11 +##### Ментор: Денис Кириллов +##### Преподаватель: Иван Возвахов `Вариант #1` diff --git a/main.cpp b/main.cpp index a4501c9..0576bcd 100644 --- a/main.cpp +++ b/main.cpp @@ -6,5 +6,12 @@ int main() { - std::cout << "Hello!\n"; + DMatrix matrix = { + {1, -2, 1}, + {2, 1, -1}, + {3, 2, -2} + }; + DVector vector = {3, 4, 5}; + DMatrix newMatrix = 2 * vector.Dot(matrix.Inv()); + std::cout << newMatrix; } diff --git a/matrix_lib/include/dmatrix.h b/matrix_lib/include/dmatrix.h index d5f2b43..aea9e64 100644 --- a/matrix_lib/include/dmatrix.h +++ b/matrix_lib/include/dmatrix.h @@ -120,6 +120,8 @@ DMatrix operator-(DMatrix left, DMatrix const &right); DMatrix operator/(DMatrix left, DMatrix const &right); DMatrix operator*(DMatrix left, DMatrix const &right); +std::ostream &operator<<(std::ostream &out, DMatrix const &matrix); + void Print(DMatrix const &matrix, std::string const &msg = std::string{}); template @@ -130,4 +132,4 @@ DMatrix DMatrix::Create(double fill_value) throw std::runtime_error("Creation is impossible"); } return DMatrix(rows, cols, fill_value); -} \ No newline at end of file +} diff --git a/matrix_lib/include/dmatrix_compile.h b/matrix_lib/include/dmatrix_compile.h index f45e66e..3d37ff1 100644 --- a/matrix_lib/include/dmatrix_compile.h +++ b/matrix_lib/include/dmatrix_compile.h @@ -139,4 +139,4 @@ DMatrix DMatrixCompile::T() const { static_assert(cols == rows, ERROR_LENGTH); return dmatRuntime.T(); -} \ No newline at end of file +} diff --git a/matrix_lib/include/dvector.h b/matrix_lib/include/dvector.h index ab828ef..1dbe99a 100644 --- a/matrix_lib/include/dvector.h +++ b/matrix_lib/include/dvector.h @@ -1,7 +1,5 @@ #pragma once -#include "stdafx.h" - class DMatrix; // Vector of doubles number @@ -80,4 +78,6 @@ DVector operator-(DVector left, DVector const &right); DVector operator/(DVector left, DVector const &right); DVector operator*(DVector left, DVector const &right); -void Print(DVector const &dvector, std::string const &message = std::string{}); \ No newline at end of file +void Print(DVector const &dvector, std::string const &message = std::string{}); + +std::ostream &operator<<(std::ostream &out, DVector const &vector); diff --git a/matrix_lib/src/dmatrix.cpp b/matrix_lib/src/dmatrix.cpp index 9120b85..fc5c81c 100644 --- a/matrix_lib/src/dmatrix.cpp +++ b/matrix_lib/src/dmatrix.cpp @@ -9,7 +9,7 @@ const std::string ERROR_LENGTH = "In a matrix, all row and column l const std::string ERROR_RECT_MATRIX = "Matrix is not square"; // проверка на равный размер, иначе исключение -void IsEqualSize(size_t size1, size_t size2, std::string const &msgError = "Exception") +void CheckEqualSize(size_t size1, size_t size2, std::string const &msgError = "Exception") { if (size1 != size2) { @@ -216,7 +216,8 @@ void DMatrix::PushRowBack(DVector const &dvec) { grow(); } - m_matrix[m_nRows++] = dvec; + m_matrix[m_nRows] = dvec; + ++m_nRows; } void DMatrix::PushRowBack(std::initializer_list const &init_list) @@ -230,7 +231,8 @@ void DMatrix::PushRowBack(std::initializer_list const &init_list) { grow(); } - m_matrix[m_nRows++] = DVector(init_list.begin(), init_list.end()); + m_matrix[m_nRows] = DVector(init_list.begin(), init_list.end()); + ++m_nRows; } void DMatrix::PopRowBack() @@ -239,7 +241,7 @@ void DMatrix::PopRowBack() { throw std::runtime_error("PopRowBack: " + ERROR_EMPTY); } - m_matrix[--m_nRows].~DVector(); + --m_nRows; if (m_nRows == 0) { if (m_matrix) @@ -366,7 +368,7 @@ DVector DMatrix::GetCol(size_t index) const DMatrix DMatrix::Dot(DMatrix const &other) const { - IsEqualSize(m_nCols, other.nRows(), "Dot: " + ERROR_SIZE); + CheckEqualSize(m_nCols, other.nRows(), "Dot: " + ERROR_SIZE); DMatrix dmat(m_nRows, other.nCols()); for (size_t i = 0; i < m_nRows; ++i) @@ -388,7 +390,7 @@ DMatrix DMatrix::Dot(DMatrix const &other) const // результат - DVector DVector DMatrix::Dot(DVector const &dvec) const { - IsEqualSize(m_nCols, dvec.Size(), "Dot: " + ERROR_SIZE); + CheckEqualSize(m_nCols, dvec.Size(), "Dot: " + ERROR_SIZE); DVector dvecRes(m_nRows); for (size_t i = 0; i < m_nRows; ++i) @@ -423,7 +425,7 @@ void DMatrix::AddVec(DVector const &dvec, ORIENT orientation) { if (orientation == ORIENT::ROW) { - IsEqualSize(dvec.Size(), m_nCols, "AddVec: " + ERROR_SIZE); + CheckEqualSize(dvec.Size(), m_nCols, "AddVec: " + ERROR_SIZE); // почему capture принимает по ссылке, хотя в сигнатуре const? std::for_each(m_matrix, &m_matrix[m_nRows - 1] + 1, [&dvec](DVector &vec) { @@ -432,7 +434,7 @@ void DMatrix::AddVec(DVector const &dvec, ORIENT orientation) } else { - IsEqualSize(dvec.Size(), m_nRows, "AddVec: " + ERROR_SIZE); + CheckEqualSize(dvec.Size(), m_nRows, "AddVec: " + ERROR_SIZE); for (size_t i = 0; i < dvec.Size(); ++i) { m_matrix[i].AddNum(dvec[i]); @@ -444,7 +446,7 @@ void DMatrix::SubVec(DVector const &dvec, ORIENT orientation) { if (orientation == ORIENT::ROW) { - IsEqualSize(dvec.Size(), m_nCols, "SubVec: " + ERROR_SIZE); + CheckEqualSize(dvec.Size(), m_nCols, "SubVec: " + ERROR_SIZE); std::for_each(m_matrix, &m_matrix[m_nRows - 1] + 1, [&dvec](DVector &vec) { vec -= dvec; @@ -452,7 +454,7 @@ void DMatrix::SubVec(DVector const &dvec, ORIENT orientation) } else { - IsEqualSize(dvec.Size(), m_nRows, "SubVec: " + ERROR_SIZE); + CheckEqualSize(dvec.Size(), m_nRows, "SubVec: " + ERROR_SIZE); for (size_t i = 0; i < dvec.Size(); ++i) { m_matrix[i].SubNum(dvec[i]); @@ -462,7 +464,7 @@ void DMatrix::SubVec(DVector const &dvec, ORIENT orientation) DMatrix DMatrix::T() const { - IsEqualSize(m_nRows, m_nCols, "Transponse: " + ERROR_RECT_MATRIX); + CheckEqualSize(m_nRows, m_nCols, "Transponse: " + ERROR_RECT_MATRIX); DMatrix dmatRes(m_nRows, m_nCols); for (size_t i = 0; i < m_nRows; ++i) { @@ -476,7 +478,7 @@ DMatrix DMatrix::T() const double DMatrix::Det() const { - IsEqualSize(m_nRows, m_nCols, "Determinant: " + ERROR_RECT_MATRIX); + CheckEqualSize(m_nRows, m_nCols, "Determinant: " + ERROR_RECT_MATRIX); if (m_nRows == 2) { return m_matrix[0][0] * m_matrix[1][1] - m_matrix[0][1] * m_matrix[1][0]; @@ -557,9 +559,10 @@ void DMatrix::EraseByIndex(size_t index, ORIENT orientation) { m_matrix[i] = m_matrix[i + 1]; } - m_matrix[--m_nRows].~DVector(); + --m_nRows; if (m_nRows == 0) { + delete[] m_matrix; Clear(); } } @@ -576,6 +579,7 @@ void DMatrix::EraseByIndex(size_t index, ORIENT orientation) m_nCols--; if (m_nCols == 0) { + delete[] m_matrix; Clear(); } } @@ -603,7 +607,6 @@ DMatrix DMatrix::SliceRow(size_t begin, size_t end, int step) const { throw std::runtime_error("operator(): " + ERROR_RANGE); } - // auto cmp = [](size_t i, size_t end) -> bool {} DMatrix dmatSlice; if (step > 0) { @@ -680,4 +683,10 @@ void Print(DMatrix const &matrix, std::string const &msg) { Print(matrix[i]); } -} \ No newline at end of file +} + +std::ostream &operator<<(std::ostream &out, DMatrix const &matrix) +{ + Print(matrix); + return out; +} diff --git a/matrix_lib/src/dmatrix_operators.cpp b/matrix_lib/src/dmatrix_operators.cpp index db3c565..28e7196 100644 --- a/matrix_lib/src/dmatrix_operators.cpp +++ b/matrix_lib/src/dmatrix_operators.cpp @@ -4,7 +4,7 @@ extern const std::string ERROR_EMPTY; extern const std::string ERROR_SIZE; -extern void IsEqualSize(size_t size1, size_t size2, std::string const &msgError); +extern void CheckEqualSize(size_t size1, size_t size2, std::string const &msgError); // --------------------------------------------------- // value *= matrix @@ -37,8 +37,8 @@ DMatrix operator/(double value, DMatrix matrix) DMatrix &operator+=(DMatrix &left, DMatrix const &right) { - IsEqualSize(left.nRows(), right.nRows(), "operator+= :" + ERROR_SIZE); - IsEqualSize(left.nCols(), right.nCols(), "operator+= :" + ERROR_SIZE); + CheckEqualSize(left.nRows(), right.nRows(), "operator+= :" + ERROR_SIZE); + CheckEqualSize(left.nCols(), right.nCols(), "operator+= :" + ERROR_SIZE); for (size_t i = 0; i < left.nRows(); ++i) { left[i] += right[i]; @@ -48,8 +48,8 @@ DMatrix &operator+=(DMatrix &left, DMatrix const &right) DMatrix &operator-=(DMatrix &left, DMatrix const &right) { - IsEqualSize(left.nRows(), right.nRows(), "operator-= :" + ERROR_SIZE); - IsEqualSize(left.nCols(), right.nCols(), "operator-= :" + ERROR_SIZE); + CheckEqualSize(left.nRows(), right.nRows(), "operator-= :" + ERROR_SIZE); + CheckEqualSize(left.nCols(), right.nCols(), "operator-= :" + ERROR_SIZE); for (size_t i = 0; i < left.nRows(); ++i) { left[i] -= right[i]; @@ -59,8 +59,8 @@ DMatrix &operator-=(DMatrix &left, DMatrix const &right) DMatrix &operator*=(DMatrix &left, DMatrix const &right) { - IsEqualSize(left.nRows(), right.nRows(), "operator*= :" + ERROR_SIZE); - IsEqualSize(left.nCols(), right.nCols(), "operator*= :" + ERROR_SIZE); + CheckEqualSize(left.nRows(), right.nRows(), "operator*= :" + ERROR_SIZE); + CheckEqualSize(left.nCols(), right.nCols(), "operator*= :" + ERROR_SIZE); for (size_t i = 0; i < left.nRows(); ++i) { left[i] *= right[i]; @@ -70,8 +70,8 @@ DMatrix &operator*=(DMatrix &left, DMatrix const &right) DMatrix &operator/=(DMatrix &left, DMatrix const &right) { - IsEqualSize(left.nRows(), right.nRows(), "operator/= :" + ERROR_SIZE); - IsEqualSize(left.nCols(), right.nCols(), "operator/= :" + ERROR_SIZE); + CheckEqualSize(left.nRows(), right.nRows(), "operator/= :" + ERROR_SIZE); + CheckEqualSize(left.nCols(), right.nCols(), "operator/= :" + ERROR_SIZE); for (size_t i = 0; i < left.nRows(); ++i) { left[i] /= right[i]; @@ -84,29 +84,29 @@ DMatrix &operator/=(DMatrix &left, DMatrix const &right) DMatrix operator+(DMatrix left, DMatrix const &right) { - IsEqualSize(left.nRows(), right.nRows(), "operator+ :" + ERROR_SIZE); - IsEqualSize(left.nCols(), right.nCols(), "operator+ :" + ERROR_SIZE); + CheckEqualSize(left.nRows(), right.nRows(), "operator+ :" + ERROR_SIZE); + CheckEqualSize(left.nCols(), right.nCols(), "operator+ :" + ERROR_SIZE); return left += right; } DMatrix operator-(DMatrix left, DMatrix const &right) { - IsEqualSize(left.nRows(), right.nRows(), "operator- :" + ERROR_SIZE); - IsEqualSize(left.nCols(), right.nCols(), "operator-:" + ERROR_SIZE); + CheckEqualSize(left.nRows(), right.nRows(), "operator- :" + ERROR_SIZE); + CheckEqualSize(left.nCols(), right.nCols(), "operator-:" + ERROR_SIZE); return left -= right; } DMatrix operator*(DMatrix left, DMatrix const &right) { - IsEqualSize(left.nRows(), right.nRows(), "operator* :" + ERROR_SIZE); - IsEqualSize(left.nCols(), right.nCols(), "operator* :" + ERROR_SIZE); + CheckEqualSize(left.nRows(), right.nRows(), "operator* :" + ERROR_SIZE); + CheckEqualSize(left.nCols(), right.nCols(), "operator* :" + ERROR_SIZE); return left *= right; } DMatrix operator/(DMatrix left, DMatrix const &right) { - IsEqualSize(left.nRows(), right.nRows(), "operator/ :" + ERROR_SIZE); - IsEqualSize(left.nCols(), right.nCols(), "operator/ :" + ERROR_SIZE); + CheckEqualSize(left.nRows(), right.nRows(), "operator/ :" + ERROR_SIZE); + CheckEqualSize(left.nCols(), right.nCols(), "operator/ :" + ERROR_SIZE); return left /= right; } @@ -144,4 +144,4 @@ DMatrix operator/(DMatrix matrix, double value) return matrix /= value; } -// -------------------------------------------------------- \ No newline at end of file +// -------------------------------------------------------- diff --git a/matrix_lib/src/dvector.cpp b/matrix_lib/src/dvector.cpp index 38a2dfc..f077155 100644 --- a/matrix_lib/src/dvector.cpp +++ b/matrix_lib/src/dvector.cpp @@ -8,7 +8,7 @@ extern const std::string ERROR_SIZE; extern const std::string ERROR_RANGE; extern const std::string ERROR_EMPTY; -extern void IsEqualSize(size_t size1, size_t size2, std::string const &msgError); +extern void CheckEqualSize(size_t size1, size_t size2, std::string const &msgError); void Print(DVector const &dvector, std::string const &message) { @@ -95,12 +95,39 @@ DVector::DVector(const double *begin, const double *end) std::copy(begin, end, m_array); } +DVector::~DVector() +{ + if (m_array) + { + delete[] m_array; + } + m_array = nullptr; +} + DVector &DVector::operator=(DVector other) { Swap(other); return *this; } +double const &DVector::operator[](size_t index) const +{ + if (index > m_size - 1) + { + throw std::runtime_error("operator[] : " + ERROR_RANGE); + } + return m_array[index]; +} + +double &DVector::operator[](size_t index) +{ + if (index > m_size - 1) + { + throw std::runtime_error("operator[] : " + ERROR_RANGE); + } + return m_array[index]; +} + const double *DVector::CBegin() const { return m_array; @@ -124,47 +151,11 @@ void DVector::Swap(DVector &other) std::swap(m_size, other.m_size); } -double const &DVector::operator[](size_t index) const -{ - if (index > m_size - 1) - { - throw std::runtime_error("operator[] : " + ERROR_RANGE); - } - return m_array[index]; -} - -double &DVector::operator[](size_t index) -{ - if (index > m_size - 1) - { - throw std::runtime_error("operator[] : " + ERROR_RANGE); - } - return m_array[index]; -} - -void DVector::PushBack(double value) -{ - if (m_size == m_capacity) - { - grow(); - } - m_array[m_size++] = value; -} - bool DVector::Empty() const { return m_size == 0; } -void DVector::PopBack() -{ - if (Empty()) - { - throw std::runtime_error("PopBack: " + ERROR_EMPTY); - } - --m_size; -} - size_t DVector::Size() const { return m_size; @@ -204,15 +195,43 @@ double DVector::Back() const return m_array[m_size - 1]; } -DVector::~DVector() + +void DVector::PushBack(double value) { - if (m_array) + if (m_size == m_capacity) { - delete[] m_array; + grow(); } - m_array = nullptr; + m_array[m_size++] = value; +} + +// возвращает элемент, следующий за удаленным либо предыдущий, если удаленный был последним +double *DVector::Erase(double *it_value) +{ + ptrdiff_t diff = reinterpret_cast(it_value) - reinterpret_cast(m_array); + if (!it_value || it_value < m_array || it_value > &m_array[m_size - 1] || diff % sizeof(double) != 0) + { + return nullptr; + } + for (double *it = it_value; it < &m_array[m_size - 1]; it++) + { + *it = *(it + 1); + } + --m_size; + return it_value == &m_array[m_size - 1] + 1 ? it_value - 1 : it_value; + } +void DVector::PopBack() +{ + if (Empty()) + { + throw std::runtime_error("PopBack: " + ERROR_EMPTY); + } + --m_size; +} + + double *DVector::Find(double value) const { double *it_end = &m_array[m_size - 1] + 1; @@ -239,28 +258,12 @@ void DVector::SubNum(double value) }); } -// возвращает элемент, следующий за удаленным либо предыдущий, если удаленный был последним -double *DVector::Erase(double *it_value) -{ - ptrdiff_t diff = reinterpret_cast(it_value) - reinterpret_cast(m_array); - if (!it_value || it_value < m_array || it_value > &m_array[m_size - 1] || diff % sizeof(double) != 0) - { - return nullptr; - } - for (double *it = it_value; it < &m_array[m_size - 1]; it++) - { - *it = *(it + 1); - } - --m_size; - return it_value == &m_array[m_size - 1] + 1 ? it_value - 1 : it_value; - -} // подразуемевается что вектор-строка умножается на матрицу -// результат - DVector +// vector[1xN] * matrix[NxM] = vector[1xM] DVector DVector::Dot(DMatrix const &matrix) const { - IsEqualSize(m_size, matrix.nRows(), ERROR_SIZE); + CheckEqualSize(m_size, matrix.nRows(), ERROR_SIZE); DVector dvecRes(matrix.nCols()); for (size_t i = 0; i < matrix.nCols(); ++i) @@ -275,9 +278,10 @@ DVector DVector::Dot(DMatrix const &matrix) const return dvecRes; } +// скалярное произведение векторов, результат - число double DVector::Dot(DVector const &other) const { - IsEqualSize(m_size, other.Size(), "Dot:" + ERROR_SIZE); + CheckEqualSize(m_size, other.Size(), "Dot:" + ERROR_SIZE); double dotProduct = 0; for (size_t i = 0; i < m_size; ++i) { @@ -331,4 +335,10 @@ void DVector::grow() delete[] m_array; m_array = new_array; m_capacity = new_capacity; -} \ No newline at end of file +} + +std::ostream &operator<<(std::ostream &out, DVector const &vector) +{ + Print(vector); + return out; +} diff --git a/matrix_lib/src/dvector_operators.cpp b/matrix_lib/src/dvector_operators.cpp index a4263b1..d917283 100644 --- a/matrix_lib/src/dvector_operators.cpp +++ b/matrix_lib/src/dvector_operators.cpp @@ -6,14 +6,14 @@ extern const std::string ERROR_SIZE; -extern void IsEqualSize(size_t size1, size_t size2, std::string const &msgError); +extern void CheckEqualSize(size_t size1, size_t size2, std::string const &msgError); // --------------------------------------------------- // vector += vector DVector &operator+=(DVector &left, DVector const &right) { - IsEqualSize(left.Size(), right.Size(), "operator+= :" + ERROR_SIZE); + CheckEqualSize(left.Size(), right.Size(), "operator+= :" + ERROR_SIZE); for (size_t i = 0; i < left.Size(); ++i) { left[i] += right[i]; @@ -23,7 +23,7 @@ DVector &operator+=(DVector &left, DVector const &right) DVector &operator-=(DVector &left, DVector const &right) { - IsEqualSize(left.Size(), right.Size(), "operator-= :" + ERROR_SIZE); + CheckEqualSize(left.Size(), right.Size(), "operator-= :" + ERROR_SIZE); for (size_t i = 0; i < left.Size(); ++i) { left[i] -= right[i]; @@ -33,7 +33,7 @@ DVector &operator-=(DVector &left, DVector const &right) DVector &operator*=(DVector &left, DVector const &right) { - IsEqualSize(left.Size(), right.Size(), "operator*= :" + ERROR_SIZE); + CheckEqualSize(left.Size(), right.Size(), "operator*= :" + ERROR_SIZE); for (size_t i = 0; i < left.Size(); ++i) { left[i] *= right[i]; @@ -43,7 +43,7 @@ DVector &operator*=(DVector &left, DVector const &right) DVector &operator/=(DVector &left, DVector const &right) { - IsEqualSize(left.Size(), right.Size(), "operator/= :" + ERROR_SIZE); + CheckEqualSize(left.Size(), right.Size(), "operator/= :" + ERROR_SIZE); for (size_t i = 0; i < left.Size(); ++i) { left[i] /= right[i]; @@ -56,25 +56,25 @@ DVector &operator/=(DVector &left, DVector const &right) DVector operator+(DVector left, DVector const &right) { - IsEqualSize(left.Size(), right.Size(), "operator+ :" + ERROR_SIZE); + CheckEqualSize(left.Size(), right.Size(), "operator+ :" + ERROR_SIZE); return left += right; } DVector operator-(DVector left, DVector const &right) { - IsEqualSize(left.Size(), right.Size(), "operator- :" + ERROR_SIZE); + CheckEqualSize(left.Size(), right.Size(), "operator- :" + ERROR_SIZE); return left -= right; } DVector operator*(DVector left, DVector const &right) { - IsEqualSize(left.Size(), right.Size(), "operator* :" + ERROR_SIZE); + CheckEqualSize(left.Size(), right.Size(), "operator* :" + ERROR_SIZE); return left *= right; } DVector operator/(DVector left, DVector const &right) { - IsEqualSize(left.Size(), right.Size(), "operator/ :" + ERROR_SIZE); + CheckEqualSize(left.Size(), right.Size(), "operator/ :" + ERROR_SIZE); return left /= right; } diff --git a/matrix_lib/src/stdafx.cpp b/matrix_lib/src/stdafx.cpp index 1577c4e..fd4f341 100644 --- a/matrix_lib/src/stdafx.cpp +++ b/matrix_lib/src/stdafx.cpp @@ -1 +1 @@ -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" diff --git a/matrix_lib/tests/test_matrix.cpp b/matrix_lib/tests/test_matrix.cpp index 57cdd07..fe3be04 100644 --- a/matrix_lib/tests/test_matrix.cpp +++ b/matrix_lib/tests/test_matrix.cpp @@ -7,6 +7,10 @@ const double EPS = 0.000001; bool CompareMatrices(DMatrix const &matrix, std::initializer_list> const &init_list) { + if ((matrix.nRows() != init_list.size()) || (matrix.nCols() != init_list.begin()->size())) + { + return false; + } for (size_t i = 0; i < matrix.nRows(); ++i) { for (size_t j = 0; j < matrix.nCols(); ++j) @@ -22,6 +26,10 @@ bool CompareMatrices(DMatrix const &matrix, std::initializer_list const &init_list) { + if (dvec.Size() != init_list.size()) + { + return false; + } for (size_t i = 0; i < dvec.Size(); ++i) { if (std::abs(dvec[i] - *(init_list.begin() + i)) > EPS) @@ -134,6 +142,8 @@ TEST(TestErrorHandling, TestAccessAndCreateNotRectangleMatrix) DMatrix dmat{ {1, 2, 3}, {4, 5, 6} }; + delete[] dvecs; + EXPECT_THROW(dmat[2][1], std::runtime_error); EXPECT_THROW(dmat[0][5], std::runtime_error); } @@ -506,7 +516,7 @@ TEST(TestFunctionalityDMatrix, TestEraseByIndexCol) })); dmat.EraseByIndex(0, ORIENT::COL); - EXPECT_TRUE(CompareMatrices(dmat, {{}})); + EXPECT_TRUE(dmat.Empty()); EXPECT_THROW(dmat.EraseByIndex(0, ORIENT::COL), std::runtime_error); EXPECT_THROW(dmat.EraseByIndex(200, ORIENT::COL), std::runtime_error); @@ -634,7 +644,7 @@ TEST(TestFunctionalityDMatrix, TestSliceOperatorRow) EXPECT_THROW(dmat(0, 100), std::runtime_error); DMatrix dmatSlice5 = dmat(0, 4, 0); - EXPECT_TRUE(CompareMatrices(dmatSlice5, { {} })); + EXPECT_TRUE(dmatSlice5.Empty()); } TEST(TestFunctionalityDMatrix, TestSliceOperatorCol) @@ -738,4 +748,3 @@ TEST(TestFunctionalityDMatrix, TestSliceCallMethod) {17, 19} })); } - diff --git a/matrix_lib/tests/test_matrix_compile.cpp b/matrix_lib/tests/test_matrix_compile.cpp index 25370b7..3ffe295 100644 --- a/matrix_lib/tests/test_matrix_compile.cpp +++ b/matrix_lib/tests/test_matrix_compile.cpp @@ -115,4 +115,3 @@ TEST(TestFunctionalityDMatrixCompile, TestGetRowAndCol) EXPECT_TRUE(CompareVectors(vec1, { 1, 1, 0 })); } - diff --git a/matrix_lib/tests/test_vector.cpp b/matrix_lib/tests/test_vector.cpp index 4c6d67d..76fca98 100644 --- a/matrix_lib/tests/test_vector.cpp +++ b/matrix_lib/tests/test_vector.cpp @@ -198,4 +198,3 @@ TEST(TestFunctionalityDVector, TestSliceOperator) EXPECT_THROW(dvec(20, 22), std::runtime_error); } -