diff --git a/.gitignore b/.gitignore index 1dc9768..92f80e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,51 @@ # Compiled class file *.class -out/ +Java/out/ +Java/.idea/workspace.xml +Java/.PVS-Studio/ # Log file *.log +# Javascript files +*.js + +# C++ generated files and folders +.vs/ +*.d +*.o +x64/ +Release/ +Debug/ +*.user +*.orig +C++/bin/ +drd.txt +helgrind.txt +valgrind.txt +report/ + +# C generated files and folders +C/bin/ + +# C# generated files and folders +DotNET/packages/ + +# Vala generated files and folders +Vala/bin/ +Vala/src/*.c +Vala/test/*.c + +# Test accestance output files +out*.txt +stdout*.txt + +# node_modules +Typescript/node_modules/ + +# package-lock +Typescript/package-lock.json + # BlueJ files *.ctxt @@ -25,6 +66,3 @@ hs_err_pid* # Git git.properties - -# IntelliJ IDEA folder -.idea/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..237ab58 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "C/3rd/unity"] + path = C/3rd/unity + url = https://github.com/ThrowTheSwitch/Unity +[submodule "C/3rd/useful-c-macros"] + path = C/3rd/useful-c-macros + url = https://github.com/fsb4000/useful-c-macros +[submodule "C++/3rd/useful-c-macros"] + path = C++/3rd/useful-c-macros + url = https://github.com/fsb4000/useful-c-macros diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index a165cb3..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/project.iml b/.idea/project.iml deleted file mode 100644 index 47baa8c..0000000 --- a/.idea/project.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/C++/.vscode/c_cpp_properties.json b/C++/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..ef87bd2 --- /dev/null +++ b/C++/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**", + "C:/msys2/mingw64/include/**", + "C:/msys2/mingw64/lib/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.17763.0", + "compilerPath": "C:/msys2/mingw64/bin/clang++.exe", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/C++/.vscode/settings.json b/C++/.vscode/settings.json new file mode 100644 index 0000000..17062d9 --- /dev/null +++ b/C++/.vscode/settings.json @@ -0,0 +1,54 @@ +{ + "C_Cpp.errorSquiggles": "Enabled", + "files.associations": { + "iosfwd": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "array": "cpp", + "strstream": "cpp", + "*.tcc": "cpp", + "complex": "cpp", + "cstdint": "cpp", + "list": "cpp", + "vector": "cpp", + "exception": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "utility": "cpp", + "ctime": "cpp", + "cwctype": "cpp", + "atomic": "cpp", + "bitset": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "fstream": "cpp", + "memory": "cpp", + "numeric": "cpp", + "ratio": "cpp", + "thread": "cpp", + "typeindex": "cpp", + "variant": "cpp" + } +} \ No newline at end of file diff --git a/C++/3rd/useful-c-macros b/C++/3rd/useful-c-macros new file mode 160000 index 0000000..6472945 --- /dev/null +++ b/C++/3rd/useful-c-macros @@ -0,0 +1 @@ +Subproject commit 6472945eb2d9950bc7f99e464ddeec8e75ab5e43 diff --git a/C++/acceptance tests/in.txt b/C++/acceptance tests/in.txt new file mode 100644 index 0000000..b1db2cf --- /dev/null +++ b/C++/acceptance tests/in.txt @@ -0,0 +1,4 @@ +3 3 +1 1 2 9 +2 4 -3 1 +3 6 -5 0 diff --git a/C++/acceptance tests/in1.txt b/C++/acceptance tests/in1.txt new file mode 100644 index 0000000..112d10d --- /dev/null +++ b/C++/acceptance tests/in1.txt @@ -0,0 +1,5 @@ +3 4 +0 1 2 9 +0 1 3 1 +1 0 6 0 +2 0 2 0 \ No newline at end of file diff --git a/C++/acceptance tests/in2.txt b/C++/acceptance tests/in2.txt new file mode 100644 index 0000000..512957d --- /dev/null +++ b/C++/acceptance tests/in2.txt @@ -0,0 +1,5 @@ +4 4 +1 0 0 5 0 +0 0 0 0 0 +0 0 1 4 6 +0 0 5 5 5 \ No newline at end of file diff --git a/C++/acceptance tests/in3.txt b/C++/acceptance tests/in3.txt new file mode 100644 index 0000000..3b20f11 --- /dev/null +++ b/C++/acceptance tests/in3.txt @@ -0,0 +1,4 @@ +3 3 +1+2i -1.5-1.1i 2.12 91+5i +-1+3i 1.2+3.5i -3.3 1+15i +12.31 1.3-5i 12.3i -78.3i \ No newline at end of file diff --git a/C++/acceptance tests/tests.ps1 b/C++/acceptance tests/tests.ps1 new file mode 100755 index 0000000..ddd3c96 --- /dev/null +++ b/C++/acceptance tests/tests.ps1 @@ -0,0 +1,89 @@ +#!/usr/bin/env pwsh +Describe CppAcceptanceTests { + It 'single solution' { + Remove-Item "$PSScriptRoot/out.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_cpp" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out.txt" -verbose > "$PSScriptRoot/stdout.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(1, 2, 3)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "-2 * R1 +R2 -> R2", "-3 * R1 +R3 -> R3", + "R2 / 2 -> R2", "-3 * R2 +R3 -> R3", "R3 / -0.5 -> R3", + "3.5 * R3 +R2 -> R2", "-2 * R3 +R1 -> R1", "-1 * R2 +R1 -> R1", + "(1, 2, 3)", "Saved to file $PSScriptRoot/out.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no solution' { + Remove-Item "$PSScriptRoot/out1.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout1.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_cpp" -in "$PSScriptRoot/in1.txt" -out "$PSScriptRoot/out1.txt" -verbose > "$PSScriptRoot/stdout1.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out1.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "There are no solutions" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout1.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 <-> R3", "-1 * R2 +R3 -> R3", "R3 / -1 -> R3", + "-3 * R3 +R2 -> R2", "-6 * R3 +R1 -> R1", "There are no solutions", "Saved to file $PSScriptRoot/out1.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'many solutions' { + Remove-Item "$PSScriptRoot/out2.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout2.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_cpp" -in "$PSScriptRoot/in2.txt" -out "$PSScriptRoot/out2.txt" -verbose > "$PSScriptRoot/stdout2.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out2.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(-8.3333, x2, -0.6667, 1.6667)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout2.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "C3 <-> C2", "R3 <-> R2", "-5 * R2 +R4 -> R4", + "C4 <-> C3", "R4 <-> R3", "R3 / -15 -> R3", "-4 * R3 +R2 -> R2", + "-5 * R3 +R1 -> R1", "(-8.3333, x2, -0.6667, 1.6667)","Saved to file $PSScriptRoot/out2.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'single solution complex numbers' { + Remove-Item "$PSScriptRoot/out3.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout3.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_cpp" -in "$PSScriptRoot/in3.txt" -out "$PSScriptRoot/out3.txt" -verbose > "$PSScriptRoot/stdout3.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out3.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout3.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 / 1+2i -> R1", "1-3i * R1 +R2 -> R2", "-12.31 * R1 +R3 -> R3", + "R2 / 1.6+6.1i -> R2", "-10.4094+9.6778i * R2 +R3 -> R3", "R3 / -6.7848+9.7158i -> R3", + "0.5432-0.746i * R3 +R2 -> R2", "-0.424+0.848i * R3 +R1 -> R1", "0.74-0.38i * R2 +R1 -> R1", + "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)", "Saved to file $PSScriptRoot/out3.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no output without -verbose' { + Remove-Item "$PSScriptRoot/out4.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout4.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_cpp" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out4.txt" > "$PSScriptRoot/stdout4.txt" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout4.txt") + $stdoutLines.Count | Should Be 0 + } +} diff --git a/C++/acceptance tests/tests_win.ps1 b/C++/acceptance tests/tests_win.ps1 new file mode 100644 index 0000000..1ab11d1 --- /dev/null +++ b/C++/acceptance tests/tests_win.ps1 @@ -0,0 +1,88 @@ +Describe CppAcceptanceTests { + It 'single solution' { + Remove-Item "$PSScriptRoot/out.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out.txt" -verbose > "$PSScriptRoot/stdout.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(1, 2, 3)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "-2 * R1 +R2 -> R2", "-3 * R1 +R3 -> R3", + "R2 / 2 -> R2", "-3 * R2 +R3 -> R3", "R3 / -0.5 -> R3", + "3.5 * R3 +R2 -> R2", "-2 * R3 +R1 -> R1", "-1 * R2 +R1 -> R1", + "(1, 2, 3)", "Saved to file $PSScriptRoot/out.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no solution' { + Remove-Item "$PSScriptRoot/out1.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout1.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in1.txt" -out "$PSScriptRoot/out1.txt" -verbose > "$PSScriptRoot/stdout1.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out1.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "There are no solutions" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout1.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 <-> R3", "-1 * R2 +R3 -> R3", "R3 / -1 -> R3", + "-3 * R3 +R2 -> R2", "-6 * R3 +R1 -> R1", "There are no solutions", "Saved to file $PSScriptRoot/out1.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'many solutions' { + Remove-Item "$PSScriptRoot/out2.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout2.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in2.txt" -out "$PSScriptRoot/out2.txt" -verbose > "$PSScriptRoot/stdout2.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out2.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(-8.3333, x2, -0.6667, 1.6667)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout2.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "C3 <-> C2", "R3 <-> R2", "-5 * R2 +R4 -> R4", + "C4 <-> C3", "R4 <-> R3", "R3 / -15 -> R3", "-4 * R3 +R2 -> R2", + "-5 * R3 +R1 -> R1", "(-8.3333, x2, -0.6667, 1.6667)","Saved to file $PSScriptRoot/out2.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'single solution complex numbers' { + Remove-Item "$PSScriptRoot/out3.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout3.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in3.txt" -out "$PSScriptRoot/out3.txt" -verbose > "$PSScriptRoot/stdout3.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out3.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout3.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 / 1+2i -> R1", "1-3i * R1 +R2 -> R2", "-12.31 * R1 +R3 -> R3", + "R2 / 1.6+6.1i -> R2", "-10.4094+9.6778i * R2 +R3 -> R3", "R3 / -6.7848+9.7158i -> R3", + "0.5432-0.746i * R3 +R2 -> R2", "-0.424+0.848i * R3 +R1 -> R1", "0.74-0.38i * R2 +R1 -> R1", + "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)", "Saved to file $PSScriptRoot/out3.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no output without -verbose' { + Remove-Item "$PSScriptRoot/out4.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout4.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out4.txt" > "$PSScriptRoot/stdout4.txt" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout4.txt") + $stdoutLines.Count | Should Be 0 + } +} diff --git a/C++/analyze.sh b/C++/analyze.sh new file mode 100755 index 0000000..fe6cbcf --- /dev/null +++ b/C++/analyze.sh @@ -0,0 +1 @@ +/usr/local/llvm60/bin/scan-build -o ./report/ gmake diff --git a/C++/bin/.do_not_delete.txt b/C++/bin/.do_not_delete.txt new file mode 100644 index 0000000..e69de29 diff --git a/C++/drd.sh b/C++/drd.sh new file mode 100755 index 0000000..5d7685c --- /dev/null +++ b/C++/drd.sh @@ -0,0 +1,12 @@ +OS="`uname`" +case $OS in + 'Linux') + alias make='make' + ;; + 'FreeBSD') + alias make='gmake' + ;; + *) ;; +esac + +make clean && VALGRIND=1 make && valgrind --log-file=drd.txt --read-var-info=yes --tool=drd bin/test_cpp diff --git a/C++/helgrind.sh b/C++/helgrind.sh new file mode 100755 index 0000000..49513cd --- /dev/null +++ b/C++/helgrind.sh @@ -0,0 +1,12 @@ +OS="`uname`" +case $OS in + 'Linux') + alias make='make' + ;; + 'FreeBSD') + alias make='gmake' + ;; + *) ;; +esac + +make clean && VALGRIND=1 make && valgrind --log-file=helgrind.txt --read-var-info=yes --tool=helgrind bin/test_cpp diff --git a/C++/include/complex.hpp b/C++/include/complex.hpp new file mode 100644 index 0000000..822bb6b --- /dev/null +++ b/C++/include/complex.hpp @@ -0,0 +1,17 @@ +#ifndef COMPLEX_HPP +#define COMPLEX_HPP + +#pragma once + +#include +#include + +#include + +std::complex parse_complex (std::string s); + +bool PURE equals (const std::complex& a, const std::complex& b) noexcept; + +std::string to_string (const std::complex& c); + +#endif diff --git a/C++/include/number_solutions.hpp b/C++/include/number_solutions.hpp new file mode 100644 index 0000000..2e52e9a --- /dev/null +++ b/C++/include/number_solutions.hpp @@ -0,0 +1,18 @@ +#ifndef NUMBER_SOLUTIONS_HPP +#define NUMBER_SOLUTIONS_HPP + +#pragma once + +#include +#include + +enum class number_solutions +{ + none, + one, + many +}; + +std::ostream& operator<< (std::ostream& out, number_solutions s); + +#endif diff --git a/C++/include/parameters.hpp b/C++/include/parameters.hpp new file mode 100644 index 0000000..54f8cde --- /dev/null +++ b/C++/include/parameters.hpp @@ -0,0 +1,23 @@ +#ifndef PARAMETERS_HPP +#define PARAMETERS_HPP + +#pragma once + +#include + +#include + +class parameters +{ +private: + const char* in; + const char* out; + bool verbose; +public: + NONNULL (3) parameters (std::size_t argc, const char* const* argv) noexcept; + const char* PURE get_in() const noexcept; + const char* PURE get_out() const noexcept; + bool PURE is_verbose() const noexcept; +}; + +#endif diff --git a/C++/include/solver.hpp b/C++/include/solver.hpp new file mode 100644 index 0000000..b2c6a13 --- /dev/null +++ b/C++/include/solver.hpp @@ -0,0 +1,52 @@ +#ifndef SOLVER_HPP +#define SOLVER_HPP + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "number_solutions.hpp" + +class solver +{ +private: + std::size_t number_equations; + std::size_t number_variables; + number_solutions number_solutions_; + std::vector < std::vector>> matrix; + std::vector> solution_partial; + std::vector solution_general; + std::vector solution_indexes; + bool verbose; +public: + solver (std::istream& in, bool verbose = false); + number_solutions PURE get_number_solutions() const noexcept; + std::optional>> get_solution_general() const + noexcept; + std::optional>>> + get_solution_partial() const noexcept; + void solve(); + void write_solution_to_file (const std::string& out_filename); + +private: + void add_k_row1_to_row2 (std::complexk, std::size_t row1, std::size_t row2); + void check_that_solution_is_sane(); + void divide_row (std::size_t row, std::complex k); + void gaus_first_step(); + void gaus_second_step(); + void generate_solutions(); + void print_solution(); + void print_solution_internal (std::ostream& out); + void swap_columns (std::size_t column1, std::size_t column2); + void swap_rows (std::size_t row1, std::size_t row2); +}; + +#endif diff --git a/C++/include/util.hpp b/C++/include/util.hpp new file mode 100644 index 0000000..f186848 --- /dev/null +++ b/C++/include/util.hpp @@ -0,0 +1,10 @@ +#ifndef UTIL_HPP +#define UTIL_HPP + +#pragma once + +#include + +bool PURE NONNULL (1, 2) str_equal (const char* s1, const char* s2) noexcept; + +#endif diff --git a/C++/makefile b/C++/makefile new file mode 100644 index 0000000..7853209 --- /dev/null +++ b/C++/makefile @@ -0,0 +1,19 @@ +include mk/init.mk + +OBJ_SOLUTION_CXX += src/main.o src/number_solutions.o src/solver.o src/complex.o src/parameters.o src/util.o +OBJ_TEST_CXX += src/number_solutions.o src/solver.o src/complex.o src/parameters.o src/util.o test/main.o test/parameters.test.o test/complex.test.o test/solver.test.o + +all: test + +release: bin/solution_cpp$(EXEEXT) + +test: bin/test_cpp$(EXEEXT) + +thread_test: bin/thread_test_cpp$(EXEEXT) + +clean: clean_details + +help: help_details + +include mk/targets.mk + diff --git a/C++/mk/detect_os.mk b/C++/mk/detect_os.mk new file mode 100644 index 0000000..378b462 --- /dev/null +++ b/C++/mk/detect_os.mk @@ -0,0 +1,75 @@ +OS?= +ifeq ($(OS),Windows_NT) + PLATFORM := $(shell uname 2>NUL; false) + ifeq ($(findstring MINGW,$(PLATFORM)),MINGW) + DEL_NUL := $(shell rm -f NUL; false) + ifeq ($(findstring MINGW64,$(PLATFORM)),MINGW64) + BITS = "64" + else + BITS = "32" + endif + else + PLATFORM = "Windows" + endif +else + PLATFORM = $(shell uname) +endif + +OS_SUPPORTED = false +DOS ?= 0 + +ifeq (${DOS}, 1) + include mk/doc_gcc.mk + EXEEXT = .exe + OS_SUPPORTED = true +else + ifeq ($(findstring Haiku, $(PLATFORM)), Haiku) + include mk/haiku_clang.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring DragonFly, $(PLATFORM)), DragonFly) + include mk/dragonfly_gcc.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring NetBSD, $(PLATFORM)), NetBSD) + include mk/netbsd_gcc.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring OpenBSD, $(PLATFORM)), OpenBSD) + include mk/openbsd_clang.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring SunOS, $(PLATFORM)), SunOS) + include mk/openindiana_gcc.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring FreeBSD, $(PLATFORM)), FreeBSD) + include mk/freebsd_clang.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring Linux, $(PLATFORM)), Linux) + include mk/linux_gcc.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring MINGW, $(PLATFORM)), MINGW) + include mk/mingw_clang.mk + EXEEXT = .exe + OS_SUPPORTED = true + endif + + ifeq ($(findstring Windows, $(PLATFORM)),Windows) + $(error "install msys2: http://www.msys2.org/") + endif +endif + +ifeq ($(OS_SUPPORTED),false) + $(error "OS is not supported") +endif + diff --git a/C++/mk/disable_sanitizers_if_enabled_valgrind.mk b/C++/mk/disable_sanitizers_if_enabled_valgrind.mk new file mode 100644 index 0000000..451b4bb --- /dev/null +++ b/C++/mk/disable_sanitizers_if_enabled_valgrind.mk @@ -0,0 +1,4 @@ +ifeq ($(VALGRIND), 1) + SANITIZERS = + LIBS_SANITIZERS = +endif diff --git a/C++/mk/doc_gcc.mk b/C++/mk/doc_gcc.mk new file mode 100644 index 0000000..56b64c6 --- /dev/null +++ b/C++/mk/doc_gcc.mk @@ -0,0 +1,53 @@ +CCACHE = ccache +CC = $(CCACHE) i386-pc-msdosdjgpp-gcc +CXX = $(CCACHE) i386-pc-msdosdjgpp-g++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security \ + -Wstrict-overflow=5 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\ + -Wswitch-default -Wformat-nonliteral -Wdouble-promotion -Wnull-dereference\ + -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wchkp\ + -Wconversion -Wlogical-not-parentheses -Walloc-zero -Wcast-qual -Wrestrict\ + -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion \ + -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum -Wstack-protector \ + -Wunused-const-variable=2 -Wdangling-else -Wnonnull -Wuseless-cast \ + -Wold-style-cast -Woverloaded-virtual -Wsuggest-final-types -Weffc++ \ + -Wsuggest-final-methods -Wsuggest-override -Wzero-as-null-pointer-constant\ + -Wsubobject-linkage -Wsuggest-attribute=pure -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wmissing-noreturn -Wmissing-format-attribute\ + -Wsuggest-attribute=malloc -Wsuggest-attribute=format \ + -Wsuggest-attribute=cold \ + -Werror +WARNINGS_TESTS = + +LTO = #-flto-partition=none -flto -ffat-lto-objects +INCLUDE += -I"include" -isystem"3rd" +SECURITY = +DEFINES = -D_FORTIFY_SOURCE=2 -D__STDC_FORMAT_MACROS -DFORCE_STATIC_BOOST +DEBUG = -g3 +OPENMP = +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CXXSTANDARD = -std=gnu++1z +CSTANDARD = -std=gnu11 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = #-flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = +LIBS_SYSTEM = -lm +LIBS_THREAD = +LIBS_3RD = +LIBS_TEST = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/C++/mk/dragonfly_gcc.mk b/C++/mk/dragonfly_gcc.mk new file mode 100644 index 0000000..d0a967c --- /dev/null +++ b/C++/mk/dragonfly_gcc.mk @@ -0,0 +1,48 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CXX = $(CCACHE) g++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security \ + -Wstrict-overflow=5 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\ + -Wswitch-default -Wformat-nonliteral -Wdouble-promotion -Wnull-dereference\ + -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wchkp\ + -Wconversion -Wlogical-not-parentheses -Walloc-zero -Wcast-qual -Wrestrict\ + -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion \ + -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum -Wstack-protector \ + -Wunused-const-variable=2 -Wdangling-else -Wnonnull -Wuseless-cast \ + -Wold-style-cast -Woverloaded-virtual -Wsuggest-final-types -Weffc++ \ + -Wsuggest-final-methods -Wsuggest-override -Wzero-as-null-pointer-constant\ + -Wsubobject-linkage -Werror +WARNINGS_TESTS = + +LTO = -flto-partition=none -flto -ffat-lto-objects +INCLUDE = -I"include" -isystem"3rd" -isystem"/usr/local/include/" +SECURITY = +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CXXSTANDARD = -std=c++1z + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = -flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = -L"/usr/local/lib" +LD_SECURITY = +LD_SYSTEM = -Wl,-O1 -rdynamic + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread -Wl,--no-as-needed -lpthread +LIBS_3RD = +LIBS_TEST = -lboost_unit_test_framework + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/C++/mk/freebsd_clang.mk b/C++/mk/freebsd_clang.mk new file mode 100644 index 0000000..6475251 --- /dev/null +++ b/C++/mk/freebsd_clang.mk @@ -0,0 +1,38 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CXX = $(CCACHE) clang++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-tautological-pointer-compare -Wno-covered-switch-default -Werror +WARNINGS_TESTS = -Wno-disabled-macro-expansion -Wno-global-constructors + +INCLUDE = -I"include" -isystem"3rd" -isystem"/usr/local/include/" +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations +CXXSTANDARD = -std=c++1z + +SANITIZERS = -fsanitize=address -fsanitize=undefined -fsanitize=leak -fno-omit-frame-pointer +THREAD_SANITIZER = -fsanitize=thread -fno-omit-frame-pointer + +LD_LTO = +LD_INCLUDE = -L"/usr/local/lib" +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp=libiomp5 +LIBS_SYSTEM = +LIBS_THREAD = -pthread +LIBS_3RD = +LIBS_TEST = -lboost_unit_test_framework + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/C++/mk/haiku_clang.mk b/C++/mk/haiku_clang.mk new file mode 100644 index 0000000..7bd64dd --- /dev/null +++ b/C++/mk/haiku_clang.mk @@ -0,0 +1,38 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CXX = $(CCACHE) clang++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-tautological-pointer-compare -Wno-covered-switch-default -Werror +WARNINGS_TESTS = -Wno-disabled-macro-expansion -Wno-global-constructors + +INCLUDE = -I"include" -isystem"3rd" -isystem "/boot/system/develop/headers/x86/c++" -isystem"/boot/system/develop/headers/x86/c++/i586-pc-haiku" +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations +CXXSTANDARD = -std=c++1z + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = +LIBS_SYSTEM = +LIBS_THREAD = +LIBS_3RD = +LIBS_TEST = -lboost_unit_test_framework + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/C++/mk/init.mk b/C++/mk/init.mk new file mode 100644 index 0000000..0b16e83 --- /dev/null +++ b/C++/mk/init.mk @@ -0,0 +1,24 @@ +VALGRIND ?= 0 +EXEEXT = + +OBJ_PLATFORM_SPECIFIC_CXX = + +OBJ_SOLUTION_CXX = $(OBJ_PLATFORM_SPECIFIC_CXX) + +OBJ_TEST_CXX = + +OBJS = $(OBJ_TEST_CXX) $(OBJ_SOLUTION_CXX) + +include mk/detect_os.mk +include mk/optional_ccache.mk +include mk/disable_sanitizers_if_enabled_valgrind.mk + +COMPILE.cpp = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c + +%.o : %.cpp +%.o : %.cpp %.d + $(COMPILE.cpp) $(OUTPUT_OPTION) $< + +%.d: ; +.PRECIOUS: %.d + diff --git a/C++/mk/linux_gcc.mk b/C++/mk/linux_gcc.mk new file mode 100644 index 0000000..614229f --- /dev/null +++ b/C++/mk/linux_gcc.mk @@ -0,0 +1,53 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CXX = $(CCACHE) g++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security \ + -Wstrict-overflow=5 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\ + -Wswitch-default -Wformat-nonliteral -Wdouble-promotion -Wnull-dereference\ + -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wchkp\ + -Wconversion -Wlogical-not-parentheses -Walloc-zero -Wcast-qual -Wrestrict\ + -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion \ + -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum -Wstack-protector \ + -Wunused-const-variable=2 -Wdangling-else -Wnonnull -Wuseless-cast \ + -Wold-style-cast -Woverloaded-virtual -Wsuggest-final-types -Weffc++ \ + -Wsuggest-final-methods -Wsuggest-override -Wzero-as-null-pointer-constant\ + -Wsubobject-linkage -Wsuggest-attribute=pure -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wmissing-noreturn -Wmissing-format-attribute\ + -Wsuggest-attribute=malloc -Wsuggest-attribute=format \ + -Wsuggest-attribute=cold \ + -Werror +WARNINGS_TESTS = + +LTO = -flto-partition=none -flto -ffat-lto-objects +INCLUDE = -I"include" -isystem"3rd" +SECURITY = -fPIC -fstack-protector-all --param ssp-buffer-size=4 -fstack-check\ + -mindirect-branch=thunk -fPIE -Wa,--noexecstack +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CXXSTANDARD = -std=c++1z + +SANITIZERS = -fsanitize=address -fsanitize=undefined -fsanitize=leak -fno-omit-frame-pointer +THREAD_SANITIZER = -fsanitize=thread -fno-omit-frame-pointer + +LD_LTO = -flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = +LD_SECURITY = -pie -Wl,-z,relro,-z,now -Wl,-z,noexecstack +LD_SYSTEM = -Wl,-O1 -rdynamic + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread -Wl,--no-as-needed -lpthread +LIBS_3RD = +LIBS_TEST = -lboost_unit_test_framework + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/C++/mk/mingw_clang.mk b/C++/mk/mingw_clang.mk new file mode 100644 index 0000000..a9072a8 --- /dev/null +++ b/C++/mk/mingw_clang.mk @@ -0,0 +1,38 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CXX = $(CCACHE) clang++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-tautological-pointer-compare -Wno-covered-switch-default -Werror +WARNINGS_TESTS = -Wno-disabled-macro-expansion -Wno-global-constructors + +INCLUDE = -I"include" -isystem"3rd" +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations +CXXSTANDARD = -std=c++1z + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp=libiomp5 +LIBS_SYSTEM = +LIBS_THREAD = +LIBS_3RD = +LIBS_TEST = -lboost_unit_test_framework-mt + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/C++/mk/netbsd_gcc.mk b/C++/mk/netbsd_gcc.mk new file mode 100644 index 0000000..50b6d05 --- /dev/null +++ b/C++/mk/netbsd_gcc.mk @@ -0,0 +1,47 @@ +CCACHE = ccache +CC = $(CCACHE) /usr/pkg/gcc8/bin/gcc +CXX = $(CCACHE) /usr/pkg/gcc8/bin/g++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security \ + -Wstrict-overflow=5 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\ + -Wswitch-default -Wformat-nonliteral -Wdouble-promotion -Wnull-dereference\ + -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wchkp\ + -Wconversion -Wlogical-not-parentheses -Walloc-zero -Wcast-qual -Wrestrict\ + -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion \ + -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum \ + -Wunused-const-variable=2 -Wdangling-else -Wnonnull -Wuseless-cast \ + -Wold-style-cast -Woverloaded-virtual -Wsuggest-final-types -Weffc++ \ + -Wsuggest-final-methods -Wsuggest-override -Wzero-as-null-pointer-constant\ + -Wsubobject-linkage -Werror +WARNINGS_TESTS = + +LTO = -flto-partition=none -flto -ffat-lto-objects +INCLUDE = -I"include" -isystem"3rd" -isystem"/usr/pkg/include" +SECURITY = +DEFINES = -D_FORTIFY_SOURCE=2 -DFORCE_STATIC_BOOST +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CXXSTANDARD = -std=c++1z + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = -flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = -L"/usr/pkg/lib" +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread -Wl,--no-as-needed -lpthread +LIBS_3RD = +LIBS_TEST = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/C++/mk/openbsd_clang.mk b/C++/mk/openbsd_clang.mk new file mode 100644 index 0000000..35e98a9 --- /dev/null +++ b/C++/mk/openbsd_clang.mk @@ -0,0 +1,38 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CXX = $(CCACHE) clang++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-tautological-pointer-compare -Wno-covered-switch-default -Werror +WARNINGS_TESTS = -Wno-disabled-macro-expansion -Wno-global-constructors + +INCLUDE = -I"include" -isystem"3rd" -isystem"/usr/local/include/" +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations +CXXSTANDARD = -std=c++1z + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = -L"/usr/local/lib" +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp=libiomp5 +LIBS_SYSTEM = +LIBS_THREAD = -pthread +LIBS_3RD = +LIBS_TEST = -lboost_unit_test_framework + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/C++/mk/openindiana_gcc.mk b/C++/mk/openindiana_gcc.mk new file mode 100644 index 0000000..ec642ab --- /dev/null +++ b/C++/mk/openindiana_gcc.mk @@ -0,0 +1,49 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CXX = $(CCACHE) g++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security \ + -Wstrict-overflow=5 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\ + -Wswitch-default -Wformat-nonliteral -Wdouble-promotion -Wnull-dereference\ + -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wchkp\ + -Wconversion -Wlogical-not-parentheses -Walloc-zero -Wcast-qual -Wrestrict\ + -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion \ + -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum -Wstack-protector \ + -Wunused-const-variable=2 -Wdangling-else -Wnonnull -Wuseless-cast \ + -Wold-style-cast -Woverloaded-virtual -Wsuggest-final-types -Weffc++ \ + -Wsuggest-final-methods -Wsuggest-override -Wzero-as-null-pointer-constant\ + -Wsubobject-linkage -Werror +WARNINGS_TESTS = + +LTO = +INCLUDE = -I"include" -isystem"3rd" +SECURITY = + +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CXXSTANDARD = -std=c++1z + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread +LIBS_3RD = +LIBS_TEST = -lboost_unit_test_framework + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/C++/mk/optional_ccache.mk b/C++/mk/optional_ccache.mk new file mode 100644 index 0000000..2b7ace5 --- /dev/null +++ b/C++/mk/optional_ccache.mk @@ -0,0 +1,4 @@ +CCACHE_VER := $(shell $(CCACHE) -V 2>/dev/null; false) +ifeq ($(CCACHE_VER),) + CCACHE = +endif diff --git a/C++/mk/targets.mk b/C++/mk/targets.mk new file mode 100644 index 0000000..13e64bd --- /dev/null +++ b/C++/mk/targets.mk @@ -0,0 +1,41 @@ +./bin/solution_cpp$(EXEEXT): $(OBJ_SOLUTION_CXX) + $(CXX) -o $@ $^ $(LDFLAGS) $(LIBS) + +./bin/debug_cpp$(EXEEXT): CXXFLAGS += $(SANITIZERS) +./bin/debug_cpp$(EXEEXT): $(OBJ_SOLUTION_CXX) + $(CXX) -o $@ $^ $(LDFLAGS) $(LIBS) $(SANITIZERS) + +./bin/thread_debug_cpp$(EXEEXT): CXXFLAGS += $(THREAD_SANITIZER) +./bin/thread_debug_cpp$(EXEEXT): $(OBJ_SOLUTION_CXX) + $(CXX) -o $@ $^ $(LDFLAGS) $(LIBS) $(THREAD_SANITIZER) + +./bin/test_cpp$(EXEEXT): CXXFLAGS += $(SANITIZERS) $(WARNINGS_TESTS) +./bin/test_cpp$(EXEEXT): $(OBJ_TEST_CXX) + $(CXX) -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_TEST) $(SANITIZERS) + +./bin/thread_test_cpp$(EXEEXT): CXXFLAGS += $(THREAD_SANITIZER) $(WARNINGS_TESTS) +./bin/thread_test_cpp$(EXEEXT): $(OBJ_TEST_CXX) + $(CXX) -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_TEST) $(THREAD_SANITIZER) + +clean_details: + find . -name "*.o" ! -path "./.git/*" ! -path "./msvc2017/*" -type f -delete + find . -name "*.d" ! -path "./.git/*" ! -path "./msvc2017/*" -type f -delete + find . -name "*.orig" ! -path "./.git/*" ! -path "./msvc2017/*" -type f -delete + rm -f "bin/solution_cpp$(EXEEXT)" + rm -f "bin/debug_cpp$(EXEEXT)" + rm -f "bin/thread_debug_cpp$(EXEEXT)" + rm -f "bin/test_cpp$(EXEEXT)" + rm -f "bin/thread_test_cpp$(EXEEXT)" + +help_details: + @echo "The following are some of the valid targets for this makefile:" + @echo " all (the default if no target is provided)(=test)" + @echo " release" + @echo " test (with msan)" + @echo " thread_test (searching thread races with tsan)" + @echo " clean" + @echo " help" + +.PHONY: all force_cpp release debug thread_debug help help_details clean clean_details + +include $(wildcard $(patsubst %, %.d,$(basename $(OBJS)))) diff --git a/C++/msvc2017/Solution/Solution/Solution.ruleset b/C++/msvc2017/Solution/Solution/Solution.ruleset new file mode 100644 index 0000000..be233f5 --- /dev/null +++ b/C++/msvc2017/Solution/Solution/Solution.ruleset @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/C++/msvc2017/Solution/Solution/Solution.vcxproj b/C++/msvc2017/Solution/Solution/Solution.vcxproj new file mode 100644 index 0000000..43f0a4a --- /dev/null +++ b/C++/msvc2017/Solution/Solution/Solution.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {5716832B-1FBD-40FA-B9C3-5A981F75023B} + Solution + 10.0.16299.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + Solution.ruleset + true + + + Solution.ruleset + true + + + Solution.ruleset + + + Solution.ruleset + + + + Level4 + MaxSpeed + true + true + true + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + Speed + true + Fast + true + stdcpp17 + true + + + true + true + Console + + + + + Level4 + Disabled + true + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + + + Console + + + + + Level4 + Disabled + true + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + + + Console + + + + + Level4 + MaxSpeed + true + true + true + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + Speed + true + Fast + true + stdcpp17 + true + + + true + true + Console + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/C++/msvc2017/Solution/Solution/Solution.vcxproj.filters b/C++/msvc2017/Solution/Solution/Solution.vcxproj.filters new file mode 100644 index 0000000..df4b663 --- /dev/null +++ b/C++/msvc2017/Solution/Solution/Solution.vcxproj.filters @@ -0,0 +1,54 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + + + Файлы заголовков + + + Файлы заголовков + + + Файлы заголовков + + + Файлы заголовков + + + + + + \ No newline at end of file diff --git a/C++/msvc2017/Test/Test.sln b/C++/msvc2017/Test/Test.sln new file mode 100644 index 0000000..4f3b0f9 --- /dev/null +++ b/C++/msvc2017/Test/Test.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27520.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{A7F93A37-D503-4669-AE95-CE0A247A9EF0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Solution", "..\Solution\Solution\Solution.vcxproj", "{5716832B-1FBD-40FA-B9C3-5A981F75023B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x64.ActiveCfg = Debug|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x64.Build.0 = Debug|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x86.ActiveCfg = Debug|Win32 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x86.Build.0 = Debug|Win32 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x64.ActiveCfg = Release|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x64.Build.0 = Release|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x86.ActiveCfg = Release|Win32 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x86.Build.0 = Release|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x64.ActiveCfg = Debug|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x64.Build.0 = Debug|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x86.ActiveCfg = Debug|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x86.Build.0 = Debug|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x64.ActiveCfg = Release|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x64.Build.0 = Release|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x86.ActiveCfg = Release|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DE43A559-CB9E-40B7-8806-BF60F337E07F} + EndGlobalSection +EndGlobal diff --git a/C++/msvc2017/Test/Test/Test.vcxproj b/C++/msvc2017/Test/Test/Test.vcxproj new file mode 100644 index 0000000..cac32ef --- /dev/null +++ b/C++/msvc2017/Test/Test/Test.vcxproj @@ -0,0 +1,198 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + 15.0 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0} + Win32Proj + Test + 10.0.16299.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + AllRules.ruleset + true + + + true + AllRules.ruleset + true + + + NativeRecommendedRules.ruleset + true + + + NativeRecommendedRules.ruleset + true + + + + NotUsing + Level4 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + Caret + + + Console + true + + + + + NotUsing + Level4 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + Caret + + + Console + true + + + + + NotUsing + Level4 + MaxSpeed + true + true + WIN32;_CONSOLE;%(PreprocessorDefinitions) + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + Caret + true + true + true + Speed + true + Fast + + + Console + true + true + true + + + + + NotUsing + Level4 + MaxSpeed + true + true + _CONSOLE;%(PreprocessorDefinitions) + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + Caret + true + true + true + Speed + true + Fast + + + Console + true + true + true + + + + + \ No newline at end of file diff --git a/C++/msvc2017/Test/Test/Test.vcxproj.filters b/C++/msvc2017/Test/Test/Test.vcxproj.filters new file mode 100644 index 0000000..04fda8c --- /dev/null +++ b/C++/msvc2017/Test/Test/Test.vcxproj.filters @@ -0,0 +1,60 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + + + Файлы заголовков + + + Файлы заголовков + + + Файлы заголовков + + + Файлы заголовков + + + \ No newline at end of file diff --git a/C++/report/.do_not_delete.txt b/C++/report/.do_not_delete.txt new file mode 100644 index 0000000..e69de29 diff --git a/C++/runastyle.sh b/C++/runastyle.sh new file mode 100755 index 0000000..7e7d8f1 --- /dev/null +++ b/C++/runastyle.sh @@ -0,0 +1,23 @@ +H_FILES_NUMBER=`find include -type f -name "*.h" -printf x 2> /dev/null | wc -c` +HPP_FILES_NUMBER=`find include -type f -name "*.hpp" -printf x 2> /dev/null | wc -c` + +CPP_FILES_NUMBER=`find src -type f -name "*.cpp" -printf x 2> /dev/null | wc -c` +TEST_CPP_FILES_NUMBER=`find test -type f -name "*.cpp" -printf x 2> /dev/null | wc -c` + +ASTYLE="astyle --style=allman --pad-oper --pad-first-paren-out --align-pointer=type --align-reference=type --lineend=windows --max-code-length=100 --indent-namespaces --convert-tabs" + +if [ $CPP_FILES_NUMBER -gt 0 ]; then + $ASTYLE --recursive "src/*.cpp" +fi + +if [ $H_FILES_NUMBER -gt 0 ]; then + $ASTYLE --recursive "include/*.h" +fi + +if [ $HPP_FILES_NUMBER -gt 0 ]; then + $ASTYLE --recursive "include/*.hpp" +fi + +if [ $TEST_CPP_FILES_NUMBER -gt 0 ]; then + $ASTYLE --recursive "test/*.cpp" +fi diff --git a/C++/src/complex.cpp b/C++/src/complex.cpp new file mode 100644 index 0000000..52ff5e7 --- /dev/null +++ b/C++/src/complex.cpp @@ -0,0 +1,143 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "complex.hpp" + +#include +#include +#include +#include + +#include "util.hpp" + +using std::abs; +using std::complex; +using std::sscanf; +using std::string; +using std::istringstream; +using std::ostringstream; +using std::runtime_error; +using std::size_t; +#ifndef __DJGPP__ +using std::round; +#endif + +constexpr double EPSILON = 0.00001; + +static void restore_omitted_imaginary_coefficient (string& s) +{ + if (s == "i") + { + s = "1i"; + } + const string plus_i = "+i"; + const string minus_i = "-i"; + size_t found = s.find (plus_i); + if (found != string::npos) + { + s.replace (found, plus_i.size(), "+1i"); + } + else + { + found = s.find (minus_i); + if (found != string::npos) + { + s.replace (found, minus_i.size(), "-1i"); + } + } +} + +#ifdef _LIBCPP_VERSION +/* в libc++ по другому устроена логика чтения из стрима, чем в libstdc++ и стандартной библиотеки от Microsoft +* подробнее: https://bugs.llvm.org/show_bug.cgi?id=17782 +*/ +complex parse_complex (string s) +{ + restore_omitted_imaginary_coefficient (s); + double real = 0.0; + double imag = 0.0; + char c[3] = {0}; + int result = sscanf (s.c_str(), "%lg%lg%2s", &real, &imag, c); + if (result != 3) + { + real = 0.0; + result = sscanf (s.c_str(), "%lg%2s", &imag, c); + if (result != 2) + { + c[0] = '\0'; + imag = 0.0; + result = sscanf (s.c_str(), "%lg", &real); + if (result == 1) + { + c[0] = 'i'; + c[1] = '\0'; + } + } + } + if (!str_equal (c, "i")) + { + throw runtime_error ("can't parse complex"); + } + return complex (real, imag); +} +#else +complex parse_complex (string s) +{ + restore_omitted_imaginary_coefficient (s); + double real = 0.0; + double imag = 0.0; + istringstream in (s); + in.exceptions (istringstream::failbit | istringstream::badbit); + in >> real; + const int next_character = in.eof() ? EOF : in.get(); + switch (next_character) + { + case 'i': + if (in.peek() != EOF) + { + throw runtime_error ("can't parse complex"); + } + imag = real; + real = 0.0; + break; + case EOF: + break; + default: + in.unget(); + in >> imag; + const int last_character = in.get(); + if (last_character != 'i' || in.peek() != EOF) + { + throw runtime_error ("can't parse complex"); + } + break; + } + return complex (real, imag); +} +#endif + +bool equals (const complex& a, const complex& b) noexcept +{ + return abs (a.imag() - b.imag()) < EPSILON && abs (a.real() - b.real()) < EPSILON; +} + +string to_string (const complex& c) +{ + ostringstream ss; + const double real = round (c.real() * 10000.0) / 10000.0; + const double imag = round (c.imag() * 10000.0) / 10000.0; + if (abs (imag) < EPSILON) + { + ss << real; + } + else if (abs (real) < EPSILON) + { + ss << imag << "i"; + } + else + { + const char* prefix = imag > 0 ? "+" : ""; + ss << real << prefix << imag << "i"; + } + + return ss.str(); +} diff --git a/C++/src/main.cpp b/C++/src/main.cpp new file mode 100644 index 0000000..a502e2b --- /dev/null +++ b/C++/src/main.cpp @@ -0,0 +1,38 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include +#include +#include +#include + +#include "parameters.hpp" +#include "solver.hpp" + +using std::cerr; +using std::ifstream; +using std::endl; +using std::exception; +using std::size_t; +using std::runtime_error; + +int main (int argc, char* argv[]) +{ + try + { + const parameters p (static_cast (argc), argv); + ifstream in (p.get_in()); + if (!in.is_open()) + { + throw runtime_error ("can't open -in file"); + } + solver s (in, p.is_verbose()); + s.solve(); + s.write_solution_to_file (p.get_out()); + } + catch (const exception& e) + { + cerr << "An exception occurs " << e.what() << endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/C++/src/number_solutions.cpp b/C++/src/number_solutions.cpp new file mode 100644 index 0000000..e7db6eb --- /dev/null +++ b/C++/src/number_solutions.cpp @@ -0,0 +1,26 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "number_solutions.hpp" + +using std::ostream; + +ostream& operator<< (ostream& out, number_solutions s) +{ + switch (s) + { + case number_solutions::none: + out << "number_solutions::none"; + break; + case number_solutions::one: + out << "number_solutions::one"; + break; + case number_solutions::many: + out << "number_solutions::many"; + break; + default: + assert (false); + break; + } + + return out; +} diff --git a/C++/src/parameters.cpp b/C++/src/parameters.cpp new file mode 100644 index 0000000..b3a54ba --- /dev/null +++ b/C++/src/parameters.cpp @@ -0,0 +1,61 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "parameters.hpp" + +#include + +#include "util.hpp" + +using std::size_t; + +parameters::parameters (size_t argc, const char* const* argv) noexcept + : in ("input.txt") + , out ("output.txt") + , verbose (false) +{ + assert (argv != nullptr); + + bool need_assigned_in = true; + bool need_assigned_out = true; + for (size_t i = 0; i < argc; ++i) + { + assert (argv[i] != nullptr); + if (need_assigned_in && str_equal (argv[i], "-in")) + { + if (i < (argc - 1)) + { + in = argv[i + 1]; + need_assigned_in = false; + ++i; + } + } + else if (need_assigned_out && str_equal (argv[i], "-out")) + { + if (i < argc - 1) + { + out = argv[i + 1]; + need_assigned_out = false; + ++i; + } + } + else if (!verbose && str_equal (argv[i], "-verbose")) + { + verbose = true; + } + } +} + +const char* parameters::get_in() const noexcept +{ + return in; +} + +const char* parameters::get_out() const noexcept +{ + return out; +} + +bool parameters::is_verbose() const noexcept +{ + return verbose; +} diff --git a/C++/src/solver.cpp b/C++/src/solver.cpp new file mode 100644 index 0000000..40501d7 --- /dev/null +++ b/C++/src/solver.cpp @@ -0,0 +1,392 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "solver.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "complex.hpp" + +using std::cout; +using std::endl; +using std::iota; +using std::istream; +using std::string; +using std::isdigit; +using std::isspace; +using std::size_t; +using std::complex; +using std::nullopt; +using std::uint32_t; +using std::ifstream; +using std::vector; +using std::optional; +using std::ofstream; +using std::ostream; +using std::swap; +using std::runtime_error; +using std::reference_wrapper; +using std::cref; + +constexpr complex ZERO (0.0, 0.0); +constexpr complex ONE (1.0, 0.0); +constexpr complex MINUS_ONE (-1.0, 0.0); + +solver::solver (istream& in, bool verbose_ /* = false */) + : number_equations (0) + , number_variables (0) + , number_solutions_ (number_solutions::one) + , matrix() + , solution_partial() + , solution_general() + , solution_indexes() + , verbose (verbose_) +{ + static_assert (SIZE_MAX >= UINT32_MAX); + + in.exceptions (istream::failbit | istream::badbit); + const auto check = [&]() + { + int next_character = ' '; + while (isspace (next_character)) + { + next_character = in.get(); + } + if (! (next_character == '+' || isdigit (next_character) != 0)) + { + throw runtime_error ("wrong data"); + } + in.unget(); + }; + check(); + uint32_t temp_number_variables; + in >> temp_number_variables; + number_variables = CAST_UINT32_TO_SIZE_T (temp_number_variables); + check(); + uint32_t temp_real_number_equations; + in >> temp_real_number_equations; + const size_t real_number_equations = CAST_UINT32_TO_SIZE_T (temp_real_number_equations); + if (number_variables < 1 || real_number_equations < 1) + { + throw runtime_error ("wrong input data"); + } + number_equations = (real_number_equations < number_variables) ? number_variables : + real_number_equations; + matrix.resize (number_equations); + for (size_t i = 0; i < real_number_equations; ++i) + { + matrix.at (i).resize (number_variables + 1); + for (auto& matrix_el : matrix.at (i)) + { + string temp; + in >> temp; + matrix_el = parse_complex (temp); + } + } + for (size_t i = real_number_equations; i < number_equations; ++i) + { + matrix.at (i).resize (number_variables + 1); + } + solution_partial.resize (number_variables); + solution_general.resize (number_variables); + solution_indexes.resize (number_variables); + iota (solution_indexes.begin(), solution_indexes.end(), 0); +} + +number_solutions solver::get_number_solutions() const noexcept +{ + return number_solutions_; +} + +optional>> solver::get_solution_general() const noexcept +{ + if (number_solutions_ != number_solutions::many) + { + return nullopt; + } + + return cref (solution_general); +} + +optional>>> solver::get_solution_partial() const +noexcept +{ + if (number_solutions_ == number_solutions::none) + { + return nullopt; + } + + return cref (solution_partial); +} + +void solver::solve() +{ + if (verbose) + { + cout << "Start solving the equation.\n" << "Rows manipulation:" << endl; + } + gaus_first_step(); + if (number_solutions_ != number_solutions::none) + { + gaus_second_step(); + generate_solutions(); + check_that_solution_is_sane(); + } + print_solution(); +} + +void solver::write_solution_to_file (const string& out_filename) +{ + ofstream out (out_filename); + print_solution_internal (out); + if (verbose) + { + cout << "Saved to file " << out_filename << endl; + } +} + +void solver::add_k_row1_to_row2 (complexk, size_t row1, size_t row2) +{ + if (verbose) + { + cout << to_string (k) << " * R" << CAST_SIZE_T_TO_UINT32 (row1 + 1) << " +R" + << CAST_SIZE_T_TO_UINT32 (row2 + 1) << " -> R" << CAST_SIZE_T_TO_UINT32 (row2 + 1) << endl; + } + for (size_t i = 0; i < number_variables + 1; ++i) + { + matrix.at (row2).at (i) += k * matrix.at (row1).at (i); + } +} + +void solver::check_that_solution_is_sane() +{ + for (size_t i = number_variables; i < number_equations; ++i) + { + complex sum (0.0, 0.0); + for (size_t j = 0; j < number_variables; ++j) + { + sum += solution_partial.at (solution_indexes.at (j)) * matrix.at (i).at (solution_indexes.at (j)); + } + if (!equals (sum, matrix.at (i).at (number_variables))) + { + number_solutions_ = number_solutions::none; + return; + } + } +} + +void solver::divide_row (size_t row, complex k) +{ + if (verbose) + { + cout << "R" << CAST_SIZE_T_TO_UINT32 (row + 1) << " / " << to_string (k) + << " -> R" << CAST_SIZE_T_TO_UINT32 (row + 1) << endl; + } + for (auto& matrix_el : matrix.at (row)) + { + matrix_el /= k; + } +} + +void solver::gaus_first_step() +{ + for (size_t i = 0; i < number_variables; ++i) + { + if (equals (matrix.at (i).at (i), ZERO)) + { + bool found_non_zero_element = false; + for (size_t j = i + 1; j < number_equations; ++j) + { + if (!equals (matrix.at (j).at (i), ZERO)) + { + swap_rows (i, j); + found_non_zero_element = true; + break; + } + } + if (!found_non_zero_element) + { + for (size_t j = i + 1; j < number_variables; ++j) + { + if (!equals (matrix.at (i).at (j), ZERO)) + { + swap_columns (i, j); + found_non_zero_element = true; + break; + } + } + } + + if (!found_non_zero_element) + { + for (size_t k = i + 1; !found_non_zero_element && k < number_variables; ++k) + { + for (size_t j = i + 1; j < number_equations; ++j) + { + if (!equals (matrix.at (j).at (k), ZERO)) + { + swap_columns (k, i); + swap_rows (j, i); + found_non_zero_element = true; + break; + } + } + } + } + + if (!found_non_zero_element) + { + if (equals (matrix.at (i).at (number_variables), ZERO)) + { + number_solutions_ = number_solutions::many; + continue; + } + else + { + number_solutions_ = number_solutions::none; + return; + } + } + } + + if (!equals (matrix.at (i).at (i), ONE)) + { + divide_row (i, matrix.at (i).at (i)); + } + for (size_t j = i + 1; j < number_equations && j < number_variables; ++j) + { + const complex k = MINUS_ONE * matrix.at (j).at (i); + if (!equals (k, ZERO)) + { + add_k_row1_to_row2 (k, i, j); + } + } + } +} + +void solver::gaus_second_step() +{ + for (size_t i = number_variables - 1; true; --i) + { + if (i == 0) + { + break; + } + for (size_t j = i - 1; true; --j) + { + const complex k = MINUS_ONE * matrix.at (j).at (i); + if (!equals (k, ZERO)) + { + add_k_row1_to_row2 (k, i, j); + } + if (j == 0) + { + break; + } + } + } +} + +void solver::generate_solutions() +{ + for (size_t i = 0; i < number_equations && i < number_variables; ++i) + { + auto& matrix_i = matrix.at (i); + solution_partial.at (solution_indexes.at (i)) = matrix_i.at (number_variables); + if (equals (matrix_i.at (i), ZERO)) + { + solution_general.at (solution_indexes.at (i)) = "x" + std::to_string (solution_indexes.at ( + i) + 1ULL); + } + else + { + solution_general.at (solution_indexes.at (i)) = to_string (matrix_i.at (number_variables)); + for (size_t j = i + 1; j < number_variables; ++j) + { + if (equals (matrix_i.at (j), ONE)) + { + solution_general.at (solution_indexes.at (i)) += " - x" + std::to_string (solution_indexes.at ( + j) + 1ULL); + } + else if (!equals (matrix_i.at (j), ZERO)) + { + solution_general.at (solution_indexes.at (i)) += " - x" + std::to_string (solution_indexes.at ( + j) + 1ULL) + " * (" + to_string (matrix_i.at (j)) + ")"; + } + } + } + } +} + +void solver::print_solution() +{ + if (verbose) + { + print_solution_internal (cout); + } +} + +void solver::print_solution_internal (ostream& out) +{ + switch (number_solutions_) + { + case number_solutions::none: + out << "There are no solutions" << endl; + break; + case number_solutions::one: + out << "(" << to_string (solution_partial.at (0)); + for (size_t i = 1; i < solution_partial.size(); ++i) + { + out << ", " << to_string (solution_partial.at (i)); + } + out << ")" << endl; + break; + case number_solutions::many: + out << "(" << solution_general.at (0); + for (size_t i = 1; i < solution_partial.size(); ++i) + { + out << ", " << solution_general.at (i); + } + out << ")" << endl; + break; + default: + assert (false); + break; + } +} + +void solver::swap_columns (size_t column1, size_t column2) +{ + if (verbose) + { + cout << "C" << CAST_SIZE_T_TO_UINT32 (column1 + 1) << " <-> C" + << CAST_SIZE_T_TO_UINT32 (column2 + 1) << endl; + } + const auto n = matrix.size(); + for (size_t i = 0; i < n; ++i) + { + swap (matrix.at (i).at (column1), matrix.at (i).at (column2)); + } + swap (solution_indexes.at (column1), solution_indexes.at (column2)); +} + +void solver::swap_rows (size_t row1, size_t row2) +{ + if (verbose) + { + cout << "R" << CAST_SIZE_T_TO_UINT32 (row1 + 1) << " <-> R" << CAST_SIZE_T_TO_UINT32 ( + row2 + 1) << endl; + } + for (size_t i = 0; i < number_variables + 1; ++i) + { + swap (matrix.at (row1).at (i), matrix.at (row2).at (i)); + } +} diff --git a/C++/src/util.cpp b/C++/src/util.cpp new file mode 100644 index 0000000..77b7f62 --- /dev/null +++ b/C++/src/util.cpp @@ -0,0 +1,25 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "util.hpp" + +#include +#include + +using std::size_t; +using std::strcmp; +using std::strlen; + +bool NONNULL (1, 2) str_equal (const char* s1, const char* s2) noexcept +{ + assert (s1 != nullptr); + assert (s2 != nullptr); + + const size_t s1_length = strlen (s1); + const size_t s2_length = strlen (s2); + if (s1_length == s2_length) + { + return strcmp (s1, s2) == 0; + } + + return false; +} diff --git a/C++/test/complex.test.cpp b/C++/test/complex.test.cpp new file mode 100644 index 0000000..65b474c --- /dev/null +++ b/C++/test/complex.test.cpp @@ -0,0 +1,248 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include + +#include "complex.hpp" + +using std::complex; +using std::string; +using std::exception; + +BOOST_AUTO_TEST_CASE (complex_toString1) +{ + const complex a (1.0, 0.0); + const string expected ("1"); + const string actual = to_string (a); + + BOOST_CHECK_EQUAL (expected, actual); +} + +BOOST_AUTO_TEST_CASE (complex_toString2) +{ + const complex a (0.0, 1.0); + const string expected ("1i"); + const string actual = to_string (a); + + BOOST_CHECK_EQUAL (expected, actual); +} + +BOOST_AUTO_TEST_CASE (complex_toString3) +{ + const complex a (-2.4, 1.5); + const string expected ("-2.4+1.5i"); + const string actual = to_string (a); + + BOOST_CHECK_EQUAL (expected, actual); +} + +BOOST_AUTO_TEST_CASE (complex_toString4) +{ + const complex a (2.4, -1.5); + const string expected ("2.4-1.5i"); + const string actual = to_string (a); + + BOOST_CHECK_EQUAL (expected, actual); +} + +BOOST_AUTO_TEST_CASE (complex_toString5) +{ + const complex a (0.0, 0.0); + const string expected ("0"); + const string actual = to_string (a); + + BOOST_CHECK_EQUAL (expected, actual); +} + +BOOST_AUTO_TEST_CASE (complex_equals1) +{ + const complex a (1.0, 2.0); + const complex b (1.0, 2.0); + + BOOST_CHECK (equals (a, b)); +} + +BOOST_AUTO_TEST_CASE (complex_equals2) +{ + const complex a (1.0, 2.0); + const complex b (1.1, 2.0); + + BOOST_CHECK (!equals (a, b)); +} + +BOOST_AUTO_TEST_CASE (complex_equals3) +{ + const complex a (1.0, 2.1); + const complex b (1.0, 2.0); + + BOOST_CHECK (!equals (a, b)); +} + +BOOST_AUTO_TEST_CASE (complex_parse1) +{ + try + { + const complexa = parse_complex ("gbc"); + (void)a; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (complex_parse2) +{ + const complex actual = parse_complex ("-1.3"); + const complex expected (-1.3, 0.0); + + BOOST_CHECK (equals (actual, expected)); +} + +BOOST_AUTO_TEST_CASE (complex_parse3) +{ + const complex actual = parse_complex ("2.5i"); + const complex expected (0.0, 2.5); + + BOOST_CHECK (equals (actual, expected)); +} + +BOOST_AUTO_TEST_CASE (complex_parse4) +{ + const complex actual = parse_complex ("1.3-2.5i"); + const complex expected (1.3, -2.5); + + BOOST_CHECK (equals (actual, expected)); +} + +BOOST_AUTO_TEST_CASE (complex_parse5) +{ + const complex actual = parse_complex ("1"); + const complex expected (1.0, 0.0); + + BOOST_CHECK (equals (actual, expected)); +} + +BOOST_AUTO_TEST_CASE (complex_parse6) +{ + try + { + const complexa = parse_complex ("1.3-2.5"); + (void)a; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (complex_parse7) +{ + try + { + const complexa = parse_complex ("1.3i-2.5"); + (void)a; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (complex_parse8) +{ + try + { + const complexa = parse_complex ("1.3ij"); + (void)a; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (complex_parse9) +{ + try + { + const complexa = parse_complex ("1.3+3.5546ij"); + (void)a; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (complex_parse10) +{ + try + { + const complexa = parse_complex ("1.3ji"); + (void)a; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (complex_parse11) +{ + try + { + const complexa = parse_complex ("1.3+3.5546ji"); + (void)a; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (complex_parse12) +{ + const complex actual = parse_complex ("i"); + const complex expected (0.0, 1.0); + + BOOST_CHECK (equals (actual, expected)); +} + +BOOST_AUTO_TEST_CASE (complex_parse13) +{ + const complex actual = parse_complex ("-i"); + const complex expected (0.0, -1.0); + + BOOST_CHECK (equals (actual, expected)); +} + +BOOST_AUTO_TEST_CASE (complex_parse14) +{ + const complex actual = parse_complex ("0.5+i"); + const complex expected (0.5, 1.0); + + BOOST_CHECK (equals (actual, expected)); +} + +BOOST_AUTO_TEST_CASE (complex_parse15) +{ + const complex actual = parse_complex ("0.5-i"); + const complex expected (0.5, -1.0); + + BOOST_CHECK (equals (actual, expected)); +} + +BOOST_AUTO_TEST_CASE (complex_parse16) +{ + const complex actual = parse_complex ("+i"); + const complex expected (0.0, 1.0); + + BOOST_CHECK (equals (actual, expected)); +} diff --git a/C++/test/main.cpp b/C++/test/main.cpp new file mode 100644 index 0000000..5dba1df --- /dev/null +++ b/C++/test/main.cpp @@ -0,0 +1,12 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#ifndef BOOST_TEST_MAIN +#define BOOST_TEST_MAIN +#undef BOOST_TEST_NO_MAIN +#ifdef FORCE_STATIC_BOOST +#include +#else +#define BOOST_TEST_DYN_LINK +#include +#endif +#endif diff --git a/C++/test/parameters.test.cpp b/C++/test/parameters.test.cpp new file mode 100644 index 0000000..bad9a29 --- /dev/null +++ b/C++/test/parameters.test.cpp @@ -0,0 +1,55 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include + +#include "parameters.hpp" + +using std::size_t; + +BOOST_AUTO_TEST_CASE (parameters_default_parameters) +{ + const size_t argc = 1; + const char* argv[argc] = {"main.exe"}; + const parameters p (argc, argv); + + const char* expected_in = "input.txt"; + const char* expected_out = "output.txt"; + const bool expected_verbose = false; + + BOOST_CHECK_EQUAL (expected_in, p.get_in()); + BOOST_CHECK_EQUAL (expected_out, p.get_out()); + BOOST_CHECK_EQUAL (expected_verbose, p.is_verbose()); +} + +BOOST_AUTO_TEST_CASE (parameters_in) +{ + const size_t argc = 2; + const char* argv[argc] = { "-in", "in.txt" }; + const parameters p (argc, argv); + + const char* expected_in = "in.txt"; + + BOOST_CHECK_EQUAL (expected_in, p.get_in()); +} + +BOOST_AUTO_TEST_CASE (parameters_out) +{ + const size_t argc = 2; + const char* argv[argc] = { "-out", "out2.txt" }; + const parameters p (argc, argv); + + const char* expected_out = "out2.txt"; + + BOOST_CHECK_EQUAL (expected_out, p.get_out()); +} + +BOOST_AUTO_TEST_CASE (parameters_verbose) +{ + const size_t argc = 1; + const char* argv[argc] = { "-verbose" }; + const parameters p (argc, argv); + + const bool expected_verbose = true; + + BOOST_CHECK_EQUAL (expected_verbose, p.is_verbose()); +} diff --git a/C++/test/solver.test.cpp b/C++/test/solver.test.cpp new file mode 100644 index 0000000..52727f4 --- /dev/null +++ b/C++/test/solver.test.cpp @@ -0,0 +1,576 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include + +#include "complex.hpp" +#include "number_solutions.hpp" +#include "solver.hpp" + +#include +#include +#include +#include +#include + +using std::complex; +using std::istringstream; +using std::size_t; +using std::string; +using std::exception; +using std::vector; +using std::all_of; +using std::optional; +using std::reference_wrapper; + + +BOOST_AUTO_TEST_CASE (types1) +{ + istringstream in ("1 1\n1 2"); + const solver s (in); + + const bool result = std::is_same::value; + BOOST_CHECK (result); +} + +BOOST_AUTO_TEST_CASE (types2) +{ + istringstream in ("1 1\n1 2"); + const solver s (in); + + const bool result = + std::is_same>>>::value; + BOOST_CHECK (result); +} + +BOOST_AUTO_TEST_CASE (types3) +{ + istringstream in ("1 1\n1 2"); + const solver s (in); + + const bool result = + std::is_same>>>>::value; + BOOST_CHECK (result); +} + + +BOOST_AUTO_TEST_CASE (solver_constructor1) +{ + istringstream in ("1 1\n1 2"); + BOOST_CHECK_NO_THROW (const solver s (in)); +} + +BOOST_AUTO_TEST_CASE (solver_constructor2) +{ + istringstream in ("1 1\nab 2"); + try + { + const solver s (in); + (void)s; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (solver_constructor3) +{ + istringstream in ("-1 1\n2 2"); + try + { + const solver s (in); + (void)s; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (solver_constructor4) +{ + istringstream in ("1 -1\n2 2"); + try + { + const solver s (in); + (void)s; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (solver_constructor5) +{ + istringstream in ("1 1\n2"); + try + { + const solver s (in); + (void)s; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (solver_constructor6) +{ + istringstream in ("0 1\n2 2"); + try + { + const solver s (in); + (void)s; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (solver_constructor7) +{ + istringstream in ("1 0\n2 2"); + try + { + const solver s (in); + (void)s; + } + catch (const exception&) + { + return; + } + BOOST_FAIL ("no throw exception"); +} + +BOOST_AUTO_TEST_CASE (solver_solve0) +{ + istringstream in ("1 1 \n\n 2 4"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = {complex (2.0, 0.0)}; + const number_solutions expected_number_solutions = number_solutions::one; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_CHECK (!actual_general_solution.has_value()); +} + +BOOST_AUTO_TEST_CASE (solver_solve1) +{ + istringstream in ("1 1\n2 4"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (2.0, 0.0) }; + const number_solutions expected_number_solutions = number_solutions::one; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_CHECK (!actual_general_solution.has_value()); +} + +BOOST_AUTO_TEST_CASE (solver_solve2) +{ + istringstream in ("2 2\n1 2 3\n4 5 6"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (-1.0, 0.0), complex (2.0, 0.0) }; + const number_solutions expected_number_solutions = number_solutions::one; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_CHECK (!actual_general_solution.has_value()); +} + +BOOST_AUTO_TEST_CASE (solver_solve3) +{ + istringstream in ("2 2\n4 5 7\n3 9 9"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (0.85714, 0.0), complex (0.71429, 0.0) }; + const number_solutions expected_number_solutions = number_solutions::one; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_CHECK (!actual_general_solution.has_value()); +} + +BOOST_AUTO_TEST_CASE (solver_solve4) +{ + istringstream in ("3 3\n1 1 2 9\n2 4 -3 1\n3 6 -5 0"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (1.0, 0.0), complex (2.0, 0.0), + complex (3.0, 0.0) + }; + const number_solutions expected_number_solutions = number_solutions::one; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_CHECK (!actual_general_solution.has_value()); +} + + +BOOST_AUTO_TEST_CASE (solver_solve5) +{ + istringstream in ("2 2\n0 1 1\n1 0 1"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (1.0, 0.0), complex (1.0, 0.0) }; + const number_solutions expected_number_solutions = number_solutions::one; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_CHECK (!actual_general_solution.has_value()); +} + +BOOST_AUTO_TEST_CASE (solver_solve6) +{ + istringstream in ("2 2\n0 1 1\n0 2 2"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (0.0, 0.0), complex (1.0, 0.0) }; + const vector expected_general_solution = { "x1", "1" }; + const number_solutions expected_number_solutions = number_solutions::many; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_REQUIRE (actual_general_solution.has_value()); + BOOST_CHECK_EQUAL_COLLECTIONS (expected_general_solution.begin(), expected_general_solution.end(), + actual_general_solution->get().begin(), actual_general_solution->get().end()); +} + +BOOST_AUTO_TEST_CASE (solver_solve7) +{ + istringstream in ("2 2\n0 1 1\n0 2 3"); + solver s (in); + s.solve(); + + const number_solutions expected_number_solutions = number_solutions::none; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_CHECK (!actual_partial_solution.has_value()); + BOOST_CHECK (!actual_general_solution.has_value()); +} + +BOOST_AUTO_TEST_CASE (solver_solve8) +{ + istringstream in ("3 4\n0 1 2 9\n0 1 3 1\n1 0 6 0\n2 0 2 0"); + solver s (in); + s.solve(); + + const number_solutions expected_number_solutions = number_solutions::none; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_CHECK (!actual_partial_solution.has_value()); + BOOST_CHECK (!actual_general_solution.has_value()); +} + +BOOST_AUTO_TEST_CASE (solver_solve9) +{ + istringstream in ("3 1\n1 1 2 9"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (9.0, 0.0), complex (0.0, 0.0), + complex (0.0, 0.0) + }; + const vector expected_general_solution = { "9 - x2 - x3 * (2)", "x2", "x3" }; + const number_solutions expected_number_solutions = number_solutions::many; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_REQUIRE (actual_general_solution.has_value()); + BOOST_CHECK_EQUAL_COLLECTIONS (expected_general_solution.begin(), expected_general_solution.end(), + actual_general_solution->get().begin(), actual_general_solution->get().end()); +} + +BOOST_AUTO_TEST_CASE (solver_solve10) +{ + istringstream in ("4 4\n1 0 0 5 0\n0 0 0 0 0\n0 0 1 4 6\n0 0 5 5 5"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (-8.3333333, 0.0), complex (0.0, 0.0), + complex (-0.6666667, 0.0), complex (1.6666667, 0.0) + }; + const vector expected_general_solution = { "-8.3333", "x2", "-0.6667", "1.6667" }; + const number_solutions expected_number_solutions = number_solutions::many; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_REQUIRE (actual_general_solution.has_value()); + BOOST_CHECK_EQUAL_COLLECTIONS (expected_general_solution.begin(), expected_general_solution.end(), + actual_general_solution->get().begin(), actual_general_solution->get().end()); +} + +BOOST_AUTO_TEST_CASE (solver_solve11) +{ + istringstream in ("4 4\n2 3 -1 1 1\n8 12 -9 8 3\n4 6 3 -2 3\n2 3 9 -7 3"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (0.6, 0.0), complex (0.0, 0.0), + complex (0.2, 0.0), complex (0.0, 0.0) + }; + const vector expected_general_solution = { "0.6 - x2 * (1.5) - x4 * (0.1)", "x2", "0.2 - x4 * (-0.8)", "x4" }; + const number_solutions expected_number_solutions = number_solutions::many; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_REQUIRE (actual_general_solution.has_value()); + BOOST_CHECK_EQUAL_COLLECTIONS (expected_general_solution.begin(), expected_general_solution.end(), + actual_general_solution->get().begin(), actual_general_solution->get().end()); +} + +BOOST_AUTO_TEST_CASE (solver_solve12) +{ + istringstream + in ("3 3\n1+2i -1.5-1.1i 2.12 91+5i\n-1+3i 1.2+3.5i -3.3 1+15i\n12.31 1.3-5i 12.3i -78.3i"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (6.73335286, -22.99754223), + complex (-1.7976071, 2.08404919), complex (15.69938581, 7.3960106) + }; + const number_solutions expected_number_solutions = number_solutions::one; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_CHECK (!actual_general_solution.has_value()); +} + +BOOST_AUTO_TEST_CASE (solver_solve13) +{ + istringstream in ("1\t1\t2\t4"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (2.0, 0.0) }; + const number_solutions expected_number_solutions = number_solutions::one; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_CHECK (!actual_general_solution.has_value()); +} + +BOOST_AUTO_TEST_CASE (solver_solve14) +{ + istringstream in ("1 1\r\n2 4"); + solver s (in); + s.solve(); + + const vector> expected_partial_solution = { complex (2.0, 0.0) }; + const number_solutions expected_number_solutions = number_solutions::one; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_REQUIRE (actual_partial_solution.has_value()); + BOOST_REQUIRE (actual_partial_solution->get().size() == expected_partial_solution.size()); + const bool equals_partial = all_of (expected_partial_solution.cbegin(), + expected_partial_solution.cend(), [&, i = size_t (0)] (auto&)mutable + { + const bool result = equals (expected_partial_solution.at (i), actual_partial_solution->get().at (i)); + ++i; + return result; + }); + BOOST_CHECK (equals_partial); + BOOST_CHECK (!actual_general_solution.has_value()); +} + +BOOST_AUTO_TEST_CASE (solver_solve15) +{ + istringstream in ("3 4\n1 1 2 9\n0 1 3 1\n0 2 6 1\n0 0 0 0"); + solver s (in); + s.solve(); + + const number_solutions expected_number_solutions = number_solutions::none; + + const auto actual_partial_solution = s.get_solution_partial(); + const auto actual_number_solutions = s.get_number_solutions(); + const auto actual_general_solution = s.get_solution_general(); + + BOOST_CHECK_EQUAL (expected_number_solutions, actual_number_solutions); + BOOST_CHECK (!actual_partial_solution.has_value()); + BOOST_CHECK (!actual_general_solution.has_value()); +} diff --git a/C++/valgrind.sh b/C++/valgrind.sh new file mode 100755 index 0000000..c8ff594 --- /dev/null +++ b/C++/valgrind.sh @@ -0,0 +1,14 @@ +OS="`uname`" +case $OS in + 'Linux') + alias make='make' + ;; + 'FreeBSD') + alias make='gmake' + ;; + *) ;; +esac + +make clean && VALGRIND=1 make && valgrind --track-origins=yes --log-file=valgrind.txt --read-var-info=yes --leak-check=full bin/test_cpp + + diff --git a/C/.vscode/c_cpp_properties.json b/C/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..10adea4 --- /dev/null +++ b/C/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**", + "C:/msys2/mingw64/include/**", + "C:/msys2/mingw64/lib/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.17763.0", + "compilerPath": "C:/msys2/mingw64/bin/clang.exe", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/C/.vscode/settings.json b/C/.vscode/settings.json new file mode 100644 index 0000000..c2a2c07 --- /dev/null +++ b/C/.vscode/settings.json @@ -0,0 +1,65 @@ +{ + "C_Cpp.errorSquiggles": "Enabled", + "files.associations": { + "iosfwd": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "array": "cpp", + "strstream": "cpp", + "*.tcc": "cpp", + "complex": "cpp", + "cstdint": "cpp", + "list": "cpp", + "vector": "cpp", + "exception": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "utility": "cpp", + "ctime": "cpp", + "cwctype": "cpp", + "atomic": "cpp", + "bitset": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "fstream": "cpp", + "memory": "cpp", + "numeric": "cpp", + "ratio": "cpp", + "thread": "cpp", + "typeindex": "cpp", + "variant": "cpp", + "solution.h": "c", + "cpp_support.h": "c", + "stdlib.h": "c", + "parameters.h": "c", + "attributes.h": "c", + "complex_support.h": "c", + "universal_complex.h": "c", + "complex.h": "c", + "util.h": "c", + "number_solutions.h": "c", + "solver.h": "c" + } +} \ No newline at end of file diff --git a/C/3rd/unity b/C/3rd/unity new file mode 160000 index 0000000..a284984 --- /dev/null +++ b/C/3rd/unity @@ -0,0 +1 @@ +Subproject commit a2849843654524194b72567b198c25d1c1dfead0 diff --git a/C/3rd/useful-c-macros b/C/3rd/useful-c-macros new file mode 160000 index 0000000..6472945 --- /dev/null +++ b/C/3rd/useful-c-macros @@ -0,0 +1 @@ +Subproject commit 6472945eb2d9950bc7f99e464ddeec8e75ab5e43 diff --git a/C/acceptance tests/in.txt b/C/acceptance tests/in.txt new file mode 100644 index 0000000..b1db2cf --- /dev/null +++ b/C/acceptance tests/in.txt @@ -0,0 +1,4 @@ +3 3 +1 1 2 9 +2 4 -3 1 +3 6 -5 0 diff --git a/C/acceptance tests/in1.txt b/C/acceptance tests/in1.txt new file mode 100644 index 0000000..112d10d --- /dev/null +++ b/C/acceptance tests/in1.txt @@ -0,0 +1,5 @@ +3 4 +0 1 2 9 +0 1 3 1 +1 0 6 0 +2 0 2 0 \ No newline at end of file diff --git a/C/acceptance tests/in2.txt b/C/acceptance tests/in2.txt new file mode 100644 index 0000000..512957d --- /dev/null +++ b/C/acceptance tests/in2.txt @@ -0,0 +1,5 @@ +4 4 +1 0 0 5 0 +0 0 0 0 0 +0 0 1 4 6 +0 0 5 5 5 \ No newline at end of file diff --git a/C/acceptance tests/in3.txt b/C/acceptance tests/in3.txt new file mode 100644 index 0000000..3b20f11 --- /dev/null +++ b/C/acceptance tests/in3.txt @@ -0,0 +1,4 @@ +3 3 +1+2i -1.5-1.1i 2.12 91+5i +-1+3i 1.2+3.5i -3.3 1+15i +12.31 1.3-5i 12.3i -78.3i \ No newline at end of file diff --git a/C/acceptance tests/tests.ps1 b/C/acceptance tests/tests.ps1 new file mode 100755 index 0000000..3aae467 --- /dev/null +++ b/C/acceptance tests/tests.ps1 @@ -0,0 +1,89 @@ +#!/usr/bin/env pwsh +Describe CppAcceptanceTests { + It 'single solution' { + Remove-Item "$PSScriptRoot/out.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_c" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out.txt" -verbose > "$PSScriptRoot/stdout.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(1, 2, 3)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "-2 * R1 +R2 -> R2", "-3 * R1 +R3 -> R3", + "R2 / 2 -> R2", "-3 * R2 +R3 -> R3", "R3 / -0.5 -> R3", + "3.5 * R3 +R2 -> R2", "-2 * R3 +R1 -> R1", "-1 * R2 +R1 -> R1", + "(1, 2, 3)", "Saved to file $PSScriptRoot/out.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no solution' { + Remove-Item "$PSScriptRoot/out1.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout1.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_c" -in "$PSScriptRoot/in1.txt" -out "$PSScriptRoot/out1.txt" -verbose > "$PSScriptRoot/stdout1.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out1.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "There are no solutions" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout1.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 <-> R3", "-1 * R2 +R3 -> R3", "R3 / -1 -> R3", + "-3 * R3 +R2 -> R2", "-6 * R3 +R1 -> R1", "There are no solutions", "Saved to file $PSScriptRoot/out1.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'many solutions' { + Remove-Item "$PSScriptRoot/out2.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout2.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_c" -in "$PSScriptRoot/in2.txt" -out "$PSScriptRoot/out2.txt" -verbose > "$PSScriptRoot/stdout2.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out2.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(-8.3333, x2, -0.6667, 1.6667)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout2.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "C3 <-> C2", "R3 <-> R2", "-5 * R2 +R4 -> R4", + "C4 <-> C3", "R4 <-> R3", "R3 / -15 -> R3", "-4 * R3 +R2 -> R2", + "-5 * R3 +R1 -> R1", "(-8.3333, x2, -0.6667, 1.6667)","Saved to file $PSScriptRoot/out2.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'single solution complex numbers' { + Remove-Item "$PSScriptRoot/out3.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout3.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_c" -in "$PSScriptRoot/in3.txt" -out "$PSScriptRoot/out3.txt" -verbose > "$PSScriptRoot/stdout3.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out3.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout3.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 / 1+2i -> R1", "1-3i * R1 +R2 -> R2", "-12.31 * R1 +R3 -> R3", + "R2 / 1.6+6.1i -> R2", "-10.4094+9.6778i * R2 +R3 -> R3", "R3 / -6.7848+9.7158i -> R3", + "0.5432-0.746i * R3 +R2 -> R2", "-0.424+0.848i * R3 +R1 -> R1", "0.74-0.38i * R2 +R1 -> R1", + "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)", "Saved to file $PSScriptRoot/out3.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no output without -verbose' { + Remove-Item "$PSScriptRoot/out4.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout4.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_c" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out4.txt" > "$PSScriptRoot/stdout4.txt" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout4.txt") + $stdoutLines.Count | Should Be 0 + } +} diff --git a/C/acceptance tests/tests_win.ps1 b/C/acceptance tests/tests_win.ps1 new file mode 100644 index 0000000..1ab11d1 --- /dev/null +++ b/C/acceptance tests/tests_win.ps1 @@ -0,0 +1,88 @@ +Describe CppAcceptanceTests { + It 'single solution' { + Remove-Item "$PSScriptRoot/out.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out.txt" -verbose > "$PSScriptRoot/stdout.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(1, 2, 3)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "-2 * R1 +R2 -> R2", "-3 * R1 +R3 -> R3", + "R2 / 2 -> R2", "-3 * R2 +R3 -> R3", "R3 / -0.5 -> R3", + "3.5 * R3 +R2 -> R2", "-2 * R3 +R1 -> R1", "-1 * R2 +R1 -> R1", + "(1, 2, 3)", "Saved to file $PSScriptRoot/out.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no solution' { + Remove-Item "$PSScriptRoot/out1.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout1.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in1.txt" -out "$PSScriptRoot/out1.txt" -verbose > "$PSScriptRoot/stdout1.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out1.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "There are no solutions" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout1.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 <-> R3", "-1 * R2 +R3 -> R3", "R3 / -1 -> R3", + "-3 * R3 +R2 -> R2", "-6 * R3 +R1 -> R1", "There are no solutions", "Saved to file $PSScriptRoot/out1.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'many solutions' { + Remove-Item "$PSScriptRoot/out2.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout2.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in2.txt" -out "$PSScriptRoot/out2.txt" -verbose > "$PSScriptRoot/stdout2.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out2.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(-8.3333, x2, -0.6667, 1.6667)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout2.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "C3 <-> C2", "R3 <-> R2", "-5 * R2 +R4 -> R4", + "C4 <-> C3", "R4 <-> R3", "R3 / -15 -> R3", "-4 * R3 +R2 -> R2", + "-5 * R3 +R1 -> R1", "(-8.3333, x2, -0.6667, 1.6667)","Saved to file $PSScriptRoot/out2.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'single solution complex numbers' { + Remove-Item "$PSScriptRoot/out3.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout3.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in3.txt" -out "$PSScriptRoot/out3.txt" -verbose > "$PSScriptRoot/stdout3.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out3.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout3.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 / 1+2i -> R1", "1-3i * R1 +R2 -> R2", "-12.31 * R1 +R3 -> R3", + "R2 / 1.6+6.1i -> R2", "-10.4094+9.6778i * R2 +R3 -> R3", "R3 / -6.7848+9.7158i -> R3", + "0.5432-0.746i * R3 +R2 -> R2", "-0.424+0.848i * R3 +R1 -> R1", "0.74-0.38i * R2 +R1 -> R1", + "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)", "Saved to file $PSScriptRoot/out3.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no output without -verbose' { + Remove-Item "$PSScriptRoot/out4.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout4.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out4.txt" > "$PSScriptRoot/stdout4.txt" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout4.txt") + $stdoutLines.Count | Should Be 0 + } +} diff --git a/C/analyze.sh b/C/analyze.sh new file mode 100755 index 0000000..fe6cbcf --- /dev/null +++ b/C/analyze.sh @@ -0,0 +1 @@ +/usr/local/llvm60/bin/scan-build -o ./report/ gmake diff --git a/C/bin/.do_not_delete.txt b/C/bin/.do_not_delete.txt new file mode 100644 index 0000000..e69de29 diff --git a/C/drd.sh b/C/drd.sh new file mode 100755 index 0000000..0a828e7 --- /dev/null +++ b/C/drd.sh @@ -0,0 +1,12 @@ +OS="`uname`" +case $OS in + 'Linux') + alias make='make' + ;; + 'FreeBSD') + alias make='gmake' + ;; + *) ;; +esac + +make clean && VALGRIND=1 make && valgrind --log-file=drd.txt --read-var-info=yes --tool=drd bin/test_c diff --git a/C/helgrind.sh b/C/helgrind.sh new file mode 100755 index 0000000..f31ad22 --- /dev/null +++ b/C/helgrind.sh @@ -0,0 +1,12 @@ +OS="`uname`" +case $OS in + 'Linux') + alias make='make' + ;; + 'FreeBSD') + alias make='gmake' + ;; + *) ;; +esac + +make clean && VALGRIND=1 make && valgrind --log-file=helgrind.txt --read-var-info=yes --tool=helgrind bin/test_c diff --git a/C/include/complex_support.h b/C/include/complex_support.h new file mode 100644 index 0000000..67c6073 --- /dev/null +++ b/C/include/complex_support.h @@ -0,0 +1,20 @@ +#ifndef COMPLEX_SUPPORT_H +#define COMPLEX_SUPPORT_H + +#pragma once + +#include + +#include + +BEGIN_DECLS + +const char* complex_to_string (complex_double a); + +bool CONST complex_equals (complex_double a, complex_double b); + +bool complex_parse (complex_double* a, const char* s); + +END_DECLS + +#endif diff --git a/C/include/number_solutions.h b/C/include/number_solutions.h new file mode 100644 index 0000000..121f611 --- /dev/null +++ b/C/include/number_solutions.h @@ -0,0 +1,15 @@ +#ifndef NUMBER_SOLUTIONS_H +#define NUMBER_SOLUTIONS_H + +#pragma once + +enum number_solutions +{ + number_solutions_none, + number_solutions_one, + number_solutions_many +}; + +typedef enum number_solutions number_solutions; + +#endif diff --git a/C/include/parameters.h b/C/include/parameters.h new file mode 100644 index 0000000..e4722dc --- /dev/null +++ b/C/include/parameters.h @@ -0,0 +1,28 @@ +#ifndef PARAMETERS_H +#define PARAMETERS_H + +#pragma once + +#include + +#include +#include + +BEGIN_DECLS + +typedef struct parameters parameters; + +extern const size_t parameters_size; + +#define parameters_new_2(...) (parameters_new)(__VA_ARGS__, nullptr) +#define parameters_new(...) EXPAND(VAR_FUNC3(__VA_ARGS__, (parameters_new), parameters_new_2, nullptr))(__VA_ARGS__) +parameters* NONNULL (2) (parameters_new) (size_t argc, const char* const* argv, + void* memory) noexcept; +void parameters_free (parameters* p); +const char* PURE NONNULL (1) parameters_get_in (const parameters* p); +const char* PURE NONNULL (1) parameters_get_out (const parameters* p); +bool PURE NONNULL (1) parameters_get_verbose (const parameters* p); + +END_DECLS + +#endif diff --git a/C/include/solver.h b/C/include/solver.h new file mode 100644 index 0000000..cb6727a --- /dev/null +++ b/C/include/solver.h @@ -0,0 +1,35 @@ +#ifndef SOLVER_H +#define SOLVER_H + +#pragma once + +#include + +#include +#include +#include + +#include "number_solutions.h" + +BEGIN_DECLS + +typedef struct solver solver; + +extern const size_t solver_size; + +#define solver_new_2(...) (solver_new)(__VA_ARGS__, nullptr) +#define solver_new_1(...) solver_new_2(__VA_ARGS__, false) +#define solver_new(...) EXPAND(VAR_FUNC3(__VA_ARGS__, (solver_new), solver_new_2, solver_new_1, nullptr))(__VA_ARGS__) +solver* NONNULL (1) (solver_new) (FILE* in, bool verbose, void* memory); +void solver_free (solver* self); +number_solutions PURE solver_get_number_solutions (const solver* self); +const char* const* solver_get_solution_general (solver* self, + size_t* solution_general_size); +const complex_double* solver_get_solution_partial (solver* self, + size_t* solution_partial_size); +bool solver_solve (solver* self); +bool solver_write_solution_to_file (solver* self, const char* out_filename); + +END_DECLS + +#endif diff --git a/C/include/util.h b/C/include/util.h new file mode 100644 index 0000000..bb642fd --- /dev/null +++ b/C/include/util.h @@ -0,0 +1,19 @@ +#ifndef UTIL_H +#define UTIL_H + +#pragma once + +#include +#include + +#include + +BEGIN_DECLS + +bool PURE NONNULL (1, 2) str_equal (const char* s1, const char* s2) noexcept; + +FILE* NONNULL (1) generate_file ( const char* s ) noexcept; + +END_DECLS + +#endif diff --git a/C/makefile b/C/makefile new file mode 100644 index 0000000..001c974 --- /dev/null +++ b/C/makefile @@ -0,0 +1,28 @@ +include mk/init.mk + +OBJ_TEST += src/solver.o src/complex_support.o src/parameters.o src/util.o \ +test/main.o test/solver.test.o test/parameters.test.o test/complex_support.test.o \ +test/test_runners/parameters.runner.o test/test_runners/solver.runner.o test/test_runners/complex_support.runner.o + +OBJ_SOLUTION = src/main.o src/solver.o src/complex_support.o src/parameters.o src/util.o + +all: bin/test_c$(EXEEXT) + +release: bin/solution_c$(EXEEXT) + +release_cpp: bin/solution_cpp$(EXEEXT) + +test: bin/test_c$(EXEEXT) + +test_cpp: bin/test_cpp$(EXEEXT) + +thread_test: bin/thread_test_c$(EXEEXT) + +thread_test_cpp: bin/thread_test_cpp$(EXEEXT) + +clean: clean_details + +help: help_details + +include mk/targets.mk + diff --git a/C/mk/detect_os.mk b/C/mk/detect_os.mk new file mode 100644 index 0000000..378b462 --- /dev/null +++ b/C/mk/detect_os.mk @@ -0,0 +1,75 @@ +OS?= +ifeq ($(OS),Windows_NT) + PLATFORM := $(shell uname 2>NUL; false) + ifeq ($(findstring MINGW,$(PLATFORM)),MINGW) + DEL_NUL := $(shell rm -f NUL; false) + ifeq ($(findstring MINGW64,$(PLATFORM)),MINGW64) + BITS = "64" + else + BITS = "32" + endif + else + PLATFORM = "Windows" + endif +else + PLATFORM = $(shell uname) +endif + +OS_SUPPORTED = false +DOS ?= 0 + +ifeq (${DOS}, 1) + include mk/doc_gcc.mk + EXEEXT = .exe + OS_SUPPORTED = true +else + ifeq ($(findstring Haiku, $(PLATFORM)), Haiku) + include mk/haiku_clang.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring DragonFly, $(PLATFORM)), DragonFly) + include mk/dragonfly_gcc.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring NetBSD, $(PLATFORM)), NetBSD) + include mk/netbsd_gcc.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring OpenBSD, $(PLATFORM)), OpenBSD) + include mk/openbsd_clang.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring SunOS, $(PLATFORM)), SunOS) + include mk/openindiana_gcc.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring FreeBSD, $(PLATFORM)), FreeBSD) + include mk/freebsd_clang.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring Linux, $(PLATFORM)), Linux) + include mk/linux_gcc.mk + OS_SUPPORTED = true + endif + + ifeq ($(findstring MINGW, $(PLATFORM)), MINGW) + include mk/mingw_clang.mk + EXEEXT = .exe + OS_SUPPORTED = true + endif + + ifeq ($(findstring Windows, $(PLATFORM)),Windows) + $(error "install msys2: http://www.msys2.org/") + endif +endif + +ifeq ($(OS_SUPPORTED),false) + $(error "OS is not supported") +endif + diff --git a/C/mk/disable_sanitizers_if_enabled_valgrind.mk b/C/mk/disable_sanitizers_if_enabled_valgrind.mk new file mode 100644 index 0000000..451b4bb --- /dev/null +++ b/C/mk/disable_sanitizers_if_enabled_valgrind.mk @@ -0,0 +1,4 @@ +ifeq ($(VALGRIND), 1) + SANITIZERS = + LIBS_SANITIZERS = +endif diff --git a/C/mk/doc_gcc.mk b/C/mk/doc_gcc.mk new file mode 100644 index 0000000..3f3be16 --- /dev/null +++ b/C/mk/doc_gcc.mk @@ -0,0 +1,55 @@ +CCACHE = ccache +CC = $(CCACHE) i386-pc-msdosdjgpp-gcc +CXX = $(CCACHE) i386-pc-msdosdjgpp-g++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security \ + -Wstrict-overflow=5 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\ + -Wswitch-default -Wformat-nonliteral -Wdouble-promotion -Wnull-dereference\ + -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wchkp\ + -Wconversion -Wlogical-not-parentheses -Walloc-zero -Wcast-qual -Wrestrict\ + -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion \ + -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum \ + -Wunused-const-variable=2 -Wdangling-else -Wnonnull \ + -Wsuggest-attribute=pure -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wmissing-noreturn -Wmissing-format-attribute\ + -Wsuggest-attribute=malloc -Wsuggest-attribute=format \ + -Wsuggest-attribute=cold \ + -Werror +WARNINGS_C_ONLY = -Wbad-function-cast -Winit-self -fno-common +WARNINGS_FORCE_CXX = -Wno-alloca -Wuseless-cast -Wsubobject-linkage -Wzero-as-null-pointer-constant +WARNINGS_TEST = -Wno-float-equal -Wno-switch-enum -Wno-strict-overflow -Wno-suggest-attribute=const +WARNINGS_TEST_CXX = -Wno-zero-as-null-pointer-constant -Wno-useless-cast -Wno-sign-conversion + +LTO = -flto-partition=none -flto -ffat-lto-objects +INCLUDE += -I"include" -isystem"3rd" +SECURITY = +DEFINES = -D_FORTIFY_SOURCE=2 -D__STDC_FORMAT_MACROS +DEBUG = -g3 +OPENMP = +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CXXSTANDARD = -std=gnu++1z +CSTANDARD = -std=gnu11 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = -flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = +LIBS_SYSTEM = -lm +LIBS_THREAD = +LIBS_3RD = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_FORCE_CXX) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/C/mk/dos_watcom.mk b/C/mk/dos_watcom.mk new file mode 100644 index 0000000..3fef057 --- /dev/null +++ b/C/mk/dos_watcom.mk @@ -0,0 +1,43 @@ +CCACHE = +CC = $(CCACHE) owcc -bdos4g +CXX = $(CCACHE) owcc -bdos4g -xc++ +CPPFLAGS = #-MT $@ -MMD -MP +TARGET_ARCH = + +WARNINGS = -Wall -Wextra +WARNINGS_C_ONLY = +WARNINGS_FORCE_CXX = +WARNINGS_TEST = +WARNINGS_TEST_CXX = + +INCLUDE = -I"${WATCOM}/h" -I"include" -I"3rd" -I"3rd/unity/src" -I"3rd/unity/extras/fixture/src" +LTO = +SECURITY = +DEFINES = -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS +DEBUG = -g3 +OPENMP = +OPTIMIZE = -O3 +CXXSTANDARD = -std=c++11 +CSTANDARD = -std=c99 + +SANITIZERS = +THREAD_SANITIZER = + +LINK = ${CC} +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = +LIBS_SYSTEM = +LIBS_THREAD = +LIBS_3RD = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_FORCE_CXX) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/C/mk/dragonfly_gcc.mk b/C/mk/dragonfly_gcc.mk new file mode 100644 index 0000000..1621692 --- /dev/null +++ b/C/mk/dragonfly_gcc.mk @@ -0,0 +1,55 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CXX = $(CCACHE) g++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security \ + -Wstrict-overflow=2 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\ + -Wswitch-default -Wformat-nonliteral -Wdouble-promotion -Wnull-dereference\ + -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wchkp\ + -Wconversion -Wlogical-not-parentheses -Walloc-zero -Wcast-qual -Wrestrict\ + -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion \ + -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum \ + -Wunused-const-variable=2 -Wdangling-else -Wnonnull \ + -Wsuggest-attribute=pure -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wmissing-noreturn -Wmissing-format-attribute\ + -Wsuggest-attribute=malloc -Wsuggest-attribute=format \ + -Wsuggest-attribute=cold \ + -Werror +WARNINGS_C_ONLY = -Wbad-function-cast -Winit-self -fno-common +WARNINGS_FORCE_CXX = -Wno-alloca -Wuseless-cast -Wsubobject-linkage -Wzero-as-null-pointer-constant +WARNINGS_TEST = -Wno-float-equal -Wno-switch-enum -Wno-strict-overflow -Wno-suggest-attribute=const +WARNINGS_TEST_CXX = -Wno-zero-as-null-pointer-constant -Wno-useless-cast -Wno-sign-conversion + +LTO = -flto-partition=none -flto -ffat-lto-objects +INCLUDE += -I"include" -isystem"3rd" -isystem"/usr/local/include/" +SECURITY = +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CXXSTANDARD = -std=gnu++1z +CSTANDARD = -std=gnu11 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = -flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = -L"/usr/local/lib" +LD_SECURITY = +LD_SYSTEM = -Wl,-O1 -rdynamic + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread -Wl,--no-as-needed -lpthread +LIBS_3RD = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_FORCE_CXX) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/C/mk/freebsd_clang.mk b/C/mk/freebsd_clang.mk new file mode 100644 index 0000000..ded1eea --- /dev/null +++ b/C/mk/freebsd_clang.mk @@ -0,0 +1,42 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CXX = $(CCACHE) clang++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Weverything -Wno-used-but-marked-unused -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-vla -Wno-tautological-pointer-compare -Wno-covered-switch-default -Werror +WARNINGS_C_ONLY = -fno-common -Wno-complex-component-init +WARNINGS_FORCE_CXX = -Wno-deprecated -Wno-old-style-cast +WARNINGS_TEST = -Wno-switch-enum +WARNINGS_TEST_CXX = -Wno-zero-as-null-pointer-constant -Wno-float-equal -Wno-disabled-macro-expansion + +INCLUDE += -I"include" -isystem"3rd" -isystem"/usr/local/include/" +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations +CXXSTANDARD = -std=gnu++1z +CSTANDARD = -std=c11 + +SANITIZERS = -fsanitize=address -fsanitize=undefined -fsanitize=leak -fno-omit-frame-pointer +THREAD_SANITIZER = -fsanitize=thread -fno-omit-frame-pointer + +LD_LTO = +LD_INCLUDE = -L"/usr/local/lib" +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp=libiomp5 +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread +LIBS_3RD = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_FORCE_CXX) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/C/mk/haiku_clang.mk b/C/mk/haiku_clang.mk new file mode 100644 index 0000000..7377a4c --- /dev/null +++ b/C/mk/haiku_clang.mk @@ -0,0 +1,42 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CXX = $(CCACHE) clang++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Weverything -Wno-used-but-marked-unused -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-vla -Wno-tautological-pointer-compare -Wno-covered-switch-default -Werror +WARNINGS_C_ONLY = -Wno-gnu-imaginary-constant -fno-common +WARNINGS_FORCE_CXX = -Wno-deprecated -Wno-old-style-cast +WARNINGS_TEST = -Wno-switch-enum +WARNINGS_TEST_CXX = -Wno-zero-as-null-pointer-constant -Wno-float-equal + +INCLUDE += -I"include" -isystem"3rd" -isystem "/boot/system/develop/headers/x86/c++" -isystem"/boot/system/develop/headers/x86/c++/i586-pc-haiku" +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations +CXXSTANDARD = -std=gnu++1z +CSTANDARD = -std=gnu11 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = +LIBS_SYSTEM = +LIBS_THREAD = +LIBS_3RD = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_FORCE_CXX) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/C/mk/init.mk b/C/mk/init.mk new file mode 100644 index 0000000..bf52e74 --- /dev/null +++ b/C/mk/init.mk @@ -0,0 +1,26 @@ +VALGRIND ?= 0 +EXEEXT = + +OBJ_UNITY = 3rd/unity/src/unity.o 3rd/unity/extras/fixture/src/unity_fixture.o + +INCLUDE = -isystem"3rd/unity/src" -isystem"3rd/unity/extras/fixture/src" + +OBJ_TEST = $(OBJ_UNITY) + +OBJ_SOLUTION = + +OBJS = $(OBJ_TEST) $(OBJ_SOLUTION) + +include mk/detect_os.mk +include mk/optional_ccache.mk +include mk/disable_sanitizers_if_enabled_valgrind.mk + +COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c + +%.o : %.c +%.o : %.c %.d + $(COMPILE.c) $(OUTPUT_OPTION) $< + +%.d: ; +.PRECIOUS: %.d + diff --git a/C/mk/linux_gcc.mk b/C/mk/linux_gcc.mk new file mode 100644 index 0000000..a518499 --- /dev/null +++ b/C/mk/linux_gcc.mk @@ -0,0 +1,56 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CXX = $(CCACHE) g++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security \ + -Wstrict-overflow=5 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\ + -Wswitch-default -Wformat-nonliteral -Wdouble-promotion -Wnull-dereference\ + -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wchkp\ + -Wconversion -Wlogical-not-parentheses -Walloc-zero -Wcast-qual -Wrestrict\ + -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion \ + -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum \ + -Wunused-const-variable=2 -Wdangling-else -Wnonnull \ + -Wsuggest-attribute=pure -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wmissing-noreturn -Wmissing-format-attribute\ + -Wsuggest-attribute=malloc -Wsuggest-attribute=format \ + -Wsuggest-attribute=cold \ + -Werror +WARNINGS_C_ONLY = -Wbad-function-cast -Winit-self -fno-common +WARNINGS_FORCE_CXX = -Wno-alloca -Wuseless-cast -Wsubobject-linkage -Wzero-as-null-pointer-constant +WARNINGS_TEST = -Wno-float-equal -Wno-switch-enum -Wno-strict-overflow -Wno-suggest-attribute=const +WARNINGS_TEST_CXX = -Wno-zero-as-null-pointer-constant -Wno-useless-cast -Wno-sign-conversion + +LTO = -flto-partition=none -flto -ffat-lto-objects +INCLUDE += -I"include" -isystem"3rd" +SECURITY = -fPIC -fstack-protector-all --param ssp-buffer-size=4 -fstack-check\ + -mindirect-branch=thunk -fPIE -Wa,--noexecstack +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CXXSTANDARD = -std=gnu++1z +CSTANDARD = -std=gnu11 + +SANITIZERS = -fsanitize=address -fsanitize=undefined -fsanitize=leak -fno-omit-frame-pointer +THREAD_SANITIZER = -fsanitize=thread -fno-omit-frame-pointer + +LD_LTO = -flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = +LD_SECURITY = -pie -Wl,-z,relro,-z,now -Wl,-z,noexecstack +LD_SYSTEM = -Wl,-O1 -rdynamic + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread -Wl,--no-as-needed -lpthread +LIBS_3RD = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_FORCE_CXX) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/C/mk/mingw_clang.mk b/C/mk/mingw_clang.mk new file mode 100644 index 0000000..ea11f91 --- /dev/null +++ b/C/mk/mingw_clang.mk @@ -0,0 +1,42 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CXX = $(CCACHE) clang++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Weverything -Wno-used-but-marked-unused -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-vla -Wno-tautological-pointer-compare -Wno-covered-switch-default -Werror +WARNINGS_C_ONLY = -fno-common +WARNINGS_FORCE_CXX = -Wno-deprecated -Wno-old-style-cast +WARNINGS_TEST = -Wno-switch-enum +WARNINGS_TEST_CXX = -Wno-zero-as-null-pointer-constant -Wno-float-equal + +INCLUDE += -I"include" -isystem"3rd" +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations +CXXSTANDARD = -std=gnu++1z +CSTANDARD = -std=gnu11 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp=libiomp5 +LIBS_SYSTEM = +LIBS_THREAD = +LIBS_3RD = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_FORCE_CXX) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/C/mk/netbsd_gcc.mk b/C/mk/netbsd_gcc.mk new file mode 100644 index 0000000..e179b69 --- /dev/null +++ b/C/mk/netbsd_gcc.mk @@ -0,0 +1,55 @@ +CCACHE = ccache +CC = $(CCACHE) /usr/pkg/gcc8/bin/gcc +CXX = $(CCACHE) /usr/pkg/gcc8/bin/g++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security \ + -Wstrict-overflow=5 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\ + -Wswitch-default -Wformat-nonliteral -Wdouble-promotion -Wnull-dereference\ + -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wchkp\ + -Wconversion -Wlogical-not-parentheses -Walloc-zero -Wcast-qual -Wrestrict\ + -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion \ + -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum \ + -Wunused-const-variable=2 -Wdangling-else -Wnonnull \ + -Wsuggest-attribute=pure -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wmissing-noreturn -Wmissing-format-attribute\ + -Wsuggest-attribute=malloc -Wsuggest-attribute=format \ + -Wsuggest-attribute=cold \ + -Werror +WARNINGS_C_ONLY = -Wbad-function-cast -Winit-self -fno-common +WARNINGS_FORCE_CXX = -Wno-alloca -Wuseless-cast -Wsubobject-linkage -Wzero-as-null-pointer-constant +WARNINGS_TEST = -Wno-float-equal -Wno-switch-enum -Wno-strict-overflow -Wno-suggest-attribute=const +WARNINGS_TEST_CXX = -Wno-zero-as-null-pointer-constant -Wno-useless-cast -Wno-sign-conversion + +LTO = -flto-partition=none -flto -ffat-lto-objects +INCLUDE += -I"include" -isystem"3rd" +SECURITY = +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CXXSTANDARD = -std=gnu++1z +CSTANDARD = -std=gnu11 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = -flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = -L"/usr/pkg/lib" +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread -Wl,--no-as-needed -lpthread +LIBS_3RD = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_FORCE_CXX) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/C/mk/openbsd_clang.mk b/C/mk/openbsd_clang.mk new file mode 100644 index 0000000..356ab7d --- /dev/null +++ b/C/mk/openbsd_clang.mk @@ -0,0 +1,42 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CXX = $(CCACHE) clang++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Weverything -Wno-used-but-marked-unused -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-vla -Wno-tautological-pointer-compare -Wno-covered-switch-default -Werror +WARNINGS_C_ONLY = -fno-common -Wno-complex-component-init -Wno-gnu-imaginary-constant +WARNINGS_FORCE_CXX = -Wno-deprecated -Wno-old-style-cast +WARNINGS_TEST = -Wno-switch-enum +WARNINGS_TEST_CXX = -Wno-zero-as-null-pointer-constant -Wno-float-equal -Wno-disabled-macro-expansion + +INCLUDE += -I"include" -isystem"3rd" -isystem"/usr/local/include/" +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations +CXXSTANDARD = -std=gnu++1z +CSTANDARD = -std=c11 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = -L"/usr/local/lib" +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp=libiomp5 +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread +LIBS_3RD = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_FORCE_CXX) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/C/mk/openindiana_gcc.mk b/C/mk/openindiana_gcc.mk new file mode 100644 index 0000000..6325768 --- /dev/null +++ b/C/mk/openindiana_gcc.mk @@ -0,0 +1,55 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CXX = $(CCACHE) g++ +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security \ + -Wstrict-overflow=5 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\ + -Wswitch-default -Wformat-nonliteral -Wdouble-promotion -Wnull-dereference\ + -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond -Wchkp\ + -Wconversion -Wlogical-not-parentheses -Walloc-zero -Wcast-qual -Wrestrict\ + -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion \ + -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum \ + -Wunused-const-variable=2 -Wdangling-else -Wnonnull \ + -Wsuggest-attribute=pure -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wmissing-noreturn -Wmissing-format-attribute\ + -Wsuggest-attribute=malloc -Wsuggest-attribute=format \ + -Wsuggest-attribute=cold \ + -Werror +WARNINGS_C_ONLY = -Wbad-function-cast -Winit-self -fno-common +WARNINGS_FORCE_CXX = -Wno-alloca -Wuseless-cast -Wsubobject-linkage -Wzero-as-null-pointer-constant +WARNINGS_TEST = -Wno-float-equal -Wno-switch-enum -Wno-strict-overflow -Wno-suggest-attribute=const +WARNINGS_TEST_CXX = -Wno-zero-as-null-pointer-constant -Wno-useless-cast -Wno-sign-conversion + +LTO = +INCLUDE += -I"include" -isystem"3rd" +SECURITY = +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CXXSTANDARD = -std=gnu++1z +CSTANDARD = -std=gnu11 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread +LIBS_3RD = + +FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) \ + $(SECURITY) $(DEBUG) + +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY) +CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_FORCE_CXX) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_3RD) $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/C/mk/optional_ccache.mk b/C/mk/optional_ccache.mk new file mode 100644 index 0000000..2b7ace5 --- /dev/null +++ b/C/mk/optional_ccache.mk @@ -0,0 +1,4 @@ +CCACHE_VER := $(shell $(CCACHE) -V 2>/dev/null; false) +ifeq ($(CCACHE_VER),) + CCACHE = +endif diff --git a/C/mk/targets.mk b/C/mk/targets.mk new file mode 100644 index 0000000..522e0a2 --- /dev/null +++ b/C/mk/targets.mk @@ -0,0 +1,55 @@ +./bin/solution_c$(EXEEXT): $(OBJ_SOLUTION) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) + +./bin/solution_cpp$(EXEEXT): CFLAGS = $(CXXFLAGS) +./bin/solution_cpp$(EXEEXT): CC = $(CXX) +./bin/solution_cpp$(EXEEXT): $(OBJ_SOLUTION) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) + +./bin/test_c$(EXEEXT): CFLAGS += $(SANITIZERS) $(WARNINGS_TEST) +./bin/test_c$(EXEEXT): $(OBJ_TEST) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) $(SANITIZERS) + +./bin/test_cpp$(EXEEXT): CFLAGS = $(CXXFLAGS) +./bin/test_cpp$(EXEEXT): CC = $(CXX) +./bin/test_cpp$(EXEEXT): CFLAGS += $(SANITIZERS) $(WARNINGS_TEST) $(WARNINGS_TEST_CXX) +./bin/test_cpp$(EXEEXT): $(OBJ_TEST) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) $(SANITIZERS) + +./bin/thread_test_c$(EXEEXT): CFLAGS += $(THREAD_SANITIZER) $(WARNINGS_TEST) +./bin/thread_test_c$(EXEEXT): $(OBJ_TEST) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) $(THREAD_SANITIZER) + +./bin/thread_test_cpp$(EXEEXT): CFLAGS = $(CXXFLAGS) +./bin/thread_test_cpp$(EXEEXT): CC = $(CXX) +./bin/thread_test_cpp$(EXEEXT): CFLAGS += $(THREAD_SANITIZER) $(WARNINGS_TEST) $(WARNINGS_TEST_CXX) +./bin/thread_test_cpp$(EXEEXT): $(OBJ_TEST) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) $(THREAD_SANITIZER) + + +clean_details: + find . -name "*.o" -type f -delete + find . -name "*.d" -type f -delete + find . -name "*.orig" -type f -delete + rm -f "bin/solution_c$(EXEEXT)" + rm -f "bin/solution_cpp$(EXEEXT)" + rm -f "bin/test_c$(EXEEXT)" + rm -f "bin/test_cpp$(EXEEXT)" + rm -f "bin/thread_test_c$(EXEEXT)" + rm -f "bin/thread_test_cpp$(EXEEXT)" + +help_details: + @echo "The following are some of the valid targets for this makefile:" + @echo " all (the default if no target is provided=test)" + @echo " release" + @echo " release_cpp" + @echo " test" + @echo " test_cpp" + @echo " thread_test" + @echo " thread_test_cpp" + @echo " clean" + @echo " help" + +.PHONY: all help help_details clean clean_details test_cpp test + +include $(wildcard $(patsubst %, %.d,$(basename $(OBJS)))) diff --git a/C/msvc2017/Solution/Solution/Solution.ruleset b/C/msvc2017/Solution/Solution/Solution.ruleset new file mode 100644 index 0000000..be233f5 --- /dev/null +++ b/C/msvc2017/Solution/Solution/Solution.ruleset @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/C/msvc2017/Solution/Solution/Solution.vcxproj b/C/msvc2017/Solution/Solution/Solution.vcxproj new file mode 100644 index 0000000..a8e8b66 --- /dev/null +++ b/C/msvc2017/Solution/Solution/Solution.vcxproj @@ -0,0 +1,181 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {5716832B-1FBD-40FA-B9C3-5A981F75023B} + Solution + 10.0.16299.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + Solution.ruleset + true + + + Solution.ruleset + true + + + Solution.ruleset + + + Solution.ruleset + + + + Level4 + MaxSpeed + true + true + true + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + Speed + true + Fast + true + stdcpp17 + true + CompileAsCpp + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + Console + + + + + Level4 + Disabled + true + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + CompileAsCpp + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + + + + + Level4 + Disabled + true + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + CompileAsCpp + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + + + + + Level4 + MaxSpeed + true + true + true + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + Speed + true + Fast + true + stdcpp17 + true + CompileAsCpp + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + Console + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/C/msvc2017/Solution/Solution/Solution.vcxproj.filters b/C/msvc2017/Solution/Solution/Solution.vcxproj.filters new file mode 100644 index 0000000..a36f919 --- /dev/null +++ b/C/msvc2017/Solution/Solution/Solution.vcxproj.filters @@ -0,0 +1,37 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + \ No newline at end of file diff --git a/C/msvc2017/Test/Test.sln b/C/msvc2017/Test/Test.sln new file mode 100644 index 0000000..4f3b0f9 --- /dev/null +++ b/C/msvc2017/Test/Test.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27520.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{A7F93A37-D503-4669-AE95-CE0A247A9EF0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Solution", "..\Solution\Solution\Solution.vcxproj", "{5716832B-1FBD-40FA-B9C3-5A981F75023B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x64.ActiveCfg = Debug|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x64.Build.0 = Debug|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x86.ActiveCfg = Debug|Win32 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x86.Build.0 = Debug|Win32 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x64.ActiveCfg = Release|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x64.Build.0 = Release|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x86.ActiveCfg = Release|Win32 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x86.Build.0 = Release|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x64.ActiveCfg = Debug|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x64.Build.0 = Debug|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x86.ActiveCfg = Debug|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x86.Build.0 = Debug|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x64.ActiveCfg = Release|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x64.Build.0 = Release|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x86.ActiveCfg = Release|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DE43A559-CB9E-40B7-8806-BF60F337E07F} + EndGlobalSection +EndGlobal diff --git a/C/msvc2017/Test/Test/Test.ruleset b/C/msvc2017/Test/Test/Test.ruleset new file mode 100644 index 0000000..ca9031f --- /dev/null +++ b/C/msvc2017/Test/Test/Test.ruleset @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/C/msvc2017/Test/Test/Test.vcxproj b/C/msvc2017/Test/Test/Test.vcxproj new file mode 100644 index 0000000..f0f8037 --- /dev/null +++ b/C/msvc2017/Test/Test/Test.vcxproj @@ -0,0 +1,218 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15.0 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0} + Win32Proj + Test + 10.0.16299.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + Test.ruleset + true + + + true + Test.ruleset + true + + + Test.ruleset + true + + + Test.ruleset + true + + + + NotUsing + Level4 + Disabled + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(ProjectDir)..\..\..\3rd\unity\extras\fixture\src;$(ProjectDir)..\..\..\3rd\unity\src;$(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + Caret + true + CompileAsCpp + + + Console + true + + + + + NotUsing + Level4 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + $(ProjectDir)..\..\..\3rd\unity\extras\fixture\src;$(ProjectDir)..\..\..\3rd\unity\src;$(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + Caret + true + CompileAsCpp + + + Console + true + + + + + NotUsing + Level4 + MaxSpeed + true + true + WIN32;_CONSOLE;%(PreprocessorDefinitions) + $(ProjectDir)..\..\..\3rd\unity\extras\fixture\src;$(ProjectDir)..\..\..\3rd\unity\src;$(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + Caret + true + true + true + Speed + true + Fast + CompileAsCpp + + + Console + true + true + true + + + + + NotUsing + Level4 + MaxSpeed + true + true + _CONSOLE;%(PreprocessorDefinitions) + $(ProjectDir)..\..\..\3rd\unity\extras\fixture\src;$(ProjectDir)..\..\..\3rd\unity\src;$(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + Caret + true + true + true + Speed + true + Fast + CompileAsCpp + + + Console + true + true + true + + + + + \ No newline at end of file diff --git a/C/msvc2017/Test/Test/Test.vcxproj.filters b/C/msvc2017/Test/Test/Test.vcxproj.filters new file mode 100644 index 0000000..81972d9 --- /dev/null +++ b/C/msvc2017/Test/Test/Test.vcxproj.filters @@ -0,0 +1,111 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {da82dd41-d1e7-49e9-bc66-dcae6fca5648} + + + {744cd46e-f503-4243-82ac-411cab055c43} + + + {a721e3b5-545c-42f1-948f-82f64d9a95de} + + + {4dc1e766-cb61-4709-97d1-00d5de42e026} + + + {db0dc142-7f6a-4d6a-abd5-a72132a5c02b} + + + + + Исходные файлы + + + Исходные файлы\runners + + + Исходные файлы\runners + + + Исходные файлы\runners + + + Исходные файлы\tests + + + Исходные файлы\tests + + + Исходные файлы\tests + + + Исходные файлы\src + + + Исходные файлы\src + + + Исходные файлы\src + + + Исходные файлы\src + + + Исходные файлы\unity + + + Исходные файлы\unity + + + + + + + + Файлы заголовков + + + Файлы заголовков + + + Файлы заголовков + + + Файлы заголовков + + + Файлы заголовков + + + Файлы заголовков\useful-c-macros + + + Файлы заголовков\useful-c-macros + + + Файлы заголовков\useful-c-macros + + + Файлы заголовков\useful-c-macros + + + Файлы заголовков\useful-c-macros + + + Файлы заголовков\useful-c-macros + + + \ No newline at end of file diff --git a/C/runastyle.sh b/C/runastyle.sh new file mode 100644 index 0000000..c8d3464 --- /dev/null +++ b/C/runastyle.sh @@ -0,0 +1,18 @@ +H_FILES_NUMBER=`find include -type f -name "*.h" -printf x 2> /dev/null | wc -c` + +C_FILES_NUMBER=`find src -type f -name "*.c" -printf x 2> /dev/null | wc -c` +TEST_C_FILES_NUMBER=`find test -type f -name "*.c" -printf x 2> /dev/null | wc -c` + +ASTYLE="astyle --style=allman --pad-oper --pad-first-paren-out --align-pointer=type --align-reference=type --lineend=windows --max-code-length=80 --indent-namespaces --convert-tabs" + +if [ $C_FILES_NUMBER -gt 0 ]; then + $ASTYLE --recursive "src/*.c" +fi + +if [ $H_FILES_NUMBER -gt 0 ]; then + $ASTYLE --recursive "include/*.h" +fi + +if [ $TEST_C_FILES_NUMBER -gt 0 ]; then + $ASTYLE --recursive "test/*.c" +fi diff --git a/C/src/complex_support.c b/C/src/complex_support.c new file mode 100644 index 0000000..db6e44d --- /dev/null +++ b/C/src/complex_support.c @@ -0,0 +1,113 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "complex_support.h" + +#include +#include +#include + +#include "util.h" + +static const double EPSILON = 0.00001; + +const char* complex_to_string (complex_double a) +{ + int snprintf_result = 0; + static char buffer[4096] = {0}; + const double real = round (creal (a) * 10000.0) / 10000.0; + const double imag = round (cimag (a) * 10000.0) / 10000.0; + if (fabs (imag) < EPSILON) + { + snprintf_result = snprintf (buffer, sizeof (buffer) - 1, "%g", real); + assert (snprintf_result > 0); + } + else if (fabs (real) < EPSILON) + { + snprintf_result = snprintf (buffer, sizeof (buffer) - 1, "%gi", imag); + assert (snprintf_result > 0); + } + else + { + const char* prefix = imag > 0 ? "+" : ""; + snprintf_result = snprintf (buffer, sizeof (buffer) - 1, "%g%s%gi", real, + prefix, imag); + assert (snprintf_result > 0); + } + + return buffer; +} + +bool complex_equals (complex_double a, complex_double b) +{ + return fabs (cimag (a) - cimag (b)) < EPSILON + && fabs (creal (a) - creal (b)) < EPSILON; +} + +bool complex_parse (complex_double* a, const char* s) +{ + assert (s != nullptr); + assert (a != nullptr); + + double real = 0.0; + double imag = 0.0; + char c[3] = {0}; + int result = sscanf (s, "%lg%lg%2s", &real, &imag, c); + if (result != 3) + { + real = 0.0; + result = sscanf (s, "%lg%2s", &imag, c); + if (result != 2) + { + c[0] = '\0'; + imag = 0.0; + result = sscanf (s, "%lg", &real); + if (result == 1) + { + c[0] = 'i'; + c[1] = '\0'; + } + else + { + result = sscanf (s, "%2s", c); + if (result == 1) + { + if (str_equal (c, "i") || str_equal (c, "+i")) + { + imag = 1.0; + c[0] = 'i'; + c[1] = '\0'; + } + else if (str_equal (c, "-i")) + { + imag = -1.0; + c[0] = 'i'; + c[1] = '\0'; + } + } + } + } + else + { + if (str_equal (c, "+i")) + { + real = imag; + imag = 1.0; + c[0] = 'i'; + c[1] = '\0'; + } + else if (str_equal (c, "-i")) + { + real = imag; + imag = -1.0; + c[0] = 'i'; + c[1] = '\0'; + } + } + } + if (!str_equal (c, "i")) + { + return false; + } + *a = CMPLX (real, imag); + return true; +} diff --git a/C/src/main.c b/C/src/main.c new file mode 100644 index 0000000..3acdaf5 --- /dev/null +++ b/C/src/main.c @@ -0,0 +1,63 @@ +#include +#include +#include "parameters.h" +#include "solver.h" + +int main (int argc, char* argv[]) +{ +#ifdef __cplusplus + uint8_t* const parameters_stack = (uint8_t*)alloca (parameters_size); + uint8_t* const solver_stack = (uint8_t*)alloca (solver_size); +#elif (__STDC_VERSION__ < 201112L) + uint8_t* const parameters_stack = nullptr; + uint8_t* const solver_stack = nullptr; +#else + alignas (max_align_t) uint8_t parameters_stack[parameters_size]; + alignas (max_align_t) uint8_t solver_stack[solver_size]; +#endif + const size_t correct_argc = (size_t)argc; + const char* const* correct_argv = (const char* const*) ((char* const*)argv); + parameters* p = parameters_new (correct_argc, correct_argv, parameters_stack); + if (p == nullptr) + { + fprintf (stderr, "can't read command line parameters\n"); + return EXIT_FAILURE; + } + FILE* in = fopen (parameters_get_in (p), "r"); + if (in == nullptr) + { + fprintf (stderr, "can't open -in file: %s\n", parameters_get_in (p)); + parameters_free (p); + return EXIT_FAILURE; + } + solver* s = solver_new (in, parameters_get_verbose (p), solver_stack); + if (s == nullptr) + { + fprintf (stderr, "can't read from -in file or incorrect data\n"); + parameters_free (p); + fclose (in); + return EXIT_FAILURE; + } + bool ok = solver_solve (s); + if (!ok) + { + fprintf (stderr, "something wrong while solve\n"); + solver_free (s); + parameters_free (p); + fclose (in); + return EXIT_FAILURE; + } + ok = solver_write_solution_to_file (s, parameters_get_out (p)); + if (!ok) + { + fprintf (stderr, "can't write to output file: %s\n", parameters_get_out (p)); + solver_free (s); + parameters_free (p); + fclose (in); + return EXIT_FAILURE; + } + solver_free (s); + parameters_free (p); + fclose (in); + return EXIT_SUCCESS; +} diff --git a/C/src/parameters.c b/C/src/parameters.c new file mode 100644 index 0000000..eff7e3a --- /dev/null +++ b/C/src/parameters.c @@ -0,0 +1,97 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "parameters.h" + +#include +#include + +#include "util.h" + +struct parameters +{ + const char* in; + const char* out; + bool verbose; + bool stack; +}; + +const size_t parameters_size = sizeof (parameters); + +parameters* (parameters_new) (size_t argc, const char* const* argv, + void* memory) noexcept +{ + assert (argv != nullptr); + + parameters* result = (parameters*)memory; + if (memory == nullptr) + { + result = (parameters*)malloc (sizeof (parameters)); + if (result == nullptr) + { + return nullptr; + } + result->stack = false; + } + else + { + result->stack = true; + } + result->in = "input.txt"; + result->out = "output.txt"; + result->verbose = false; + bool need_assigned_in = true; + bool need_assigned_out = true; + for (size_t i = 0; i < argc; ++i) + { + assert (argv[i] != nullptr); + if (need_assigned_in && str_equal (argv[i], "-in")) + { + if (i < (argc - 1)) + { + result->in = argv[i + 1]; + need_assigned_in = false; + ++i; + } + } + else if (need_assigned_out && str_equal (argv[i], "-out")) + { + if (i < argc - 1) + { + result->out = argv[i + 1]; + need_assigned_out = false; + ++i; + } + } + else if (!result->verbose && str_equal (argv[i], "-verbose")) + { + result->verbose = true; + } + } + return result; +} +void parameters_free (parameters* p) +{ + if (p != nullptr) + { + if (!p->stack) + { + free (p); + } + } + +} +const char* parameters_get_in (const parameters* p) +{ + assert (p != nullptr); + return p->in; +} +const char* parameters_get_out (const parameters* p) +{ + assert (p != nullptr); + return p->out; +} +bool parameters_get_verbose (const parameters* p) +{ + assert (p != nullptr); + return p->verbose; +} diff --git a/C/src/solver.c b/C/src/solver.c new file mode 100644 index 0000000..ad82f04 --- /dev/null +++ b/C/src/solver.c @@ -0,0 +1,551 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "solver.h" + +#include +#include +#include +#include + +#include "util.h" +#include "number_solutions.h" +#include "complex_support.h" + + +struct solver +{ + size_t number_equations; + size_t number_variables; + complex_double* matrix; + complex_double* solution_partial; + char** solution_general; + size_t* solution_indexes; + number_solutions number_solutions_; + bool verbose; + bool stack; +}; + +const size_t solver_size = sizeof (solver); + +STATIC_CONST complex_double ZERO = CMPLX (0.0, 0.0); +STATIC_CONST complex_double ONE = CMPLX (1.0, 0.0); +STATIC_CONST complex_double MINUS_ONE = CMPLX (-1.0, 0.0); + +static void add_k_row1_to_row2 (solver* self, complex_double k, size_t row1, + size_t row2); +static size_t get_matrix_index (const solver* self, size_t i, + size_t j) noexcept; +static void check_that_solution_is_sane (solver* self); +static void divide_row (solver* self, size_t row, complex_double k); +static void gaus_first_step (solver* self); +static void gaus_second_step (solver* self); +static bool generate_solutions (solver* self) noexcept; +static void print_solution (solver* self) noexcept; +static void print_solution_internal (solver* self, FILE* out) noexcept; +static void swap_columns (solver* self, size_t column1, + size_t column2) noexcept; +static void swap_rows (solver* self, size_t row1, size_t row2) noexcept; + +solver* (solver_new) (FILE* in, bool verbose, void* memory) +{ + assert (in != nullptr); + + solver* self = (solver*)memory; + if (self == nullptr) + { + self = (solver*)calloc (1, sizeof (solver)); + if (self == nullptr) + { + return nullptr; + } + self->stack = false; + } + else + { + self->stack = true; + } + + long long temp_number_variables = 0; + long long temp_real_number_equations = 0; + int scanf_result = fscanf (in, "%lld%lld", &temp_number_variables, + &temp_real_number_equations); + if (scanf_result != 2 || temp_number_variables < 1 || + temp_real_number_equations < 1 || + temp_number_variables > UINT32_MAX || + temp_real_number_equations > UINT32_MAX) + { + solver_free (self); + return nullptr; + } + const size_t real_number_equations = (size_t)temp_real_number_equations; + self->number_variables = (size_t)temp_number_variables; + self->number_equations = (real_number_equations < self->number_variables) ? + self->number_variables : real_number_equations; + + self->matrix = (complex_double*)calloc (self->number_equations * + (self->number_variables + 1), + sizeof (complex_double)); + self->solution_partial = (complex_double*)calloc (self->number_variables, + sizeof (complex_double)); + self->solution_general = (char**)calloc (self->number_variables, + sizeof (char*)); + self->solution_indexes = (size_t*)calloc (self->number_variables, + sizeof (size_t)); + if (self->matrix == nullptr || self->solution_partial == nullptr + || self->solution_general == nullptr || self->solution_indexes == nullptr) + { + solver_free (self); + return nullptr; + } + for (size_t i = 0; i < real_number_equations; ++i) + { + for (size_t j = 0; j < self->number_variables + 1; ++j) + { + char temp[4096] = {0}; + scanf_result = fscanf (in, "%4095s", temp); + if (scanf_result != 1) + { + solver_free (self); + return nullptr; + } + const bool parse_ok = complex_parse (&self->matrix[get_matrix_index (self, i, + j)], + temp); + if (!parse_ok) + { + solver_free (self); + return nullptr; + } + } + } + + for (size_t i = 0; i < self->number_variables; ++i) + { + self->solution_indexes[i] = i; + } + + self->number_solutions_ = number_solutions_one; + self->verbose = verbose; + + return self; +} + +void solver_free (solver* self) +{ + if (self != nullptr) + { + if (self->solution_general != nullptr) + { + for (size_t i = 0; i < self->number_variables; ++i) + { + free (self->solution_general[i]); + } + } + free (self->matrix); + free (self->solution_partial); + free (self->solution_general); + free (self->solution_indexes); + if (!self->stack) + { + free (self); + } + } +} + +number_solutions solver_get_number_solutions (const solver* self) +{ + assert (self != nullptr); + return self->number_solutions_; +} + +const char* const* solver_get_solution_general (solver* self, + size_t* solution_general_size) +{ + assert (self != nullptr); + assert (solution_general_size != nullptr); + if (self->number_solutions_ != number_solutions_many) + { + return nullptr; + } + *solution_general_size = self->number_variables; + char* const* const tmp1 = (char* const*)self->solution_general; + const char* const* const tmp2 = (const char* const*)tmp1; + return tmp2; +} + +const complex_double* solver_get_solution_partial (solver* self, + size_t* solution_partial_size) +{ + assert (self != nullptr); + assert (solution_partial_size != nullptr); + if (self->number_solutions_ == number_solutions_none) + { + return nullptr; + } + *solution_partial_size = self->number_variables; + return self->solution_partial; +} + +bool solver_solve (solver* self) +{ + assert (self != nullptr); + if (self->verbose) + { + puts ("Start solving the equation.\nRows manipulation:"); + } + gaus_first_step (self); + if (self->number_solutions_ != number_solutions_none) + { + gaus_second_step (self); + const bool ok = generate_solutions (self); + if (!ok) + { + return false; + } + check_that_solution_is_sane (self); + } + print_solution (self); + return true; +} +bool solver_write_solution_to_file (solver* self, const char* out_filename) +{ + assert (self != nullptr); + assert (out_filename != nullptr); + FILE* out = fopen (out_filename, "w"); + if (out == nullptr) + { + return false; + } + print_solution_internal (self, out); + fclose (out); + if (self->verbose) + { + printf ("Saved to file %s\n", out_filename); + } + return true; +} + +static void add_k_row1_to_row2 (solver* self, complex_double k, size_t row1, + size_t row2) +{ + assert (self != nullptr); + if (self->verbose) + { + printf ("%s * R%" PRIu32 " +R%" PRIu32 " -> R%" PRIu32 "\n", + complex_to_string (k), CAST_SIZE_T_TO_UINT32 (row1 + 1), + CAST_SIZE_T_TO_UINT32 (row2 + 1), CAST_SIZE_T_TO_UINT32 (row2 + 1)); + } + for (size_t i = 0; i < self->number_variables + 1; ++i) + { + self->matrix[get_matrix_index (self, row2, + i)] += k * self->matrix[get_matrix_index (self, row1, i)]; + } +} + +static void check_that_solution_is_sane (solver* self) +{ + assert (self != nullptr); + for (size_t i = self->number_variables; i < self->number_equations; ++i) + { + complex_double sum = CMPLX (0.0, 0.0); + for (size_t j = 0; j < self->number_variables; ++j) + { + sum += self->solution_partial[self->solution_indexes[j]] * + self->matrix[get_matrix_index (self, i, j)]; + } + if (!complex_equals (sum, self->matrix[get_matrix_index (self, i, + self->number_variables)])) + { + self->number_solutions_ = number_solutions_none; + return; + } + } +} + +static void divide_row (solver* self, size_t row, complex_double k) +{ + assert (self != nullptr); + if (self->verbose) + { + printf ("R%" PRIu32 " / %s -> R%" PRIu32 "\n", CAST_SIZE_T_TO_UINT32 (row + 1), + complex_to_string (k), CAST_SIZE_T_TO_UINT32 (row + 1)); + } + for (size_t i = 0; i < self->number_variables + 1; ++i) + { + self->matrix[get_matrix_index (self, row, i)] /= k; + } +} + +static void gaus_first_step (solver* self) +{ + assert (self != nullptr); + for (size_t i = 0; i < self->number_variables; ++i) + { + if (complex_equals (self->matrix[get_matrix_index (self, i, i)], ZERO)) + { + bool found_non_zero_element = false; + for (size_t j = i + 1; j < self->number_equations; ++j) + { + if (!complex_equals (self->matrix[get_matrix_index (self, j, i)], ZERO)) + { + swap_rows (self, i, j); + found_non_zero_element = true; + break; + } + } + if (!found_non_zero_element) + { + for (size_t j = i + 1; j < self->number_variables; ++j) + { + if (!complex_equals (self->matrix[get_matrix_index (self, i, j)], ZERO)) + { + swap_columns (self, i, j); + found_non_zero_element = true; + break; + } + } + } + + if (!found_non_zero_element) + { + for (size_t k = i + 1; !found_non_zero_element + && k < self->number_variables; ++k) + { + for (size_t j = i + 1; j < self->number_equations; ++j) + { + if (!complex_equals (self->matrix[get_matrix_index (self, j, k)], ZERO)) + { + swap_columns (self, k, i); + swap_rows (self, j, i); + found_non_zero_element = true; + break; + } + } + } + } + + if (!found_non_zero_element) + { + if (complex_equals (self->matrix[get_matrix_index (self, i, + self->number_variables)], ZERO)) + { + self->number_solutions_ = number_solutions_many; + continue; + } + else + { + self->number_solutions_ = number_solutions_none; + return; + } + } + } + + if (!complex_equals (self->matrix[get_matrix_index (self, i, i)], ONE)) + { + divide_row (self, i, self->matrix[get_matrix_index (self, i, i)]); + } + for (size_t j = i + 1; j < self->number_equations + && j < self->number_variables; ++j) + { + const complex_double k = MINUS_ONE * self->matrix[get_matrix_index (self, j, + i)]; + if (!complex_equals (k, ZERO)) + { + add_k_row1_to_row2 (self, k, i, j); + } + } + } +} + +static void gaus_second_step (solver* self) +{ + assert (self != nullptr); + for (size_t i = self->number_variables - 1; true; --i) + { + if (i == 0) + { + break; + } + for (size_t j = i - 1; true; --j) + { + const complex_double k = MINUS_ONE * self->matrix[get_matrix_index (self, j, + i)]; + if (!complex_equals (k, ZERO)) + { + add_k_row1_to_row2 (self, k, i, j); + } + if (j == 0) + { + break; + } + } + } +} + + +static size_t get_matrix_index (const solver* self, size_t i, size_t j) noexcept +{ + return i * (self->number_variables + 1) + j; +} + + +static bool generate_solutions (solver* self) noexcept +{ + assert (self != nullptr); + static char buffer[8192] = {0}; + bool ok = true; + for (size_t i = 0; i < self->number_equations + && i < self->number_variables; ++i) + { + self->solution_partial[self->solution_indexes[i]] = + self->matrix[get_matrix_index (self, i, self->number_variables)]; + free (self->solution_general[self->solution_indexes[i]]); + if (complex_equals (self->matrix[get_matrix_index (self, i, i)], ZERO)) + { + ok = snprintf (buffer, sizeof (buffer) - 1, "x%llu", + self->solution_indexes[i] + 1ULL) > 0; + if (!ok) + { + return false; + } + self->solution_general[self->solution_indexes[i]] = (char*)calloc (strlen ( + buffer) + 1, sizeof (char)); + if (self->solution_general[self->solution_indexes[i]] == nullptr) + { + return false; + } + strcpy (self->solution_general[self->solution_indexes[i]], buffer); + } + else + { + ok = snprintf (buffer, sizeof (buffer) - 1, "%s", + complex_to_string (self->matrix[get_matrix_index (self, i, + self->number_variables)])) > 0; + self->solution_general[self->solution_indexes[i]] = (char*)calloc (strlen ( + buffer) + 1, sizeof (char)); + if (self->solution_general[self->solution_indexes[i]] == nullptr) + { + return false; + } + strcpy (self->solution_general[self->solution_indexes[i]], buffer); + for (size_t j = i + 1; j < self->number_variables; ++j) + { + if (complex_equals (self->matrix[get_matrix_index (self, i, j)], ONE)) + { + ok = snprintf (buffer, sizeof (buffer) - 1, " - x%llu", + self->solution_indexes[j] + 1ULL) > 0; + if (!ok) + { + return false; + } + char* tmp = (char*)realloc (self->solution_general[self->solution_indexes[i]], + strlen (self->solution_general[self->solution_indexes[i]]) + strlen ( + buffer) + 1); + if (tmp == nullptr) + { + return false; + } + self->solution_general[self->solution_indexes[i]] = tmp; + strcat (self->solution_general[self->solution_indexes[i]], buffer); + } + else if (!complex_equals (self->matrix[get_matrix_index (self, i, j)], ZERO)) + { + ok = snprintf (buffer, sizeof (buffer) - 1, " - x%llu * (%s)", + self->solution_indexes[j] + 1ULL, + complex_to_string (self->matrix[get_matrix_index (self, i, j)])) > 0; + if (!ok) + { + return false; + } + char* tmp = (char*)realloc (self->solution_general[self->solution_indexes[i]], + strlen (self->solution_general[self->solution_indexes[i]]) + strlen ( + buffer) + 1); + if (tmp == nullptr) + { + return false; + } + self->solution_general[self->solution_indexes[i]] = tmp; + strcat (self->solution_general[self->solution_indexes[i]], buffer); + } + } + } + } + return true; +} + +static void print_solution (solver* self) noexcept +{ + assert (self != nullptr); + if (self->verbose) + { + print_solution_internal (self, stdout); + } +} + +static void print_solution_internal (solver* self, FILE* out) noexcept +{ + assert (self != nullptr); + assert (out != nullptr); + switch (self->number_solutions_) + { + case number_solutions_none: + fprintf (out, "There are no solutions\n"); + break; + case number_solutions_one: + fprintf (out, "(%s", complex_to_string (self->solution_partial[0])); + for (size_t i = 1; i < self->number_variables; ++i) + { + fprintf (out, ", %s", complex_to_string (self->solution_partial[i])); + } + fprintf (out, ")\n"); + break; + case number_solutions_many: + fprintf (out, "(%s", self->solution_general[0]); + for (size_t i = 1; i < self->number_variables; ++i) + { + fprintf (out, ", %s", self->solution_general[i]); + } + fprintf (out, ")\n"); + break; + default: + assert (false); + break; + } +} + +static void swap_columns (solver* self, size_t column1, size_t column2) noexcept +{ + assert (self != nullptr); + if (self->verbose) + { + printf ("C%" PRIu32 " <-> C%" PRIu32 "\n", CAST_SIZE_T_TO_UINT32 (column1 + 1), + CAST_SIZE_T_TO_UINT32 (column2 + 1)); + } + for (size_t i = 0; i < self->number_equations; ++i) + { + const complex_double tmp = self->matrix[get_matrix_index (self, i, column1)]; + self->matrix[get_matrix_index (self, i, + column1)] = self->matrix[get_matrix_index (self, i, column2)]; + self->matrix[get_matrix_index (self, i, column2)] = tmp; + } + const size_t temp_index = self->solution_indexes[column1]; + self->solution_indexes[column1] = self->solution_indexes[column2]; + self->solution_indexes[column2] = temp_index; +} + +static void swap_rows (solver* self, size_t row1, size_t row2) noexcept +{ + assert (self != nullptr); + if (self->verbose) + { + printf ("R%" PRIu32 " <-> R%" PRIu32 "\n", CAST_SIZE_T_TO_UINT32 (row1 + 1), + CAST_SIZE_T_TO_UINT32 (row2 + 1)); + } + for (size_t i = 0; i < self->number_variables + 1; ++i) + { + const complex_double tmp = self->matrix[get_matrix_index (self, row1, i)]; + self->matrix[get_matrix_index (self, row1, + i)] = self->matrix[get_matrix_index (self, row2, i)]; + self->matrix[get_matrix_index (self, row2, i)] = tmp; + } +} diff --git a/C/src/util.c b/C/src/util.c new file mode 100644 index 0000000..a4658ec --- /dev/null +++ b/C/src/util.c @@ -0,0 +1,38 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "util.h" + +#include +#include + +bool NONNULL (1, 2) str_equal (const char* s1, const char* s2) noexcept +{ + assert (s1 != nullptr); + assert (s2 != nullptr); + + const size_t s1_length = strlen (s1); + const size_t s2_length = strlen (s2); + if (s1_length == s2_length) + { + return strcmp (s1, s2) == 0; + } + + return false; +} + +FILE* generate_file ( const char* s ) noexcept +{ + assert (s != nullptr); +#ifdef _WIN32 + FILE* f = fopen (_tempnam ("c:\\tmp", "test"), "w+"); +#else + FILE* f = tmpfile(); +#endif + if (f == nullptr) + { + return f; + } + fputs (s, f); + rewind (f); + return f; +} diff --git a/C/test/complex_support.test.c b/C/test/complex_support.test.c new file mode 100644 index 0000000..e3c5bd8 --- /dev/null +++ b/C/test/complex_support.test.c @@ -0,0 +1,236 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include + +#include "complex_support.h" + +TEST_GROUP (ComplexSupport); + + +TEST_SETUP (ComplexSupport) +{ +} + +TEST_TEAR_DOWN (ComplexSupport) +{ +} + +TEST (ComplexSupport, to_string1) +{ + const complex_double a = CMPLX (1.0, 0.0); + const char* expected = "1"; + const char* actual = complex_to_string (a); + + TEST_ASSERT (actual != nullptr); + TEST_ASSERT_EQUAL_STRING (expected, actual); +} + +TEST (ComplexSupport, to_string2) +{ + const complex_double a = CMPLX (0.0, 1.0); + const char* expected = "1i"; + const char* actual = complex_to_string (a); + + TEST_ASSERT (actual != nullptr); + TEST_ASSERT_EQUAL_STRING (expected, actual); +} + +TEST (ComplexSupport, to_string3) +{ + const complex_double a = CMPLX (-2.4, 1.5); + const char* expected = "-2.4+1.5i"; + const char* actual = complex_to_string (a); + + TEST_ASSERT (actual != nullptr); + TEST_ASSERT_EQUAL_STRING (expected, actual); +} + +TEST (ComplexSupport, to_string4) +{ + const complex_double a = CMPLX (2.4, -1.5); + const char* expected = "2.4-1.5i"; + const char* actual = complex_to_string (a); + + TEST_ASSERT (actual != nullptr); + TEST_ASSERT_EQUAL_STRING (expected, actual); +} + +TEST (ComplexSupport, to_string5) +{ + const complex_double a = CMPLX (0.0, 0.0); + const char* expected = "0"; + const char* actual = complex_to_string (a); + + TEST_ASSERT (actual != nullptr); + TEST_ASSERT_EQUAL_STRING (expected, actual); +} + +TEST (ComplexSupport, equals1) +{ + const complex_double a = CMPLX (1.0, 2.0); + const complex_double b = CMPLX (1.0, 2.0); + + TEST_ASSERT (complex_equals (a, b)); +} + +TEST (ComplexSupport, equals2) +{ + const complex_double a = CMPLX (1.0, 2.0); + const complex_double b = CMPLX (1.1, 2.0); + + TEST_ASSERT_FALSE (complex_equals (a, b)); +} + +TEST (ComplexSupport, equals3) +{ + const complex_double a = CMPLX (1.0, 2.1); + const complex_double b = CMPLX (1.0, 2.0); + + TEST_ASSERT_FALSE (complex_equals (a, b)); +} + +TEST (ComplexSupport, parse1) +{ + complex_double a = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&a, "gdc"); + + TEST_ASSERT_FALSE (ok); +} + +TEST (ComplexSupport, parse2) +{ + const complex_double expected = CMPLX (-1.3, 0.0); + complex_double actual = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&actual, "-1.3"); + + TEST_ASSERT (ok); + TEST_ASSERT (complex_equals (expected, actual)); +} + +TEST (ComplexSupport, parse3) +{ + const complex_double expected = CMPLX (0.0, 2.5); + complex_double actual = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&actual, "2.5i"); + + TEST_ASSERT (ok); + TEST_ASSERT (complex_equals (expected, actual)); +} + +TEST (ComplexSupport, parse4) +{ + const complex_double expected = CMPLX (1.3, -2.5); + complex_double actual = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&actual, "1.3-2.5i"); + + TEST_ASSERT (ok); + TEST_ASSERT (complex_equals (expected, actual)); +} + +TEST (ComplexSupport, parse5) +{ + const complex_double expected = CMPLX (1.0, 0.0); + complex_double actual = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&actual, "1"); + + TEST_ASSERT (ok); + TEST_ASSERT (complex_equals (expected, actual)); +} + +TEST (ComplexSupport, parse6) +{ + complex_double a = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&a, "1.3-2.5"); + + TEST_ASSERT_FALSE (ok); +} + +TEST (ComplexSupport, parse7) +{ + complex_double a = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&a, "1.3i-2.5"); + + TEST_ASSERT_FALSE (ok); +} + +TEST (ComplexSupport, parse8) +{ + complex_double a = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&a, "1.3ij"); + + TEST_ASSERT_FALSE (ok); +} + +TEST (ComplexSupport, parse9) +{ + complex_double a = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&a, "1.3+3.5546ij"); + + TEST_ASSERT_FALSE (ok); +} + +TEST (ComplexSupport, parse10) +{ + complex_double a = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&a, "1.3ji"); + + TEST_ASSERT_FALSE (ok); +} + +TEST (ComplexSupport, parse11) +{ + complex_double a = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&a, "1.3+3.5546ji"); + + TEST_ASSERT_FALSE (ok); +} + +TEST (ComplexSupport, parse12) +{ + const complex_double expected = CMPLX (0.0, 1.0); + complex_double actual = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&actual, "i"); + + TEST_ASSERT (ok); + TEST_ASSERT (complex_equals (expected, actual)); +} + +TEST (ComplexSupport, parse13) +{ + const complex_double expected = CMPLX (0.0, -1.0); + complex_double actual = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&actual, "-i"); + + TEST_ASSERT (ok); + TEST_ASSERT (complex_equals (expected, actual)); +} + +TEST (ComplexSupport, parse14) +{ + const complex_double expected = CMPLX (0.5, 1.0); + complex_double actual = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&actual, "0.5+i"); + + TEST_ASSERT (ok); + TEST_ASSERT (complex_equals (expected, actual)); +} + +TEST (ComplexSupport, parse15) +{ + const complex_double expected = CMPLX (0.5, -1.0); + complex_double actual = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&actual, "0.5-i"); + + TEST_ASSERT (ok); + TEST_ASSERT (complex_equals (expected, actual)); +} + +TEST (ComplexSupport, parse16) +{ + const complex_double expected = CMPLX (0.0, 1.0); + complex_double actual = CMPLX (0.0, 0.0); + const bool ok = complex_parse (&actual, "+i"); + + TEST_ASSERT (ok); + TEST_ASSERT (complex_equals (expected, actual)); +} diff --git a/C/test/main.c b/C/test/main.c new file mode 100644 index 0000000..35999f5 --- /dev/null +++ b/C/test/main.c @@ -0,0 +1,15 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include + +static void RunAllTests (void) +{ + RUN_TEST_GROUP (Parameters); + RUN_TEST_GROUP (ComplexSupport); + RUN_TEST_GROUP (Solver); +} + +int main (int argc, const char* argv[]) +{ + return UnityMain (argc, argv, RunAllTests); +} diff --git a/C/test/parameters.test.c b/C/test/parameters.test.c new file mode 100644 index 0000000..181543d --- /dev/null +++ b/C/test/parameters.test.c @@ -0,0 +1,88 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include + +#include "parameters.h" + +TEST_GROUP (Parameters); + + +TEST_SETUP (Parameters) +{ +} + +TEST_TEAR_DOWN (Parameters) +{ +} + +TEST (Parameters, new_stack) +{ +#ifdef __cplusplus + uint8_t* const stack = (uint8_t*)alloca (parameters_size); +#elif (__STDC_VERSION__ < 201112L) + uint8_t* const stack = nullptr; +#else + alignas (max_align_t) uint8_t stack[parameters_size]; +#endif + const char* const argv[] = {""}; + const size_t argc = sizeof (argv) / sizeof (argv[0]); + parameters* p = parameters_new (argc, argv, stack); + + TEST_ASSERT (p != nullptr); + TEST_ASSERT_EQUAL_STRING ("input.txt", parameters_get_in (p)); + TEST_ASSERT_EQUAL_STRING ("output.txt", parameters_get_out (p)); + TEST_ASSERT_FALSE (parameters_get_verbose (p)); + + parameters_free (p); +} + +TEST (Parameters, default_parameters) +{ + const char* const argv[] = {""}; + const size_t argc = sizeof (argv) / sizeof (argv[0]); + parameters* p = parameters_new (argc, argv); + + TEST_ASSERT (p != nullptr); + TEST_ASSERT_EQUAL_STRING ("input.txt", parameters_get_in (p)); + TEST_ASSERT_EQUAL_STRING ("output.txt", parameters_get_out (p)); + TEST_ASSERT_FALSE (parameters_get_verbose (p)); + + parameters_free (p); +} + +TEST (Parameters, in) +{ + const char* const argv[] = {"-in", "in.txt"}; + const size_t argc = sizeof (argv) / sizeof (argv[0]); + parameters* p = parameters_new (argc, argv); + + TEST_ASSERT (p != nullptr); + TEST_ASSERT_EQUAL_STRING ("in.txt", parameters_get_in (p)); + + parameters_free (p); +} + +TEST (Parameters, out) +{ + const char* const argv[] = {"-out", "out.txt"}; + const size_t argc = sizeof (argv) / sizeof (argv[0]); + parameters* p = parameters_new (argc, argv); + + TEST_ASSERT (p != nullptr); + TEST_ASSERT_EQUAL_STRING ("out.txt", parameters_get_out (p)); + + parameters_free (p); +} + +TEST (Parameters, verbose) +{ + const char* const argv[] = {"-verbose"}; + const size_t argc = sizeof (argv) / sizeof (argv[0]); + parameters* p = parameters_new (argc, argv); + + TEST_ASSERT (p != nullptr); + TEST_ASSERT (parameters_get_verbose (p)); + + parameters_free (p); +} + diff --git a/C/test/solver.test.c b/C/test/solver.test.c new file mode 100644 index 0000000..fe5bfd4 --- /dev/null +++ b/C/test/solver.test.c @@ -0,0 +1,780 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include + +#include "solver.h" +#include "util.h" +#include "complex_support.h" + +TEST_GROUP (Solver); + + +TEST_SETUP (Solver) +{ +} + +TEST_TEAR_DOWN (Solver) +{ +} + +#ifndef __cplusplus + +#define RIGHT_NUMBER_SOLUTIONS_TYPE(x) _Generic((x), \ + number_solutions: true, \ + default: false) + +#define RIGHT_SOLUTION_GENERAL_TYPE(x) _Generic((x), \ + const char* const*: true, \ + default: false) + +#define RIGHT_SOLUTION_PARTIAL_TYPE(x) _Generic((x), \ + const complex_double*: true, \ + default: false) + +#else + +#include + +#define RIGHT_NUMBER_SOLUTIONS_TYPE(x) std::is_same::value +#define RIGHT_SOLUTION_GENERAL_TYPE(x) std::is_same::value +#define RIGHT_SOLUTION_PARTIAL_TYPE(x) std::is_same::value + +#endif + +TEST (Solver, types1) +{ + FILE* in = generate_file ("1 1\n1 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + + TEST_ASSERT_NOT_NULL (s); + TEST_ASSERT ( RIGHT_NUMBER_SOLUTIONS_TYPE (solver_get_number_solutions (s)) ); + + solver_free (s); + fclose (in); +} + +TEST (Solver, types2) +{ + FILE* in = generate_file ("1 1\n1 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + size_t temp; + + TEST_ASSERT_NOT_NULL (s); + TEST_ASSERT ( RIGHT_SOLUTION_GENERAL_TYPE (solver_get_solution_general (s, + &temp)) ); + + solver_free (s); + fclose (in); +} + +TEST (Solver, types3) +{ + FILE* in = generate_file ("1 1\n1 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + size_t temp; + + TEST_ASSERT_NOT_NULL (s); + TEST_ASSERT ( RIGHT_SOLUTION_PARTIAL_TYPE (solver_get_solution_partial (s, + &temp)) ); + + solver_free (s); + fclose (in); +} + +TEST (Solver, constructor1) +{ + FILE* in = generate_file ("1 1\n1 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + + TEST_ASSERT_NOT_NULL (s); + + solver_free (s); + fclose (in); +} + +TEST (Solver, constructor2) +{ + FILE* in = generate_file ("1 1\nnab 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + + TEST_ASSERT_NULL (s); + + solver_free (s); + fclose (in); +} + +TEST (Solver, constructor3) +{ + FILE* in = generate_file ("-1 1\n2 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + + TEST_ASSERT_NULL (s); + + solver_free (s); + fclose (in); +} + +TEST (Solver, constructor4) +{ + FILE* in = generate_file ("1 -1\n2 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + + TEST_ASSERT_NULL (s); + + solver_free (s); + fclose (in); +} + +TEST (Solver, constructor5) +{ + FILE* in = generate_file ("1 1\n2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + + TEST_ASSERT_NULL (s); + + solver_free (s); + fclose (in); +} + +TEST (Solver, constructor6) +{ + FILE* in = generate_file ("0 1\n2 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + + TEST_ASSERT_NULL (s); + + solver_free (s); + fclose (in); +} + +TEST (Solver, constructor7) +{ + FILE* in = generate_file ("1 0\n2 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + + TEST_ASSERT_NULL (s); + + solver_free (s); + fclose (in); +} + +TEST (Solver, constructor8) +{ +#ifdef __cplusplus + uint8_t* const stack = (uint8_t*)alloca (solver_size); +#elif (__STDC_VERSION__ < 201112L) + uint8_t* const stack = nullptr; +#else + alignas (max_align_t) uint8_t stack[solver_size]; +#endif + FILE* in = generate_file ("1 1\n1 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in, false, stack); + + TEST_ASSERT_NOT_NULL (s); + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve0) +{ + FILE* in = generate_file ("1 1 \n\n 2 4"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (2.0, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const number_solutions expected_number_solutions = number_solutions_one; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve1) +{ + FILE* in = generate_file ("1 1 \n2 4"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (2.0, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const number_solutions expected_number_solutions = number_solutions_one; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve2) +{ + FILE* in = generate_file ("2 2\n1 2 3\n4 5 6"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (-1.0, 0.0), CMPLX (2.0, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const number_solutions expected_number_solutions = number_solutions_one; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve3) +{ + FILE* in = generate_file ("2 2\n4 5 7\n3 9 9"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (0.85714, 0.0), CMPLX (0.71429, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const number_solutions expected_number_solutions = number_solutions_one; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve4) +{ + FILE* in = generate_file ("3 3\n1 1 2 9\n2 4 -3 1\n3 6 -5 0"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (1.0, 0.0), CMPLX (2.0, 0.0), CMPLX (3.0, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const number_solutions expected_number_solutions = number_solutions_one; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve5) +{ + FILE* in = generate_file ("2 2\n0 1 1\n1 0 1"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (1.0, 0.0), CMPLX (1.0, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const number_solutions expected_number_solutions = number_solutions_one; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve6) +{ + FILE* in = generate_file ("2 2\n0 1 1\n0 2 2"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (0.0, 0.0), CMPLX (1.0, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const char* expected_general_solution[] = { "x1", "1" }; + const size_t expected_general_solution_size = sizeof ( + expected_general_solution) / sizeof (expected_general_solution[0]); + const number_solutions expected_number_solutions = number_solutions_many; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NOT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + TEST_ASSERT_EQUAL (expected_general_solution_size, + actual_general_solution_size); + TEST_ASSERT_EQUAL_STRING_ARRAY (actual_general_solution, + expected_general_solution, actual_general_solution_size); + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve7) +{ + FILE* in = generate_file ("2 2\n0 1 1\n0 2 3"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const number_solutions expected_number_solutions = number_solutions_none; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve8) +{ + FILE* in = generate_file ("3 4\n0 1 2 9\n0 1 3 1\n1 0 6 0\n2 0 2 0"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const number_solutions expected_number_solutions = number_solutions_none; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve9) +{ + FILE* in = generate_file ("3 1\n1 1 2 9"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (9.0, 0.0), CMPLX (0.0, 0.0), CMPLX (0.0, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const char* expected_general_solution[] = { "9 - x2 - x3 * (2)", "x2", "x3" }; + const size_t expected_general_solution_size = sizeof ( + expected_general_solution) / sizeof (expected_general_solution[0]); + const number_solutions expected_number_solutions = number_solutions_many; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NOT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + TEST_ASSERT_EQUAL (expected_general_solution_size, + actual_general_solution_size); + TEST_ASSERT_EQUAL_STRING_ARRAY (actual_general_solution, + expected_general_solution, actual_general_solution_size); + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve10) +{ + FILE* in = generate_file ("4 4\n1 0 0 5 0\n0 0 0 0 0\n0 0 1 4 6\n0 0 5 5 5"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (-8.3333333, 0.0), CMPLX (0.0, 0.0), CMPLX (-0.6666667, 0.0), CMPLX (1.6666667, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const char* expected_general_solution[] = { "-8.3333", "x2", "-0.6667", "1.6667" }; + const size_t expected_general_solution_size = sizeof ( + expected_general_solution) / sizeof (expected_general_solution[0]); + const number_solutions expected_number_solutions = number_solutions_many; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NOT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + TEST_ASSERT_EQUAL (expected_general_solution_size, + actual_general_solution_size); + TEST_ASSERT_EQUAL_STRING_ARRAY (actual_general_solution, + expected_general_solution, actual_general_solution_size); + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve11) +{ + FILE* in = + generate_file ("4 4\n2 3 -1 1 1\n8 12 -9 8 3\n4 6 3 -2 3\n2 3 9 -7 3"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (0.6, 0.0), CMPLX (0.0, 0.0), CMPLX (0.2, 0.0), CMPLX (0.0, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const char* expected_general_solution[] = { "0.6 - x2 * (1.5) - x4 * (0.1)", "x2", "0.2 - x4 * (-0.8)", "x4" }; + const size_t expected_general_solution_size = sizeof ( + expected_general_solution) / sizeof (expected_general_solution[0]); + const number_solutions expected_number_solutions = number_solutions_many; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NOT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + TEST_ASSERT_EQUAL (expected_general_solution_size, + actual_general_solution_size); + TEST_ASSERT_EQUAL_STRING_ARRAY (actual_general_solution, + expected_general_solution, actual_general_solution_size); + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve12) +{ + FILE* in = + generate_file ("3 3\n1+2i -1.5-1.1i 2.12 91+5i\n-1+3i 1.2+3.5i -3.3 1+15i\n12.31 1.3-5i 12.3i -78.3i"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (6.73335286, -22.99754223), CMPLX (-1.7976071, 2.08404919), CMPLX (15.69938581, 7.3960106)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const number_solutions expected_number_solutions = number_solutions_one; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve13) +{ + FILE* in = generate_file ("1\t1\t2\t4"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (2.0, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const number_solutions expected_number_solutions = number_solutions_one; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve14) +{ + FILE* in = generate_file ("1 1\r\n2 4"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const complex_double expected_partial_solution[] = {CMPLX (2.0, 0.0)}; + const size_t expected_partial_solution_size = sizeof ( + expected_partial_solution) / sizeof (expected_partial_solution[0]); + const number_solutions expected_number_solutions = number_solutions_one; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NOT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + TEST_ASSERT_EQUAL (expected_partial_solution_size, + actual_partial_solution_size); + for (size_t i = 0; i < actual_partial_solution_size; ++i) + { + TEST_ASSERT (complex_equals (actual_partial_solution[i], + expected_partial_solution[i])); + } + + solver_free (s); + fclose (in); +} + +TEST (Solver, solve15) +{ + FILE* in = generate_file ("3 4\n1 1 2 9\n0 1 3 1\n0 2 6 1\n0 0 0 0"); + TEST_ASSERT_NOT_NULL (in); + solver* s = solver_new (in); + TEST_ASSERT_NOT_NULL (s); + solver_solve (s); + + const number_solutions expected_number_solutions = number_solutions_none; + + size_t actual_partial_solution_size = 0; + const complex_double* actual_partial_solution = solver_get_solution_partial (s, + &actual_partial_solution_size); + const number_solutions actual_number_solutions = solver_get_number_solutions ( + s); + size_t actual_general_solution_size = 0; + const char* const* actual_general_solution = solver_get_solution_general (s, + &actual_general_solution_size); + + TEST_ASSERT_NULL (actual_partial_solution); + TEST_ASSERT_NULL (actual_general_solution); + TEST_ASSERT_EQUAL (expected_number_solutions, actual_number_solutions); + + solver_free (s); + fclose (in); +} diff --git a/C/test/test_runners/complex_support.runner.c b/C/test/test_runners/complex_support.runner.c new file mode 100644 index 0000000..a8f655c --- /dev/null +++ b/C/test/test_runners/complex_support.runner.c @@ -0,0 +1,31 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include + +TEST_GROUP_RUNNER (ComplexSupport) +{ + RUN_TEST_CASE (ComplexSupport, to_string1); + RUN_TEST_CASE (ComplexSupport, to_string2); + RUN_TEST_CASE (ComplexSupport, to_string3); + RUN_TEST_CASE (ComplexSupport, to_string4); + RUN_TEST_CASE (ComplexSupport, to_string5); + RUN_TEST_CASE (ComplexSupport, equals1); + RUN_TEST_CASE (ComplexSupport, equals2); + RUN_TEST_CASE (ComplexSupport, equals3); + RUN_TEST_CASE (ComplexSupport, parse1); + RUN_TEST_CASE (ComplexSupport, parse2); + RUN_TEST_CASE (ComplexSupport, parse3); + RUN_TEST_CASE (ComplexSupport, parse4); + RUN_TEST_CASE (ComplexSupport, parse5); + RUN_TEST_CASE (ComplexSupport, parse6); + RUN_TEST_CASE (ComplexSupport, parse7); + RUN_TEST_CASE (ComplexSupport, parse8); + RUN_TEST_CASE (ComplexSupport, parse9); + RUN_TEST_CASE (ComplexSupport, parse10); + RUN_TEST_CASE (ComplexSupport, parse11); + RUN_TEST_CASE (ComplexSupport, parse12); + RUN_TEST_CASE (ComplexSupport, parse13); + RUN_TEST_CASE (ComplexSupport, parse14); + RUN_TEST_CASE (ComplexSupport, parse15); + RUN_TEST_CASE (ComplexSupport, parse16); +} diff --git a/C/test/test_runners/parameters.runner.c b/C/test/test_runners/parameters.runner.c new file mode 100644 index 0000000..8bc7547 --- /dev/null +++ b/C/test/test_runners/parameters.runner.c @@ -0,0 +1,12 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include + +TEST_GROUP_RUNNER (Parameters) +{ + RUN_TEST_CASE (Parameters, default_parameters); + RUN_TEST_CASE (Parameters, in); + RUN_TEST_CASE (Parameters, out); + RUN_TEST_CASE (Parameters, verbose); + RUN_TEST_CASE (Parameters, new_stack); +} diff --git a/C/test/test_runners/solver.runner.c b/C/test/test_runners/solver.runner.c new file mode 100644 index 0000000..27718e6 --- /dev/null +++ b/C/test/test_runners/solver.runner.c @@ -0,0 +1,34 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include + +TEST_GROUP_RUNNER (Solver) +{ + RUN_TEST_CASE (Solver, constructor1); + RUN_TEST_CASE (Solver, constructor2); + RUN_TEST_CASE (Solver, constructor3); + RUN_TEST_CASE (Solver, constructor4); + RUN_TEST_CASE (Solver, constructor5); + RUN_TEST_CASE (Solver, constructor6); + RUN_TEST_CASE (Solver, constructor7); + RUN_TEST_CASE (Solver, constructor8); + RUN_TEST_CASE (Solver, solve0); + RUN_TEST_CASE (Solver, solve1); + RUN_TEST_CASE (Solver, solve2); + RUN_TEST_CASE (Solver, solve3); + RUN_TEST_CASE (Solver, solve4); + RUN_TEST_CASE (Solver, solve5); + RUN_TEST_CASE (Solver, solve6); + RUN_TEST_CASE (Solver, solve7); + RUN_TEST_CASE (Solver, solve8); + RUN_TEST_CASE (Solver, solve9); + RUN_TEST_CASE (Solver, solve10); + RUN_TEST_CASE (Solver, solve11); + RUN_TEST_CASE (Solver, solve12); + RUN_TEST_CASE (Solver, solve13); + RUN_TEST_CASE (Solver, solve14); + RUN_TEST_CASE (Solver, solve15); + RUN_TEST_CASE (Solver, types1); + RUN_TEST_CASE (Solver, types2); + RUN_TEST_CASE (Solver, types3); +} diff --git a/C/valgrind.sh b/C/valgrind.sh new file mode 100755 index 0000000..51d3df0 --- /dev/null +++ b/C/valgrind.sh @@ -0,0 +1,14 @@ +OS="`uname`" +case $OS in + 'Linux') + alias make='make' + ;; + 'FreeBSD') + alias make='gmake' + ;; + *) ;; +esac + +make clean && VALGRIND=1 make && valgrind --track-origins=yes --log-file=valgrind.txt --read-var-info=yes --leak-check=full bin/test_c + + diff --git a/DotNET/DotNET.sln b/DotNET/DotNET.sln new file mode 100644 index 0000000..4a81274 --- /dev/null +++ b/DotNET/DotNET.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{AE08A80F-0BC3-4276-9E4B-FF9EA4557037}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "src", "src\src.csproj", "{6A0B0D41-8EC4-425F-81C8-89F071C80FF8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AE08A80F-0BC3-4276-9E4B-FF9EA4557037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE08A80F-0BC3-4276-9E4B-FF9EA4557037}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE08A80F-0BC3-4276-9E4B-FF9EA4557037}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE08A80F-0BC3-4276-9E4B-FF9EA4557037}.Release|Any CPU.Build.0 = Release|Any CPU + {6A0B0D41-8EC4-425F-81C8-89F071C80FF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A0B0D41-8EC4-425F-81C8-89F071C80FF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A0B0D41-8EC4-425F-81C8-89F071C80FF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A0B0D41-8EC4-425F-81C8-89F071C80FF8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/DotNET/acceptance tests/in.txt b/DotNET/acceptance tests/in.txt new file mode 100644 index 0000000..b1db2cf --- /dev/null +++ b/DotNET/acceptance tests/in.txt @@ -0,0 +1,4 @@ +3 3 +1 1 2 9 +2 4 -3 1 +3 6 -5 0 diff --git a/DotNET/acceptance tests/in1.txt b/DotNET/acceptance tests/in1.txt new file mode 100644 index 0000000..112d10d --- /dev/null +++ b/DotNET/acceptance tests/in1.txt @@ -0,0 +1,5 @@ +3 4 +0 1 2 9 +0 1 3 1 +1 0 6 0 +2 0 2 0 \ No newline at end of file diff --git a/DotNET/acceptance tests/in2.txt b/DotNET/acceptance tests/in2.txt new file mode 100644 index 0000000..512957d --- /dev/null +++ b/DotNET/acceptance tests/in2.txt @@ -0,0 +1,5 @@ +4 4 +1 0 0 5 0 +0 0 0 0 0 +0 0 1 4 6 +0 0 5 5 5 \ No newline at end of file diff --git a/DotNET/acceptance tests/in3.txt b/DotNET/acceptance tests/in3.txt new file mode 100644 index 0000000..3b20f11 --- /dev/null +++ b/DotNET/acceptance tests/in3.txt @@ -0,0 +1,4 @@ +3 3 +1+2i -1.5-1.1i 2.12 91+5i +-1+3i 1.2+3.5i -3.3 1+15i +12.31 1.3-5i 12.3i -78.3i \ No newline at end of file diff --git a/DotNET/acceptance tests/tests.ps1 b/DotNET/acceptance tests/tests.ps1 new file mode 100755 index 0000000..b8ae9cb --- /dev/null +++ b/DotNET/acceptance tests/tests.ps1 @@ -0,0 +1,89 @@ +#!/usr/bin/env pwsh +Describe JavaAcceptanceTests { + It 'single solution' { + Remove-Item "$PSScriptRoot/out.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout.txt" -ErrorAction SilentlyContinue + + mono "$PSScriptRoot/../src/bin/Release/src.exe" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out.txt" -verbose > "$PSScriptRoot/stdout.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(1, 2, 3)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "-2 * R1 +R2 -> R2", "-3 * R1 +R3 -> R3", + "R2 / 2 -> R2", "-3 * R2 +R3 -> R3", "R3 / -0.5 -> R3", + "3.5 * R3 +R2 -> R2", "-2 * R3 +R1 -> R1", "-1 * R2 +R1 -> R1", + "(1, 2, 3)", "Saved to file $PSScriptRoot/out.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no solution' { + Remove-Item "$PSScriptRoot/out1.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout1.txt" -ErrorAction SilentlyContinue + + mono "$PSScriptRoot/../src/bin/Release/src.exe" -in "$PSScriptRoot/in1.txt" -out "$PSScriptRoot/out1.txt" -verbose > "$PSScriptRoot/stdout1.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out1.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "There are no solutions" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout1.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 <-> R3", "-1 * R2 +R3 -> R3", "R3 / -1 -> R3", + "-3 * R3 +R2 -> R2", "-6 * R3 +R1 -> R1", "There are no solutions", "Saved to file $PSScriptRoot/out1.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'many solutions' { + Remove-Item "$PSScriptRoot/out2.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout2.txt" -ErrorAction SilentlyContinue + + mono "$PSScriptRoot/../src/bin/Release/src.exe" -in "$PSScriptRoot/in2.txt" -out "$PSScriptRoot/out2.txt" -verbose > "$PSScriptRoot/stdout2.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out2.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(-8.3333, x2, -0.6667, 1.6667)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout2.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "C3 <-> C2", "R3 <-> R2", "-5 * R2 +R4 -> R4", + "C4 <-> C3", "R4 <-> R3", "R3 / -15 -> R3", "-4 * R3 +R2 -> R2", + "-5 * R3 +R1 -> R1", "(-8.3333, x2, -0.6667, 1.6667)","Saved to file $PSScriptRoot/out2.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'single solution complex numbers' { + Remove-Item "$PSScriptRoot/out3.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout3.txt" -ErrorAction SilentlyContinue + + mono "$PSScriptRoot/../src/bin/Release/src.exe" -in "$PSScriptRoot/in3.txt" -out "$PSScriptRoot/out3.txt" -verbose > "$PSScriptRoot/stdout3.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out3.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout3.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 / 1+2i -> R1", "1-3i * R1 +R2 -> R2", "-12.31 * R1 +R3 -> R3", + "R2 / 1.6+6.1i -> R2", "-10.4094+9.6778i * R2 +R3 -> R3", "R3 / -6.7848+9.7158i -> R3", + "0.5432-0.746i * R3 +R2 -> R2", "-0.424+0.848i * R3 +R1 -> R1", "0.74-0.38i * R2 +R1 -> R1", + "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)", "Saved to file $PSScriptRoot/out3.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no output without -verbose' { + Remove-Item "$PSScriptRoot/out4.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout4.txt" -ErrorAction SilentlyContinue + + mono "$PSScriptRoot/../src/bin/Release/src.exe" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out4.txt" > "$PSScriptRoot/stdout4.txt" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout4.txt") + $stdoutLines.Count | Should Be 0 + } +} diff --git a/DotNET/src/Complex.cs b/DotNET/src/Complex.cs new file mode 100644 index 0000000..ad004ac --- /dev/null +++ b/DotNET/src/Complex.cs @@ -0,0 +1,132 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +using System; +namespace src +{ + public class Complex + { + public static readonly double EPSILON = 0.00001; + + public static bool operator ==(Complex a, Complex b) + { + return !(a is null) && !(b is null) && Math.Abs(a.Imag - b.Imag) < EPSILON && Math.Abs(a.Real - b.Real) < EPSILON; + } + + public static bool operator !=(Complex a, Complex b) + { + return !(a == b); + } + + public static Complex operator +(Complex a, Complex b) + { + return new Complex(a.Real + b.Real, a.Imag + b.Imag); + } + + public static Complex operator /(Complex a, Complex b) + { + Complex bConjugate = b.Conjugate(); + Complex a1 = a * bConjugate; + Complex b1 = b * bConjugate; + + return new Complex(a1.Real / b1.Real, a1.Imag / b1.Real); + } + + public static Complex operator *(Complex a, Complex b) + { + return new Complex(a.Real * b.Real - a.Imag * b.Imag, a.Real * b.Imag + a.Imag * b.Real); + } + + public double Real { get; private set; } + public double Imag { get; private set; } + + public Complex(double real = 0.0, double imag = 0.0) + { + Real = real; + Imag = imag; + } + + public Complex(string s) + { + IFormatProvider iFormatProvider = new System.Globalization.CultureInfo("en-US"); + String[] strs = Split(s); + Real = Double.Parse(strs[0], iFormatProvider); + Imag = Double.Parse(strs[1], iFormatProvider); + } + + public Complex Conjugate() + { + return new Complex(Real, -Imag); + } + + public override string ToString() + { + IFormatProvider iFormatProvider = new System.Globalization.CultureInfo("en-US"); + if (Math.Abs(Imag) < EPSILON) + { + return string.Format(iFormatProvider, "{0:0.####}", Real); + } + if (Math.Abs(Real) < EPSILON) + { + return string.Format(iFormatProvider, "{0:0.####}i", Imag); + } + string prefix = (Imag > 0) ? "+" : ""; + return string.Format(iFormatProvider, "{0:0.####}{1}{2:0.####}i", Real, prefix, Imag); + } + + private string[] Split(string s) + { + s = Restore_omitted_imaginary_coefficient(s); + string realString = "0"; + string imagString = "0"; + int i = 1; + for (; i < s.Length; ++i) + { + if (s[i] == '+' || s[i] == '-') + { + realString = s.Substring(0, i); + imagString = s.Substring(i, s.Length - i - 1); + if (s[s.Length - 1] != 'i') + { + throw new FormatException("can't parse complex"); + } + break; + } + if (s[i] == 'i') + { + if (i != s.Length - 1) + { + throw new FormatException("can't parse complex"); + } + imagString = s.Substring(0, i); + break; + } + } + if (i == s.Length) + { + realString = s; + } + return new string[] { realString, imagString }; + } + + private string Restore_omitted_imaginary_coefficient(string s) + { + if (s == "i") + { + return "1i"; + } + s = s.Replace("+i", "+1i"); + s = s.Replace("-i", "-1i"); + return s; + } + + public override bool Equals(object obj) + { + return obj is Complex && this == (Complex)obj; + } + + public override int GetHashCode() + { + return ToString().GetHashCode(); + } + } +} diff --git a/DotNET/src/NumberSolutions.cs b/DotNET/src/NumberSolutions.cs new file mode 100644 index 0000000..0245206 --- /dev/null +++ b/DotNET/src/NumberSolutions.cs @@ -0,0 +1,11 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +namespace src +{ + public enum NumberSolutions + { + NONE, + ONE, + MANY + } +} diff --git a/DotNET/src/Parameters.cs b/DotNET/src/Parameters.cs new file mode 100644 index 0000000..1963bfd --- /dev/null +++ b/DotNET/src/Parameters.cs @@ -0,0 +1,48 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +using System; +namespace src +{ + public class Parameters + { + public readonly string Input; + public readonly string Output; + public readonly bool Verbose; + public Parameters(string[] args) + { + bool needAssignedIn = true; + string inTemp = "input.txt"; + bool needAssignedOut = true; + string outTemp = "output.txt"; + bool verboseTemp = false; + for (int i = 0; i < args.Length; ++i) + { + if (needAssignedIn && "-in".Equals(args[i])) + { + if (i < args.Length - 1) + { + inTemp = args[i + 1]; + needAssignedIn = false; + ++i; + } + } + else if (needAssignedOut && "-out".Equals(args[i])) + { + if (i < args.Length - 1) + { + outTemp = args[i + 1]; + needAssignedOut = false; + ++i; + } + } + else if (!verboseTemp && "-verbose".Equals(args[i])) + { + verboseTemp = true; + } + } + Input = inTemp; + Output = outTemp; + Verbose = verboseTemp; + } + } +} diff --git a/DotNET/src/Program.cs b/DotNET/src/Program.cs new file mode 100644 index 0000000..3ecff36 --- /dev/null +++ b/DotNET/src/Program.cs @@ -0,0 +1,26 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +using System; +using System.IO; + +namespace src +{ + class Program + { + public static void Main(string[] args) + { + try + { + Parameters p = new Parameters(args); + string fileIn = File.ReadAllText(p.Input); + Solver s = new Solver(fileIn, p.Verbose); + s.Solve(); + s.WriteSolutionToFile(p.Output); + } + catch (Exception e) + { + Console.WriteLine("An exception occurs {0}", e.Message); + } + } + } +} diff --git a/DotNET/src/Properties/AssemblyInfo.cs b/DotNET/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..fef7614 --- /dev/null +++ b/DotNET/src/Properties/AssemblyInfo.cs @@ -0,0 +1,28 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("src")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("${AuthorCopyright}")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/DotNET/src/Solver.cs b/DotNET/src/Solver.cs new file mode 100644 index 0000000..8872645 --- /dev/null +++ b/DotNET/src/Solver.cs @@ -0,0 +1,335 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +using System; +using System.Linq; +using System.IO; +using System.Diagnostics; +namespace src +{ + public class Solver + { + private static readonly Complex ZERO = new Complex(0.0, 0.0); + private static readonly Complex ONE = new Complex(1.0, 0.0); + private static readonly Complex MINUS_ONE = new Complex(-1.0, 0.0); + + private readonly int numberEquations; + private readonly int numberVariables; + private readonly Complex[,] matrix; + private readonly Complex[] solutionPartial; + private string[] solutionGeneral; + private readonly int[] solutionIndexes; + private readonly bool verbose; + public NumberSolutions NumberSolutions { get; private set; } + + + public Solver(string s, bool verbose = false) + { + NumberSolutions = NumberSolutions.ONE; + var args = s.Split(new char[] { '\r', '\n', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + int argsI = 0; + numberVariables = int.Parse(args[argsI++]); + int realNumberEquations = int.Parse(args[argsI++]); + if (numberVariables < 1 || realNumberEquations < 1) { + throw new FormatException("wrong input data"); + } + numberEquations = (realNumberEquations < numberVariables) ? numberVariables : realNumberEquations; + matrix = new Complex[numberEquations, numberVariables + 1]; + for (int i = 0; i < realNumberEquations; ++i) { + for (int j = 0; j < numberVariables + 1; ++j) { + matrix[i, j] = new Complex(args[argsI++]); + } + } + for (int i = realNumberEquations; i < numberEquations; ++i) { + for (int j = 0; j < numberVariables + 1; ++j) { + matrix[i, j] = new Complex(); + } + } + solutionPartial = new Complex[numberVariables]; + solutionGeneral = new String[numberVariables]; + solutionIndexes = Enumerable.Range(0, numberVariables).ToArray(); + this.verbose = verbose; + } + + public string[] GetSolutionGeneral() + { + if (NumberSolutions != NumberSolutions.MANY) + { + return null; + } + return (string[])solutionGeneral.Clone(); + } + + public Complex[] GetSolutionPartial() + { + if (NumberSolutions == NumberSolutions.NONE) + { + return null; + } + return (Complex[])solutionPartial.Clone(); + } + + public void Solve() + { + if (verbose) + { + Console.WriteLine("Start solving the equation."); + Console.WriteLine("Rows manipulation:"); + } + GausFirstStep(); + if (NumberSolutions != NumberSolutions.NONE) + { + GausSecondStep(); + GenerateSolutions(); + CheckThatSolutionIsSane(); + } + PrintSolution(); + } + + public void WriteSolutionToFile(string outfile) + { + StreamWriter printWriter = new StreamWriter(outfile); + PrintSolutionInternal(printWriter); + printWriter.Close(); + if (verbose) { + Console.WriteLine("Saved to file {0}", outfile); + } + } + + private void AddKRow1ToRow2(Complex k, int row1, int row2) + { + if (verbose) + { + Console.WriteLine("{0} * R{1} +R{2} -> R{2}", k, row1 + 1, row2 + 1); + } + for (int i = 0; i < numberVariables + 1; ++i) + { + Complex temp = k * matrix[row1, i]; + matrix[row2, i] += temp; + } + } + + private void CheckThatSolutionIsSane() + { + for (int i = numberVariables; i < numberEquations; ++i) + { + Complex sum = new Complex(0.0, 0.0); + for (int j = 0; j < numberVariables; ++j) + { + Complex temp = solutionPartial[solutionIndexes[j]] * matrix[i, solutionIndexes[j]]; + sum += temp; + } + if (sum != matrix[i, numberVariables]) + { + NumberSolutions = NumberSolutions.NONE; + return; + } + } + } + + private void DivideRow(int row, Complex k) + { + if (verbose) + { + Console.WriteLine("R{0} / {1} -> R{0}", row + 1, k); + } + for (int i = 0; i < numberVariables + 1; ++i) + { + matrix[row, i] /= k; + } + } + + private void GausFirstStep() + { + for (int i = 0; i < numberVariables; ++i) + { + if (matrix[i, i] == ZERO) + { + bool foundNonZeroElement = false; + for (int j = i + 1; j < numberEquations; ++j) + { + if (matrix[j, i] != ZERO) + { + SwapRows(i, j); + foundNonZeroElement = true; + break; + } + } + if (!foundNonZeroElement) + { + for (int j = i + 1; j < numberVariables; ++j) + { + if (matrix[i, j] != ZERO) + { + SwapColumns(i, j); + foundNonZeroElement = true; + break; + } + } + } + + if (!foundNonZeroElement) + { + for (int k = i + 1; !foundNonZeroElement && k < numberVariables; ++k) + { + for (int j = i + 1; j < numberEquations; ++j) + { + if (matrix[j, k] != ZERO) + { + SwapColumns(k, i); + SwapRows(j, i); + foundNonZeroElement = true; + break; + } + } + } + } + + if (!foundNonZeroElement) + { + if (matrix[i, numberVariables] == ZERO) + { + NumberSolutions = NumberSolutions.MANY; + continue; + } + else + { + NumberSolutions = NumberSolutions.NONE; + return; + } + } + } + + if (matrix[i, i] != ONE) + { + DivideRow(i, matrix[i, i]); + } + for (int j = i + 1; j < numberEquations && j < numberVariables; ++j) + { + Complex k = MINUS_ONE * matrix[j, i]; + if (k != ZERO) + { + AddKRow1ToRow2(k, i, j); + } + } + } + } + + private void GausSecondStep() + { + for (int i = numberVariables - 1; i >= 0; --i) + { + for (int j = i - 1; j >= 0; --j) + { + Complex k = MINUS_ONE * matrix[j, i]; + if (k != ZERO) + { + AddKRow1ToRow2(k, i, j); + } + } + } + } + + private void GenerateSolutions() + { + for (int i = 0; i < numberEquations && i < numberVariables; ++i) + { + solutionPartial[solutionIndexes[i]] = matrix[i, numberVariables]; + if (matrix[i, i] == ZERO) + { + solutionGeneral[solutionIndexes[i]] = "x" + (solutionIndexes[i] + 1); + } + else + { + solutionGeneral[solutionIndexes[i]] = matrix[i, numberVariables].ToString(); + for (int j = i + 1; j < numberVariables; ++j) + { + if (matrix[i, j] == ONE) + { + solutionGeneral[solutionIndexes[i]] = solutionGeneral[solutionIndexes[i]] + " - x" + + (solutionIndexes[j] + 1); + } + else if (matrix[i, j] != ZERO) + { + solutionGeneral[solutionIndexes[i]] = solutionGeneral[solutionIndexes[i]] + " - x" + + (solutionIndexes[j] + 1) + " * (" + matrix[i, j] + ")"; + } + } + } + } + } + + private void PrintSolution() + { + if (verbose) + { + var writer = new StreamWriter(Console.OpenStandardOutput()) + { + AutoFlush = true + }; + PrintSolutionInternal(writer); + } + } + + private void PrintSolutionInternal(StreamWriter printWriter) + { + switch (NumberSolutions) + { + case NumberSolutions.NONE: + printWriter.WriteLine("There are no solutions"); + break; + case NumberSolutions.ONE: + printWriter.Write("({0}", solutionPartial[0]); + for (int i = 1; i < solutionPartial.Length; ++i) + { + printWriter.Write(", {0}", solutionPartial[i]); + } + printWriter.WriteLine(")"); + break; + case NumberSolutions.MANY: + printWriter.Write("({0}", solutionGeneral[0]); + for (int i = 1; i < solutionGeneral.Length; ++i) + { + printWriter.Write(", {0}", solutionGeneral[i]); + } + printWriter.WriteLine(")"); + break; + default: + Trace.Assert(false); + break; + } + printWriter.Flush(); + } + + private void SwapColumns(int column1, int column2) + { + if (verbose) + { + Console.WriteLine("C{0} <-> C{1}", column1 + 1, column2 + 1); + } + for (int i = 0; i < numberEquations; ++i) + { + Complex temp1 = matrix[i, column1]; + matrix[i, column1] = matrix[i, column2]; + matrix[i, column2] = temp1; + } + int temp2 = solutionIndexes[column1]; + solutionIndexes[column1] = solutionIndexes[column2]; + solutionIndexes[column2] = temp2; + } + + private void SwapRows(int row1, int row2) + { + if (verbose) + { + Console.WriteLine("R{0} <-> R{1}", row1 + 1, row2 + 1); + } + for (int i = 0; i < numberVariables + 1; ++i) + { + Complex temp = matrix[row1, i]; + matrix[row1, i] = matrix[row2, i]; + matrix[row2, i] = temp; + } + } + } +} + diff --git a/DotNET/src/src.csproj b/DotNET/src/src.csproj new file mode 100644 index 0000000..4576e95 --- /dev/null +++ b/DotNET/src/src.csproj @@ -0,0 +1,41 @@ + + + + Debug + AnyCPU + {6A0B0D41-8EC4-425F-81C8-89F071C80FF8} + Exe + src + src + v4.5 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + true + bin\Release + prompt + 4 + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DotNET/tests/ComplexTest.cs b/DotNET/tests/ComplexTest.cs new file mode 100644 index 0000000..fe78e96 --- /dev/null +++ b/DotNET/tests/ComplexTest.cs @@ -0,0 +1,253 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +using NUnit.Framework; +using src; +using System; +namespace tests +{ + [TestFixture()] + public class ComplexTest + { + [Test()] + public void Equals1() + { + Complex a = new Complex(1.0, 2.0); + Complex b = new Complex(1.0, 2.0); + Assert.AreEqual(a, b); + } + [Test()] + public void Equals2() + { + Complex a = new Complex(1.0, 2.0); + Assert.AreNotEqual("Hello", a); + } + + [Test()] + public void Equals3() + { + Complex a = new Complex(1.0, 2.0); + Complex b = new Complex(1.1, 2.0); + Assert.AreNotEqual(b, a); + } + + [Test()] + public void Equals4() + { + Complex a = new Complex(1.0, 2.1); + Complex b = new Complex(1.0, 2.0); + Assert.AreNotEqual(b, a); + } + [Test()] + public void ToString1() + { + Complex a = new Complex(1.0, 0.0); + Assert.AreEqual("1", a.ToString()); + } + [Test()] + public void ToString2() + { + Complex a = new Complex(0.0, 1.0); + Assert.AreEqual("1i", a.ToString()); + } + [Test()] + public void ToString3() + { + Complex a = new Complex(-2.4, 1.5); + Assert.AreEqual("-2.4+1.5i", a.ToString()); + } + [Test()] + public void ToString4() + { + Complex a = new Complex(2.4, -1.5); + Assert.AreEqual("2.4-1.5i", a.ToString()); + } + + [Test()] + public void ToString5() + { + Complex a = new Complex(0, 0); + Assert.AreEqual("0", a.ToString()); + } + [Test()] + public void DefaultConstructor() + { + Complex a = new Complex(0.0, 0.0); + Complex b = new Complex(); + Assert.AreEqual(a, b); + } + [Test()] + public void Constructor1() + { + Complex c = new Complex(1.0, 0.0); + Assert.AreEqual(1.0, c.Real, Complex.EPSILON); + Assert.AreEqual(0.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Constructor2() + { + TestDelegate f = () => { Complex a = new Complex("gbc"); }; + Assert.Throws(f); + } + [Test()] + public void Constructor3() + { + string s = "-1.3"; + Complex c = new Complex(s); + Assert.AreEqual(-1.3, c.Real, Complex.EPSILON); + Assert.AreEqual(0.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Constructor4() + { + string s = "2.5i"; + Complex c = new Complex(s); + Assert.AreEqual(0.0, c.Real, Complex.EPSILON); + Assert.AreEqual(2.5, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Constructor5() + { + string s = "1.3-2.5i"; + Complex c = new Complex(s); + Assert.AreEqual(1.3, c.Real, Complex.EPSILON); + Assert.AreEqual(-2.5, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Constructor6() + { + string s = "1"; + Complex c = new Complex(s); + Assert.AreEqual(1.0, c.Real, Complex.EPSILON); + Assert.AreEqual(0.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Constructor7() + { + TestDelegate f = () => { Complex a = new Complex("1.3-2.5"); }; + Assert.Throws(f); + } + + [Test()] + public void Constructor8() + { + TestDelegate f = () => { Complex a = new Complex("1.3i-2.5"); }; + Assert.Throws(f); + } + [Test()] + public void Constructor9() + { + TestDelegate f = () => { Complex a = new Complex("1.3ij"); }; + Assert.Throws(f); + } + + [Test()] + public void Constructor10() + { + TestDelegate f = () => { Complex a = new Complex("1.3+3.5546ij"); }; + Assert.Throws(f); + } + + [Test()] + public void Constructor11() + { + TestDelegate f = () => { Complex a = new Complex("1.3ji"); }; + Assert.Throws(f); + } + + [Test()] + public void Constructor12() + { + TestDelegate f = () => { Complex a = new Complex("1.3+3.5546ji"); }; + Assert.Throws(f); + } + + [Test()] + public void Constructor13() + { + string s = "i"; + Complex c = new Complex(s); + Assert.AreEqual(0.0, c.Real, Complex.EPSILON); + Assert.AreEqual(1.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Constructor14() + { + string s = "-i"; + Complex c = new Complex(s); + Assert.AreEqual(0.0, c.Real, Complex.EPSILON); + Assert.AreEqual(-1.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Constructor15() + { + string s = "0.5+i"; + Complex c = new Complex(s); + Assert.AreEqual(0.5, c.Real, Complex.EPSILON); + Assert.AreEqual(1.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Constructor16() + { + string s = "0.5-i"; + Complex c = new Complex(s); + Assert.AreEqual(0.5, c.Real, Complex.EPSILON); + Assert.AreEqual(-1.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Constructor17() + { + string s = "+i"; + Complex c = new Complex(s); + Assert.AreEqual(0.0, c.Real, Complex.EPSILON); + Assert.AreEqual(1.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Add() + { + Complex a = new Complex(3.0, -5.0); + Complex b = new Complex(4.0, 2.0); + Complex c = a + b; + Assert.AreEqual(7.0, c.Real, Complex.EPSILON); + Assert.AreEqual(-3.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Multiply() + { + Complex a = new Complex(3.0, 2.0); + Complex b = new Complex(1.0, 7.0); + Complex c = a* b; + Assert.AreEqual(-11.0, c.Real, Complex.EPSILON); + Assert.AreEqual(23.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Conjugate() + { + Complex a = new Complex(3.0, 2.0); + Complex c = a.Conjugate(); + Assert.AreEqual(3.0, c.Real, Complex.EPSILON); + Assert.AreEqual(-2.0, c.Imag, Complex.EPSILON); + } + + [Test()] + public void Divide() + { + Complex a = new Complex(2.0, 3.0); + Complex b = new Complex(4.0, -5.0); + Complex c = a / b; + Assert.AreEqual(-7.0 / 41.0, c.Real, Complex.EPSILON); + Assert.AreEqual(22.0 / 41.0, c.Imag, Complex.EPSILON); + } + } +} diff --git a/DotNET/tests/ParametersTest.cs b/DotNET/tests/ParametersTest.cs new file mode 100644 index 0000000..a03a111 --- /dev/null +++ b/DotNET/tests/ParametersTest.cs @@ -0,0 +1,41 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +using NUnit.Framework; +using src; + +namespace tests +{ + [TestFixture()] + public class ParametersTest + { + [Test()] + public void DefaultParameters() + { + Parameters p = new Parameters(new string[] { }); + Assert.AreEqual("input.txt", p.Input); + Assert.AreEqual("output.txt", p.Output); + Assert.False(p.Verbose); + } + + [Test()] + public void Input() + { + Parameters p = new Parameters(new string[] { "-in", "in.txt" }); + Assert.AreEqual("in.txt", p.Input); + } + + [Test()] + public void Output() + { + Parameters p = new Parameters(new string[] { "-out", "out2.txt" }); + Assert.AreEqual("out2.txt", p.Output); + } + + [Test()] + public void Verbose() + { + Parameters p = new Parameters(new string[] { "-verbose" }); + Assert.True(p.Verbose); + } + } +} diff --git a/DotNET/tests/SolverTest.cs b/DotNET/tests/SolverTest.cs new file mode 100644 index 0000000..7d6ea9b --- /dev/null +++ b/DotNET/tests/SolverTest.cs @@ -0,0 +1,322 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +using NUnit.Framework; +using src; +using System; +namespace tests +{ + [TestFixture()] + public class SolverTest + { + [Test()] + public void Types1() + { + void f() + { + Solver p = new Solver("1 1\n1 2"); + p.Solve(); + NumberSolutions n = p.NumberSolutions; + Assert.AreEqual(NumberSolutions.ONE, n); + n = NumberSolutions.MANY; + Assert.AreEqual(NumberSolutions.ONE, p.NumberSolutions); + + } + Assert.DoesNotThrow(f); + } + + [Test()] + public void Types2() + { + void f() + { + Solver p = new Solver("1 1\n1 2"); + p.Solve(); + var array = p.GetSolutionPartial(); + Complex expected = new Complex(2.0, 0.0); + Assert.AreEqual(expected, array[0]); + array[0] = new Complex(); + array = p.GetSolutionPartial(); + Assert.AreEqual(expected, array[0]); + + } + Assert.DoesNotThrow(f); + } + + [Test()] + public void Types3() + { + void f() + { + Solver p = new Solver("1 1\n0 0"); + p.Solve(); + var array = p.GetSolutionGeneral(); + string expected = "x1"; + Assert.AreEqual(expected, array[0]); + array[0] = "hello"; + array = p.GetSolutionGeneral(); + Assert.AreEqual(expected, array[0]); + + } + Assert.DoesNotThrow(f); + } + + [Test()] + public void Constructor1() + { + void f() { Solver p = new Solver("1 1\n1 2"); } + Assert.DoesNotThrow(f); + } + [Test()] + public void Constructor2() + { + void f() { Solver p = new Solver("1 1\nab 2"); } + Assert.Throws(f); + } + [Test()] + public void Constructor3() + { + void f() { Solver p = new Solver("-1 1\n2 2"); } + Assert.Throws(f); + } + [Test()] + public void Constructor4() + { + void f() { Solver p = new Solver("1 -1\n2 2"); } + Assert.Throws(f); + } + + [Test()] + public void Constructor5() + { + void f() { Solver p = new Solver("1 1\n2"); } + Assert.Throws(f); + } + [Test()] + public void Constructor6() + { + void f() { Solver p = new Solver("0 1\n2 2"); } + Assert.Throws(f); + } + [Test()] + public void Constructor7() + { + void f() { Solver p = new Solver("1 0\n2 2"); } + Assert.Throws(f); + } + [Test()] + public void Solve0() + { + string s = "1 1 \n\n 2 4"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(2.0, 0) }; + + Assert.AreEqual(NumberSolutions.ONE, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve1() + { + string s = "1 1\n2 4"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(2.0, 0) }; + + Assert.AreEqual(NumberSolutions.ONE, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve2() + { + string s = "2 2\n1 2 3\n4 5 6"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(-1.0, 0), new Complex(2.0, 0) }; + + Assert.AreEqual(NumberSolutions.ONE, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve3() + { + string s = "2 2\n4 5 7\n3 9 9"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(0.85714, 0), + new Complex(0.71429, 0) }; + + Assert.AreEqual(NumberSolutions.ONE, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve4() + { + string s = "3 3\n1 1 2 9\n2 4 -3 1\n3 6 -5 0"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(1.0, 0), + new Complex(2.0, 0), new Complex(3.0, 0) }; + + Assert.AreEqual(NumberSolutions.ONE, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve5() + { + string s = "2 2\n0 1 1\n1 0 1"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(1.0, 0), + new Complex(1.0, 0) }; + + Assert.AreEqual(NumberSolutions.ONE, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve6() + { + string s = "2 2\n0 1 1\n0 2 2"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(0.0, 0), + new Complex(1.0, 0) }; + string[] expectedGeneralSolution = { "x1", "1" }; + + Assert.AreEqual(NumberSolutions.MANY, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(expectedGeneralSolution, p.GetSolutionGeneral()); + } + [Test()] + public void Solve7() + { + string s = "2 2\n0 1 1\n0 2 3"; + Solver p = new Solver(s); + p.Solve(); + + Assert.AreEqual(NumberSolutions.NONE, p.NumberSolutions); + Assert.AreEqual(null, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve8() + { + string s = "3 4\n0 1 2 9\n0 1 3 1\n1 0 6 0\n2 0 2 0"; + Solver p = new Solver(s); + p.Solve(); + + Assert.AreEqual(NumberSolutions.NONE, p.NumberSolutions); + Assert.AreEqual(null, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve9() + { + string s = "3 1\n1 1 2 9"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(9.0, 0), + new Complex(0, 0), new Complex(0, 0) }; + string[] expectedGeneralSolution = { "9 - x2 - x3 * (2)", "x2", "x3" }; + + Assert.AreEqual(NumberSolutions.MANY, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(expectedGeneralSolution, p.GetSolutionGeneral()); + } + [Test()] + public void Solve10() + { + string s = "4 4\n1 0 0 5 0\n0 0 0 0 0\n0 0 1 4 6\n0 0 5 5 5"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(-8.3333333, 0), + new Complex(0, 0), new Complex(-0.6666667, 0), new Complex(1.6666667, 0) }; + string[] expectedGeneralSolution = { "-8.3333", "x2", "-0.6667", "1.6667" }; + + Assert.AreEqual(NumberSolutions.MANY, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(expectedGeneralSolution, p.GetSolutionGeneral()); + } + [Test()] + public void Solve11() + { + string s = "4 4\n2 3 -1 1 1\n8 12 -9 8 3\n4 6 3 -2 3\n2 3 9 -7 3"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(0.6, 0), + new Complex(0, 0), new Complex(0.2, 0), new Complex(0, 0) }; + string[] expectedGeneralSolution = { "0.6 - x2 * (1.5) - x4 * (0.1)", "x2", + "0.2 - x4 * (-0.8)", "x4" }; + + Assert.AreEqual(NumberSolutions.MANY, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(expectedGeneralSolution, p.GetSolutionGeneral()); + } + [Test()] + public void Solve12() + { + string s = "3 3\n1+2i -1.5-1.1i 2.12 91+5i\n-1+3i 1.2+3.5i -3.3 1+15i\n12.31 1.3-5i 12.3i -78.3i"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(6.73335286, -22.99754223), + new Complex(-1.7976071, 2.08404919), new Complex(15.69938581, 7.3960106) }; + + Assert.AreEqual(NumberSolutions.ONE, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve13() + { + string s = "1\t1\t2\t4"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(2.0, 0) }; + + Assert.AreEqual(NumberSolutions.ONE, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve14() + { + string s = "1 1\r\n2 4"; + Solver p = new Solver(s); + p.Solve(); + + Complex[] expectedPartialSolution = { new Complex(2.0, 0) }; + + Assert.AreEqual(NumberSolutions.ONE, p.NumberSolutions); + Assert.AreEqual(expectedPartialSolution, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + [Test()] + public void Solve15() + { + string s = "3 4\n1 1 2 9\n0 1 3 1\n0 2 6 1\n0 0 0 0"; + Solver p = new Solver(s); + p.Solve(); + + Assert.AreEqual(NumberSolutions.NONE, p.NumberSolutions); + Assert.AreEqual(null, p.GetSolutionPartial()); + Assert.AreEqual(null, p.GetSolutionGeneral()); + } + } +} diff --git a/DotNET/tests/packages.config b/DotNET/tests/packages.config new file mode 100644 index 0000000..66057d2 --- /dev/null +++ b/DotNET/tests/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/DotNET/tests/tests.csproj b/DotNET/tests/tests.csproj new file mode 100644 index 0000000..3493605 --- /dev/null +++ b/DotNET/tests/tests.csproj @@ -0,0 +1,58 @@ + + + + + + Debug + AnyCPU + {AE08A80F-0BC3-4276-9E4B-FF9EA4557037} + Library + tests + tests + v4.5 + + + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + + + true + bin\Release + prompt + 4 + + + + + ..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll + + + + + + + + + + {6A0B0D41-8EC4-425F-81C8-89F071C80FF8} + src + + + + + + + + + Данный проект ссылается на пакеты NuGet, отсутствующие на этом компьютере. Используйте восстановление пакетов NuGet, чтобы скачать их. Дополнительную информацию см. по адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}. + + + + \ No newline at end of file diff --git a/Java/.idea/checkstyle-idea.xml b/Java/.idea/checkstyle-idea.xml new file mode 100644 index 0000000..b3059d6 --- /dev/null +++ b/Java/.idea/checkstyle-idea.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/Java/.idea/compiler.xml b/Java/.idea/compiler.xml new file mode 100644 index 0000000..7d7a0fd --- /dev/null +++ b/Java/.idea/compiler.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/Java/.idea/encodings.xml b/Java/.idea/encodings.xml new file mode 100644 index 0000000..f13fa33 --- /dev/null +++ b/Java/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Java/.idea/libraries/junit_junit_4_12.xml b/Java/.idea/libraries/junit_junit_4_12.xml new file mode 100644 index 0000000..76510ff --- /dev/null +++ b/Java/.idea/libraries/junit_junit_4_12.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Java/.idea/libraries/org_jetbrains_annotations_16_0_3.xml b/Java/.idea/libraries/org_jetbrains_annotations_16_0_3.xml new file mode 100644 index 0000000..1e76a4d --- /dev/null +++ b/Java/.idea/libraries/org_jetbrains_annotations_16_0_3.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Java/.idea/misc.xml b/Java/.idea/misc.xml new file mode 100644 index 0000000..df60b67 --- /dev/null +++ b/Java/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/Java/.idea/modules.xml similarity index 100% rename from .idea/modules.xml rename to Java/.idea/modules.xml diff --git a/Java/.idea/modules/Java.iml b/Java/.idea/modules/Java.iml new file mode 100644 index 0000000..a8aec01 --- /dev/null +++ b/Java/.idea/modules/Java.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Java/.idea/modules/Java.main.iml b/Java/.idea/modules/Java.main.iml new file mode 100644 index 0000000..a720554 --- /dev/null +++ b/Java/.idea/modules/Java.main.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Java/.idea/modules/Java.test.iml b/Java/.idea/modules/Java.test.iml new file mode 100644 index 0000000..dd331e2 --- /dev/null +++ b/Java/.idea/modules/Java.test.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Java/.idea/project.iml b/Java/.idea/project.iml new file mode 100644 index 0000000..9362fd9 --- /dev/null +++ b/Java/.idea/project.iml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Java/.idea/workspace.xml b/Java/.idea/workspace.xml new file mode 100644 index 0000000..5eab856 --- /dev/null +++ b/Java/.idea/workspace.xml @@ -0,0 +1,664 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1545073768711 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No facets are configured + + + + + + + + + + + + + + + 11 + + + + + + + + project + + + + + + + + org.jetbrains:annotations:16.0.3 + + + + + + + + \ No newline at end of file diff --git a/Java/acceptance tests/in.txt b/Java/acceptance tests/in.txt new file mode 100644 index 0000000..b1db2cf --- /dev/null +++ b/Java/acceptance tests/in.txt @@ -0,0 +1,4 @@ +3 3 +1 1 2 9 +2 4 -3 1 +3 6 -5 0 diff --git a/Java/acceptance tests/in1.txt b/Java/acceptance tests/in1.txt new file mode 100644 index 0000000..112d10d --- /dev/null +++ b/Java/acceptance tests/in1.txt @@ -0,0 +1,5 @@ +3 4 +0 1 2 9 +0 1 3 1 +1 0 6 0 +2 0 2 0 \ No newline at end of file diff --git a/Java/acceptance tests/in2.txt b/Java/acceptance tests/in2.txt new file mode 100644 index 0000000..512957d --- /dev/null +++ b/Java/acceptance tests/in2.txt @@ -0,0 +1,5 @@ +4 4 +1 0 0 5 0 +0 0 0 0 0 +0 0 1 4 6 +0 0 5 5 5 \ No newline at end of file diff --git a/Java/acceptance tests/in3.txt b/Java/acceptance tests/in3.txt new file mode 100644 index 0000000..3b20f11 --- /dev/null +++ b/Java/acceptance tests/in3.txt @@ -0,0 +1,4 @@ +3 3 +1+2i -1.5-1.1i 2.12 91+5i +-1+3i 1.2+3.5i -3.3 1+15i +12.31 1.3-5i 12.3i -78.3i \ No newline at end of file diff --git a/Java/acceptance tests/tests.ps1 b/Java/acceptance tests/tests.ps1 new file mode 100755 index 0000000..75653cd --- /dev/null +++ b/Java/acceptance tests/tests.ps1 @@ -0,0 +1,89 @@ +#!/usr/bin/env pwsh +Describe JavaAcceptanceTests { + It 'single solution' { + Remove-Item "$PSScriptRoot/out.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout.txt" -ErrorAction SilentlyContinue + + java -classpath "$PSScriptRoot/../out/production/project" solver.Main -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out.txt" -verbose > "$PSScriptRoot/stdout.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(1, 2, 3)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "-2 * R1 +R2 -> R2", "-3 * R1 +R3 -> R3", + "R2 / 2 -> R2", "-3 * R2 +R3 -> R3", "R3 / -0.5 -> R3", + "3.5 * R3 +R2 -> R2", "-2 * R3 +R1 -> R1", "-1 * R2 +R1 -> R1", + "(1, 2, 3)", "Saved to file $PSScriptRoot/out.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no solution' { + Remove-Item "$PSScriptRoot/out1.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout1.txt" -ErrorAction SilentlyContinue + + java -classpath "$PSScriptRoot/../out/production/project" solver.Main -in "$PSScriptRoot/in1.txt" -out "$PSScriptRoot/out1.txt" -verbose > "$PSScriptRoot/stdout1.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out1.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "There are no solutions" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout1.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 <-> R3", "-1 * R2 +R3 -> R3", "R3 / -1 -> R3", + "-3 * R3 +R2 -> R2", "-6 * R3 +R1 -> R1", "There are no solutions", "Saved to file $PSScriptRoot/out1.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'many solutions' { + Remove-Item "$PSScriptRoot/out2.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout2.txt" -ErrorAction SilentlyContinue + + java -classpath "$PSScriptRoot/../out/production/project" solver.Main -in "$PSScriptRoot/in2.txt" -out "$PSScriptRoot/out2.txt" -verbose > "$PSScriptRoot/stdout2.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out2.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(-8.3333, x2, -0.6667, 1.6667)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout2.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "C3 <-> C2", "R3 <-> R2", "-5 * R2 +R4 -> R4", + "C4 <-> C3", "R4 <-> R3", "R3 / -15 -> R3", "-4 * R3 +R2 -> R2", + "-5 * R3 +R1 -> R1", "(-8.3333, x2, -0.6667, 1.6667)","Saved to file $PSScriptRoot/out2.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'single solution complex numbers' { + Remove-Item "$PSScriptRoot/out3.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout3.txt" -ErrorAction SilentlyContinue + + java -classpath "$PSScriptRoot/../out/production/project" solver.Main -in "$PSScriptRoot/in3.txt" -out "$PSScriptRoot/out3.txt" -verbose > "$PSScriptRoot/stdout3.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out3.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout3.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 / 1+2i -> R1", "1-3i * R1 +R2 -> R2", "-12.31 * R1 +R3 -> R3", + "R2 / 1.6+6.1i -> R2", "-10.4094+9.6778i * R2 +R3 -> R3", "R3 / -6.7848+9.7158i -> R3", + "0.5432-0.746i * R3 +R2 -> R2", "-0.424+0.848i * R3 +R1 -> R1", "0.74-0.38i * R2 +R1 -> R1", + "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)", "Saved to file $PSScriptRoot/out3.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no output without -verbose' { + Remove-Item "$PSScriptRoot/out4.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout4.txt" -ErrorAction SilentlyContinue + + java -classpath "$PSScriptRoot/../out/production/project" solver.Main -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out4.txt" > "$PSScriptRoot/stdout4.txt" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout4.txt") + $stdoutLines.Count | Should Be 0 + } +} diff --git a/Java/src/solver/Complex.java b/Java/src/solver/Complex.java new file mode 100644 index 0000000..b5451c5 --- /dev/null +++ b/Java/src/solver/Complex.java @@ -0,0 +1,140 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +package solver; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +public class Complex { + public static final double EPSILON = 0.00001; + + @NotNull + @Contract("_, _ -> new") + public static Complex add(@NotNull Complex a, @NotNull Complex b) { + return new Complex(a.real + b.real, a.imag + b.imag); + } + + @NotNull + @Contract("_, _ -> new") + public static Complex divide(@NotNull Complex a, @NotNull Complex b) { + final Complex bConjugate = b.conjugate(); + final Complex a1 = Complex.multiply(a, bConjugate); + final Complex b1 = Complex.multiply(b, bConjugate); + + return new Complex(a1.real / b1.real, a1.imag / b1.real); + } + + @NotNull + @Contract("_, _ -> new") + public static Complex multiply(@NotNull Complex a, @NotNull Complex b) { + return new Complex(a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real); + } + + private final double real; + private final double imag; + + public Complex(double real, double imag) { + this.real = real; + this.imag = imag; + } + + public Complex() { + this(0.0, 0.0); + } + + public Complex(@NotNull String s) throws NumberFormatException { + final String[] strs = split(s); + real = Double.parseDouble(strs[0]); + imag = Double.parseDouble(strs[1]); + } + + public Complex conjugate() { + return new Complex(real, -imag); + } + + @Contract(value = "null -> false", pure = true) + @Override + public boolean equals(Object other) { + if (other == null) { + return false; + } + + if (!(other instanceof Complex)) { + return false; + } + + Complex o = (Complex) other; + return Math.abs(o.imag - imag) < EPSILON && Math.abs(o.real - real) < EPSILON; + } + + public double getReal() { + return real; + } + + public double getImag() { + return imag; + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + @Override + public String toString() { + final DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US); + final DecimalFormat realFormat = new DecimalFormat("0.####", symbols); + final DecimalFormat imagFormat = new DecimalFormat("0.####i", symbols); + if (Math.abs(imag) < EPSILON) { + return realFormat.format(real); + } + if (Math.abs(real) < EPSILON) { + return imagFormat.format(imag); + } + imagFormat.setPositivePrefix("+"); + return String.format("%s%s", realFormat.format(real), imagFormat.format(imag)); + } + + @NotNull + @Contract("_ -> new") + private String[] split(@NotNull String s) throws NumberFormatException { + s = restoreOmittedImaginaryCoefficient(s); + String realString = "0"; + String imagString = "0"; + int i = 1; + for (; i < s.length(); ++i) { + if (s.charAt(i) == '+' || s.charAt(i) == '-') { + realString = s.substring(0, i); + imagString = s.substring(i, s.length() - 1); + if (s.charAt(s.length()-1) != 'i') { + throw new NumberFormatException("can't parse complex"); + } + break; + } + if (s.charAt(i) == 'i') { + if (i != s.length() - 1) { + throw new NumberFormatException("can't parse complex"); + } + imagString = s.substring(0, i); + break; + } + } + if (i == s.length()) { + realString = s; + } + return new String[]{realString, imagString}; + } + + private String restoreOmittedImaginaryCoefficient(@NotNull String s) { + if (s.equals("i")) { + return "1i"; + } + s = s.replaceAll("\\+i", "+1i"); + s = s.replaceAll("-i", "-1i"); + return s; + } +} diff --git a/Java/src/solver/Main.java b/Java/src/solver/Main.java new file mode 100644 index 0000000..6709a2f --- /dev/null +++ b/Java/src/solver/Main.java @@ -0,0 +1,16 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +package solver; + +class Main { + public static void main(String[] args) { + try { + final Parameters p = new Parameters(args); + final Solver s = new Solver(p.in, p.verbose); + s.solve(); + s.writeSolutionToFile(p.out); + } catch (Exception e) { + System.out.printf("An exception occurs %s\n", e.getMessage()); + } + } +} diff --git a/Java/src/solver/NumberSolutions.java b/Java/src/solver/NumberSolutions.java new file mode 100644 index 0000000..f28a70a --- /dev/null +++ b/Java/src/solver/NumberSolutions.java @@ -0,0 +1,9 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +package solver; + +public enum NumberSolutions { + NONE, + ONE, + MANY +} diff --git a/Java/src/solver/Parameters.java b/Java/src/solver/Parameters.java new file mode 100644 index 0000000..0538f46 --- /dev/null +++ b/Java/src/solver/Parameters.java @@ -0,0 +1,38 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +package solver; + +import org.jetbrains.annotations.NotNull; + +public class Parameters { + public final String in; + public final String out; + public final boolean verbose; + public Parameters(@NotNull String[] args) { + boolean needAssignedIn = true; + String inTemp = "input.txt"; + boolean needAssignedOut = true; + String outTemp = "output.txt"; + boolean verboseTemp = false; + for (int i = 0; i < args.length; ++i) { + if (needAssignedIn && "-in".equals(args[i])) { + if (i < args.length - 1) { + inTemp = args[i+1]; + needAssignedIn = false; + ++i; + } + } else if (needAssignedOut && "-out".equals(args[i])) { + if (i < args.length - 1) { + outTemp = args[i+1]; + needAssignedOut = false; + ++i; + } + } else if (!verboseTemp && "-verbose".equals(args[i])) { + verboseTemp = true; + } + } + in = inTemp; + out = outTemp; + verbose = verboseTemp; + } +} diff --git a/Java/src/solver/Solver.java b/Java/src/solver/Solver.java new file mode 100644 index 0000000..72c17f3 --- /dev/null +++ b/Java/src/solver/Solver.java @@ -0,0 +1,281 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +package solver; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.Scanner; +import java.util.stream.IntStream; + +public class Solver { + private static final Complex ZERO = new Complex(0.0, 0.0); + private static final Complex ONE = new Complex(1.0, 0.0); + private static final Complex MINUS_ONE = new Complex(-1.0, 0.0); + + private final int numberEquations; + private final int numberVariables; + private final Complex[][] matrix; + private final Complex[] solutionPartial; + private final String[] solutionGeneral; + private final int[] solutionIndexes; + private final boolean verbose; + private NumberSolutions numberSolutions = NumberSolutions.ONE; + + public Solver(@NotNull Scanner sc) throws NumberFormatException { + this(sc, false); + } + + @SuppressWarnings("WeakerAccess") + public Solver(@NotNull Scanner sc, boolean verbose) throws NumberFormatException { + numberVariables = sc.nextInt(); + final int realNumberEquations = sc.nextInt(); + if (numberVariables < 1 || realNumberEquations < 1) { + throw new NumberFormatException("wrong input data"); + } + numberEquations = (realNumberEquations < numberVariables) ? numberVariables : realNumberEquations; + matrix = new Complex[numberEquations][numberVariables + 1]; + for (int i = 0; i < realNumberEquations; ++i) { + for (int j = 0; j < numberVariables + 1; ++j) { + matrix[i][j] = new Complex(sc.next()); + } + } + for (int i = realNumberEquations; i < numberEquations; ++i) { + for (int j = 0; j < numberVariables + 1; ++j) { + matrix[i][j] = new Complex(); + } + } + solutionPartial = new Complex[numberVariables]; + solutionGeneral = new String[numberVariables]; + solutionIndexes = IntStream.range(0, numberVariables).toArray(); + this.verbose = verbose; + } + + public Solver(String in, boolean verbose) throws FileNotFoundException { + this(new Scanner(new File(in)), verbose); + } + + public NumberSolutions getNumberSolutions() { + return numberSolutions; + } + + public String[] getSolutionGeneral() { + if (numberSolutions != NumberSolutions.MANY) { + return null; + } + return solutionGeneral.clone(); + } + + public Complex[] getSolutionPartial() { + if (numberSolutions == NumberSolutions.NONE) { + return null; + } + return solutionPartial.clone(); + } + + public void solve() { + if (verbose) { + System.out.println("Start solving the equation."); + System.out.println("Rows manipulation:"); + } + gausFirstStep(); + if (numberSolutions != NumberSolutions.NONE) { + gausSecondStep(); + generateSolutions(); + checkThatSolutionIsSane(); + } + printSolution(); + } + + public void writeSolutionToFile(String out) throws FileNotFoundException { + final File file = new File(out); + final PrintWriter printWriter = new PrintWriter(file); + printSolutionInternal(printWriter); + printWriter.close(); + if (verbose) { + System.out.printf("Saved to file %s\n", out); + } + } + + private void addKRow1ToRow2(@NotNull Complex k, int row1, int row2) { + if (verbose) { + System.out.printf("%s * R%d +R%d -> R%d\n", k.toString(), row1 + 1, row2 + 1, row2 + 1); + } + for (int i = 0; i < numberVariables + 1; ++i) { + final Complex temp = Complex.multiply(k, matrix[row1][i]); + matrix[row2][i] = Complex.add(temp, matrix[row2][i]); + } + } + + private void checkThatSolutionIsSane() { + for (int i = numberVariables; i < numberEquations; ++i) { + Complex sum = new Complex(0.0, 0.0); + for (int j = 0; j < numberVariables; ++j) { + final Complex temp = Complex.multiply(solutionPartial[solutionIndexes[j]], matrix[i][solutionIndexes[j]]); + sum = Complex.add(sum, temp); + } + if (!sum.equals(matrix[i][numberVariables])) { + numberSolutions = NumberSolutions.NONE; + return; + } + } + } + + private void divideRow(int row, @NotNull Complex k) { + if (verbose) { + System.out.printf("R%d / %s -> R%d\n", row + 1, k.toString(), row + 1); + } + final int n = matrix[row].length; + for (int i = 0; i < n; ++i) { + matrix[row][i] = Complex.divide(matrix[row][i], k); + } + } + + private void gausFirstStep() { + for (int i = 0; i < numberVariables; ++i) { + if (matrix[i][i].equals(ZERO)) { + boolean foundNonZeroElement = false; + for (int j = i + 1; j < numberEquations; ++j) { + if (!matrix[j][i].equals(ZERO)) { + swapRows(i, j); + foundNonZeroElement = true; + break; + } + } + if (!foundNonZeroElement) { + for (int j = i + 1; j < numberVariables; ++j) { + if (!matrix[i][j].equals(ZERO)) { + swapColumns(i, j); + foundNonZeroElement = true; + break; + } + } + } + + if (!foundNonZeroElement) { + for (int k = i + 1; !foundNonZeroElement && k < numberVariables; ++k) { + for (int j = i + 1; j < numberEquations; ++j) { + if (!matrix[j][k].equals(ZERO)) { + swapColumns(k, i); + swapRows(j, i); + foundNonZeroElement = true; + break; + } + } + } + } + + if (!foundNonZeroElement) { + if (matrix[i][numberVariables].equals(ZERO)) { + numberSolutions = NumberSolutions.MANY; + continue; + } else { + numberSolutions = NumberSolutions.NONE; + return; + } + } + } + + if (!matrix[i][i].equals(ONE)) { + divideRow(i, matrix[i][i]); + } + for (int j = i + 1; j < numberEquations && j < numberVariables; ++j) { + final Complex k = Complex.multiply(MINUS_ONE, matrix[j][i]); + if (!k.equals(ZERO)) { + addKRow1ToRow2(k, i, j); + } + } + } + } + + private void gausSecondStep() { + for (int i = numberVariables - 1; i >= 0; --i) { + for (int j = i - 1; j >= 0; --j) { + final Complex k = Complex.multiply(MINUS_ONE, matrix[j][i]); + if (!k.equals(ZERO)) { + addKRow1ToRow2(k, i, j); + } + } + } + } + + private void generateSolutions() { + for (int i = 0; i < numberEquations && i < numberVariables; ++i) { + solutionPartial[solutionIndexes[i]] = matrix[i][numberVariables]; + if (matrix[i][i].equals(ZERO)) { + solutionGeneral[solutionIndexes[i]] = "x" + (solutionIndexes[i] + 1); + } else { + solutionGeneral[solutionIndexes[i]] = matrix[i][numberVariables].toString(); + for (int j = i + 1; j < numberVariables; ++j) { + if (matrix[i][j].equals(ONE)) { + solutionGeneral[solutionIndexes[i]] = solutionGeneral[solutionIndexes[i]] + " - x" + + (solutionIndexes[j] + 1); + } else if (!matrix[i][j].equals(ZERO)) { + solutionGeneral[solutionIndexes[i]] = solutionGeneral[solutionIndexes[i]] + " - x" + + (solutionIndexes[j] + 1) + " * (" + matrix[i][j].toString() + ")"; + } + } + } + } + } + + private void printSolution() { + if (verbose) { + printSolutionInternal(new PrintWriter(System.out, true)); + } + } + + private void printSolutionInternal(PrintWriter printWriter) { + switch (numberSolutions) { + case NONE: + printWriter.println("There are no solutions"); + break; + case ONE: + printWriter.printf("(%s", solutionPartial[0].toString()); + for (int i = 1; i < solutionPartial.length; ++i) { + printWriter.printf(", %s", solutionPartial[i].toString()); + } + printWriter.println(")"); + break; + case MANY: + printWriter.printf("(%s", solutionGeneral[0]); + for (int i = 1; i < solutionGeneral.length; ++i) { + printWriter.printf(", %s", solutionGeneral[i]); + } + printWriter.println(")"); + break; + default: + assert (false); + break; + } + printWriter.flush(); + } + + private void swapColumns(int column1, int column2) { + if (verbose) { + System.out.printf("C%d <-> C%d\n", column1 + 1, column2 + 1); + } + final int n = matrix.length; + for (int i = 0; i < n; ++i) { + final Complex temp1 = matrix[i][column1]; + matrix[i][column1] = matrix[i][column2]; + matrix[i][column2] = temp1; + } + final int temp2 = solutionIndexes[column1]; + solutionIndexes[column1] = solutionIndexes[column2]; + solutionIndexes[column2] = temp2; + } + + private void swapRows(int row1, int row2) { + if (verbose) { + System.out.printf("R%d <-> R%d\n", row1 + 1, row2 + 1); + } + for (int i = 0; i < numberVariables + 1; ++i) { + final Complex temp = matrix[row1][i]; + matrix[row1][i] = matrix[row2][i]; + matrix[row2][i] = temp; + } + } +} diff --git a/Java/test/ComplexTest.java b/Java/test/ComplexTest.java new file mode 100644 index 0000000..c60a7b0 --- /dev/null +++ b/Java/test/ComplexTest.java @@ -0,0 +1,262 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +import org.junit.Assert; +import org.junit.Test; +import solver.Complex; + +public class ComplexTest { + @Test + public void equals1() { + final Complex a = new Complex(1.0, 2.0); + final Complex b = new Complex(1.0, 2.0); + Assert.assertEquals(a, b); + } + + @Test + public void equals2() { + final Complex a = new Complex(1.0, 2.0); + Assert.assertNotEquals("Hello", a); + } + + @Test + public void equals3() { + final Complex a = new Complex(1.0, 2.0); + final Complex b = new Complex(1.1, 2.0); + Assert.assertNotEquals(b, a); + } + + @Test + public void equals4() { + final Complex a = new Complex(1.0, 2.1); + final Complex b = new Complex(1.0, 2.0); + Assert.assertNotEquals(b, a); + } + + @Test + public void toString1() { + final Complex a = new Complex(1.0, 0.0); + Assert.assertEquals("1", a.toString()); + } + + @Test + public void toString2() { + final Complex a = new Complex(0.0, 1.0); + Assert.assertEquals("1i", a.toString()); + } + + @Test + public void toString3() { + final Complex a = new Complex(-2.4, 1.5); + Assert.assertEquals("-2.4+1.5i", a.toString()); + } + + @Test + public void toString4() { + final Complex a = new Complex(2.4, -1.5); + Assert.assertEquals("2.4-1.5i", a.toString()); + } + + @Test + public void toString5() { + final Complex a = new Complex(0, 0); + Assert.assertEquals("0", a.toString()); + } + + @Test + public void defaultConstructor() { + final Complex c = new Complex(); + Assert.assertEquals(0.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(0.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void constructor1() { + final Complex c = new Complex(1.0, 0.0); + Assert.assertEquals(1.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(0.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void constructor2() { + boolean ok = false; + try { + @SuppressWarnings("unused") final Complex c = new Complex("gbc"); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor3() { + final String s = "-1.3"; + final Complex c = new Complex(s); + Assert.assertEquals(-1.3, c.getReal(), Complex.EPSILON); + Assert.assertEquals(0.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void constructor4() { + final String s = "2.5i"; + final Complex c = new Complex(s); + Assert.assertEquals(0.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(2.5, c.getImag(), Complex.EPSILON); + } + + @Test + public void constructor5() { + final String s = "1.3-2.5i"; + final Complex c = new Complex(s); + Assert.assertEquals(1.3, c.getReal(), Complex.EPSILON); + Assert.assertEquals(-2.5, c.getImag(), Complex.EPSILON); + } + + @Test + public void constructor6() { + final String s = "1"; + final Complex c = new Complex(s); + Assert.assertEquals(1.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(0.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void constructor7() { + boolean ok = false; + try { + @SuppressWarnings("unused") final Complex c = new Complex("1.3-2.5"); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor8() { + boolean ok = false; + try { + @SuppressWarnings("unused") final Complex c = new Complex("1.3i-2.5"); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor9() { + boolean ok = false; + try { + @SuppressWarnings("unused") final Complex c = new Complex("1.3ij"); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor10() { + boolean ok = false; + try { + @SuppressWarnings("unused") final Complex c = new Complex("1.3+3.5546ij"); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor11() { + boolean ok = false; + try { + @SuppressWarnings("unused") final Complex c = new Complex("1.3ji"); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor12() { + boolean ok = false; + try { + @SuppressWarnings("unused") final Complex c = new Complex("1.3+3.5546ji"); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor13() { + final String s = "i"; + final Complex c = new Complex(s); + Assert.assertEquals(0.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(1.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void constructor14() { + final String s = "-i"; + final Complex c = new Complex(s); + Assert.assertEquals(0.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(-1.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void constructor15() { + final String s = "0.5+i"; + final Complex c = new Complex(s); + Assert.assertEquals(0.5, c.getReal(), Complex.EPSILON); + Assert.assertEquals(1.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void constructor16() { + final String s = "0.5-i"; + final Complex c = new Complex(s); + Assert.assertEquals(0.5, c.getReal(), Complex.EPSILON); + Assert.assertEquals(-1.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void constructor17() { + final String s = "+i"; + final Complex c = new Complex(s); + Assert.assertEquals(0.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(1.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void add() { + final Complex a = new Complex(3.0, -5.0); + final Complex b = new Complex(4.0, 2.0); + final Complex c = Complex.add(a, b); + Assert.assertEquals(7.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(-3.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void multiply() { + final Complex a = new Complex(3.0, 2.0); + final Complex b = new Complex(1.0, 7.0); + final Complex c = Complex.multiply(a, b); + Assert.assertEquals(-11.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(23.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void conjugate() { + final Complex a = new Complex(3.0, 2.0); + final Complex c = a.conjugate(); + Assert.assertEquals(3.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(-2.0, c.getImag(), Complex.EPSILON); + } + + @Test + public void divide() { + final Complex a = new Complex(2.0, 3.0); + final Complex b = new Complex(4.0, -5.0); + final Complex c = Complex.divide(a, b); + Assert.assertEquals(-7.0 / 41.0, c.getReal(), Complex.EPSILON); + Assert.assertEquals(22.0 / 41.0, c.getImag(), Complex.EPSILON); + } +} diff --git a/Java/test/ParametersTest.java b/Java/test/ParametersTest.java new file mode 100644 index 0000000..d46b589 --- /dev/null +++ b/Java/test/ParametersTest.java @@ -0,0 +1,33 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +import org.junit.Assert; +import org.junit.Test; +import solver.Parameters; + +public class ParametersTest { + @Test + public void defaultParameters() { + final Parameters p = new Parameters(new String[]{}); + Assert.assertEquals("input.txt", p.in); + Assert.assertEquals("output.txt", p.out); + Assert.assertFalse(p.verbose); + } + + @Test + public void in() { + final Parameters p = new Parameters(new String[]{"-in", "in.txt"}); + Assert.assertEquals("in.txt", p.in); + } + + @Test + public void out() { + final Parameters p = new Parameters(new String[]{"-out", "out2.txt"}); + Assert.assertEquals("out2.txt", p.out); + } + + @Test + public void verbose() { + final Parameters p = new Parameters(new String[]{"-verbose"}); + Assert.assertTrue(p.verbose); + } +} diff --git a/Java/test/SolverTest.java b/Java/test/SolverTest.java new file mode 100644 index 0000000..e754172 --- /dev/null +++ b/Java/test/SolverTest.java @@ -0,0 +1,351 @@ +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +import org.junit.Assert; +import org.junit.Test; +import solver.Complex; +import solver.NumberSolutions; +import solver.Solver; + +import java.util.Scanner; + +public class SolverTest { + + @Test + public void types1() { + final Scanner sc = new Scanner("1 1\r\n2 4"); + final Solver p = new Solver(sc); + p.solve(); + + NumberSolutions n = p.getNumberSolutions(); + Assert.assertEquals(NumberSolutions.ONE, n); + //noinspection UnusedAssignment + n = NumberSolutions.MANY; + Assert.assertEquals(NumberSolutions.ONE, p.getNumberSolutions()); + } + + @Test + public void types2() { + final Scanner sc = new Scanner("1 1\r\n2 4"); + final Solver p = new Solver(sc); + p.solve(); + + Complex[] array = p.getSolutionPartial(); + Assert.assertEquals(array[0], new Complex(2.0, 0.0)); + array[0] = new Complex(); + array = p.getSolutionPartial(); + Assert.assertEquals(array[0], new Complex(2.0, 0.0)); + } + + @Test + public void types3() { + final Scanner sc = new Scanner("1 1\r\n0 0"); + final Solver p = new Solver(sc); + p.solve(); + + String[] array = p.getSolutionGeneral(); + Assert.assertEquals(array[0], "x1"); + array[0] = "hello"; + array = p.getSolutionGeneral(); + Assert.assertEquals(array[0], "x1"); + } + + @Test + public void constructor1() { + try { + final Scanner sc = new Scanner("1 1\n1 2"); + @SuppressWarnings("unused") final Solver p = new Solver(sc); + } + catch (Exception e) { + Assert.fail(); + } + } + + @Test + public void constructor2() { + boolean ok = false; + try { + final Scanner sc = new Scanner("1 1\nab 2"); + @SuppressWarnings("unused") final Solver p = new Solver(sc); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor3() { + boolean ok = false; + try { + final Scanner sc = new Scanner("-1 1\n2 2"); + @SuppressWarnings("unused") final Solver p = new Solver(sc); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor4() { + boolean ok = false; + try { + final Scanner sc = new Scanner("1 -1\n2 2"); + @SuppressWarnings("unused") final Solver p = new Solver(sc); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor5() { + boolean ok = false; + try { + final Scanner sc = new Scanner("1 1\n2"); + @SuppressWarnings("unused") final Solver p = new Solver(sc); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + @Test + public void constructor6() { + boolean ok = false; + try { + final Scanner sc = new Scanner("0 1\n2 2"); + @SuppressWarnings("unused") final Solver p = new Solver(sc); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + @Test + public void constructor7() { + boolean ok = false; + try { + final Scanner sc = new Scanner("1 0\n2 2"); + @SuppressWarnings("unused") final Solver p = new Solver(sc); + } catch (Exception e) { + ok = true; + } + Assert.assertTrue(ok); + } + + + @Test + public void solve0() { + final Scanner sc = new Scanner("1 1 \n\n 2 4"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(2.0, 0)}; + + Assert.assertEquals(NumberSolutions.ONE, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve1() { + final Scanner sc = new Scanner("1 1\n2 4"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(2.0, 0)}; + + Assert.assertEquals(NumberSolutions.ONE, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve2() { + final Scanner sc = new Scanner("2 2\n1 2 3\n4 5 6"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(-1.0, 0), + new Complex(2.0, 0)}; + + Assert.assertEquals(NumberSolutions.ONE, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve3() { + final Scanner sc = new Scanner("2 2\n4 5 7\n3 9 9"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(0.85714, 0), + new Complex(0.71429, 0)}; + + Assert.assertEquals(NumberSolutions.ONE, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve4() { + final Scanner sc = new Scanner("3 3\n1 1 2 9\n2 4 -3 1\n3 6 -5 0"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(1.0, 0), + new Complex(2.0, 0), new Complex(3.0, 0)}; + + Assert.assertEquals(NumberSolutions.ONE, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve5() { + final Scanner sc = new Scanner("2 2\n0 1 1\n1 0 1"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(1.0, 0), + new Complex(1.0, 0)}; + + Assert.assertEquals(NumberSolutions.ONE, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve6() { + final Scanner sc = new Scanner("2 2\n0 1 1\n0 2 2"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(0.0, 0), + new Complex(1.0, 0)}; + final String[] expectedGeneralSolution = new String[]{"x1", "1"}; + + Assert.assertEquals(NumberSolutions.MANY, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(expectedGeneralSolution, p.getSolutionGeneral()); + } + + @Test + public void solve7() { + final Scanner sc = new Scanner("2 2\n0 1 1\n0 2 3"); + final Solver p = new Solver(sc); + p.solve(); + + Assert.assertEquals(NumberSolutions.NONE, p.getNumberSolutions()); + Assert.assertArrayEquals(null, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve8() { + final Scanner sc = new Scanner("3 4\n0 1 2 9\n0 1 3 1\n1 0 6 0\n2 0 2 0"); + final Solver p = new Solver(sc); + p.solve(); + + Assert.assertEquals(NumberSolutions.NONE, p.getNumberSolutions()); + Assert.assertArrayEquals(null, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve9() { + final Scanner sc = new Scanner("3 1\n1 1 2 9"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(9.0, 0), + new Complex(0, 0), new Complex(0, 0)}; + final String[] expectedGeneralSolution = new String[]{"9 - x2 - x3 * (2)", "x2", "x3"}; + + Assert.assertEquals(NumberSolutions.MANY, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(expectedGeneralSolution, p.getSolutionGeneral()); + } + + @Test + public void solve10() { + final Scanner sc = new Scanner("4 4\n1 0 0 5 0\n0 0 0 0 0\n0 0 1 4 6\n0 0 5 5 5"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(-8.3333333, 0), + new Complex(0, 0), new Complex(-0.6666667, 0), new Complex(1.6666667, 0)}; + final String[] expectedGeneralSolution = new String[]{"-8.3333", "x2", "-0.6667", "1.6667"}; + + Assert.assertEquals(NumberSolutions.MANY, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(expectedGeneralSolution, p.getSolutionGeneral()); + } + + @Test + public void solve11() { + final Scanner sc = new Scanner("4 4\n2 3 -1 1 1\n8 12 -9 8 3\n4 6 3 -2 3\n2 3 9 -7 3"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(0.6, 0), + new Complex(0, 0), new Complex(0.2, 0), new Complex(0, 0)}; + final String[] expectedGeneralSolution = new String[]{"0.6 - x2 * (1.5) - x4 * (0.1)", "x2", + "0.2 - x4 * (-0.8)", "x4"}; + + Assert.assertEquals(NumberSolutions.MANY, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(expectedGeneralSolution, p.getSolutionGeneral()); + } + + @Test + public void solve12() { + final String source = "3 3\n1+2i -1.5-1.1i 2.12 91+5i\n-1+3i 1.2+3.5i -3.3 1+15i\n12.31 1.3-5i 12.3i -78.3i"; + final Scanner sc = new Scanner(source); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(6.73335286, -22.99754223), + new Complex(-1.7976071, 2.08404919), new Complex(15.69938581, 7.3960106)}; + + Assert.assertEquals(NumberSolutions.ONE, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve13() { + final Scanner sc = new Scanner("1\t1\t2\t4"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(2.0, 0)}; + + Assert.assertEquals(NumberSolutions.ONE, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve14() { + final Scanner sc = new Scanner("1 1\r\n2 4"); + final Solver p = new Solver(sc); + p.solve(); + + final Complex[] expectedPartialSolution = new Complex[]{new Complex(2.0, 0)}; + + Assert.assertEquals(NumberSolutions.ONE, p.getNumberSolutions()); + Assert.assertArrayEquals(expectedPartialSolution, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } + + @Test + public void solve15() { + final Scanner sc = new Scanner("3 4\n1 1 2 9\n0 1 3 1\n0 2 6 1\n0 0 0 0"); + final Solver p = new Solver(sc); + p.solve(); + + Assert.assertEquals(NumberSolutions.NONE, p.getNumberSolutions()); + Assert.assertArrayEquals(null, p.getSolutionPartial()); + Assert.assertArrayEquals(null, p.getSolutionGeneral()); + } +} diff --git a/Typescript/acceptance tests/in.txt b/Typescript/acceptance tests/in.txt new file mode 100644 index 0000000..b1db2cf --- /dev/null +++ b/Typescript/acceptance tests/in.txt @@ -0,0 +1,4 @@ +3 3 +1 1 2 9 +2 4 -3 1 +3 6 -5 0 diff --git a/Typescript/acceptance tests/in1.txt b/Typescript/acceptance tests/in1.txt new file mode 100644 index 0000000..112d10d --- /dev/null +++ b/Typescript/acceptance tests/in1.txt @@ -0,0 +1,5 @@ +3 4 +0 1 2 9 +0 1 3 1 +1 0 6 0 +2 0 2 0 \ No newline at end of file diff --git a/Typescript/acceptance tests/in2.txt b/Typescript/acceptance tests/in2.txt new file mode 100644 index 0000000..512957d --- /dev/null +++ b/Typescript/acceptance tests/in2.txt @@ -0,0 +1,5 @@ +4 4 +1 0 0 5 0 +0 0 0 0 0 +0 0 1 4 6 +0 0 5 5 5 \ No newline at end of file diff --git a/Typescript/acceptance tests/in3.txt b/Typescript/acceptance tests/in3.txt new file mode 100644 index 0000000..3b20f11 --- /dev/null +++ b/Typescript/acceptance tests/in3.txt @@ -0,0 +1,4 @@ +3 3 +1+2i -1.5-1.1i 2.12 91+5i +-1+3i 1.2+3.5i -3.3 1+15i +12.31 1.3-5i 12.3i -78.3i \ No newline at end of file diff --git a/Typescript/acceptance tests/tests.ps1 b/Typescript/acceptance tests/tests.ps1 new file mode 100755 index 0000000..075e4de --- /dev/null +++ b/Typescript/acceptance tests/tests.ps1 @@ -0,0 +1,89 @@ +#!/usr/bin/env pwsh +Describe TypescriptAcceptanceTests { + It 'single solution' { + Remove-Item "$PSScriptRoot/out.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout.txt" -ErrorAction SilentlyContinue + + node "$PSScriptRoot/../src/main.js" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out.txt" -verbose > "$PSScriptRoot/stdout.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(1, 2, 3)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "-2 * R1 +R2 -> R2", "-3 * R1 +R3 -> R3", + "R2 / 2 -> R2", "-3 * R2 +R3 -> R3", "R3 / -0.5 -> R3", + "3.5 * R3 +R2 -> R2", "-2 * R3 +R1 -> R1", "-1 * R2 +R1 -> R1", + "(1, 2, 3)", "Saved to file $PSScriptRoot/out.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no solution' { + Remove-Item "$PSScriptRoot/out1.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout1.txt" -ErrorAction SilentlyContinue + + node "$PSScriptRoot/../src/main.js" -in "$PSScriptRoot/in1.txt" -out "$PSScriptRoot/out1.txt" -verbose > "$PSScriptRoot/stdout1.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out1.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "There are no solutions" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout1.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 <-> R3", "-1 * R2 +R3 -> R3", "R3 / -1 -> R3", + "-3 * R3 +R2 -> R2", "-6 * R3 +R1 -> R1", "There are no solutions", "Saved to file $PSScriptRoot/out1.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'many solutions' { + Remove-Item "$PSScriptRoot/out2.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout2.txt" -ErrorAction SilentlyContinue + + node "$PSScriptRoot/../src/main.js" -in "$PSScriptRoot/in2.txt" -out "$PSScriptRoot/out2.txt" -verbose > "$PSScriptRoot/stdout2.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out2.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(-8.3333, x2, -0.6667, 1.6667)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout2.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "C3 <-> C2", "R3 <-> R2", "-5 * R2 +R4 -> R4", + "C4 <-> C3", "R4 <-> R3", "R3 / -15 -> R3", "-4 * R3 +R2 -> R2", + "-5 * R3 +R1 -> R1", "(-8.3333, x2, -0.6667, 1.6667)","Saved to file $PSScriptRoot/out2.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'single solution complex numbers' { + Remove-Item "$PSScriptRoot/out3.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout3.txt" -ErrorAction SilentlyContinue + + node "$PSScriptRoot/../src/main.js" -in "$PSScriptRoot/in3.txt" -out "$PSScriptRoot/out3.txt" -verbose > "$PSScriptRoot/stdout3.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out3.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout3.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 / 1+2i -> R1", "1-3i * R1 +R2 -> R2", "-12.31 * R1 +R3 -> R3", + "R2 / 1.6+6.1i -> R2", "-10.4094+9.6778i * R2 +R3 -> R3", "R3 / -6.7848+9.7158i -> R3", + "0.5432-0.746i * R3 +R2 -> R2", "-0.424+0.848i * R3 +R1 -> R1", "0.74-0.38i * R2 +R1 -> R1", + "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)", "Saved to file $PSScriptRoot/out3.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no output without -verbose' { + Remove-Item "$PSScriptRoot/out4.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout4.txt" -ErrorAction SilentlyContinue + + node "$PSScriptRoot/../src/main.js" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out4.txt" > "$PSScriptRoot/stdout4.txt" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout4.txt") + $stdoutLines.Count | Should Be 0 + } +} diff --git a/Typescript/package.json b/Typescript/package.json new file mode 100644 index 0000000..de29c17 --- /dev/null +++ b/Typescript/package.json @@ -0,0 +1,22 @@ +{ + "name": "solution", + "version": "0.0.1", + "description": "", + "main": "./src/main.js", + "dependencies": { + "@types/jasmine": "3.3.5", + "@types/node": "10.12.18", + "jasmine": "3.3.1", + "npm-check-updates": "2.15.0", + "tslint": "5.12.0", + "typescript": "3.2.2" + }, + "scripts": { + "start": "node ./src/main.js", + "build": "tsc", + "test": "jasmine", + "update": "ncu -u && npm update" + }, + "author": "fsb4000", + "license": "MIT" +} diff --git a/Typescript/spec/complex.spec.ts b/Typescript/spec/complex.spec.ts new file mode 100644 index 0000000..865245f --- /dev/null +++ b/Typescript/spec/complex.spec.ts @@ -0,0 +1,210 @@ +import { Complex } from "../src/complex"; + +describe("complex tests", () => { + it("equals1", () => { + const a = new Complex(1, 2); + const b = new Complex(1, 2); + + expect(a.equals(b)).toBe(true); + }); + + it("equals2", () => { + const a = new Complex(1, 2); + const b = new Complex(1.1, 2); + + expect(a.equals(b)).toBe(false); + }); + + it("equals3", () => { + const a = new Complex(1, 2.1); + const b = new Complex(1, 2); + + expect(a.equals(b)).toBe(false); + }); + + it("toString1", () => { + const a = new Complex(1, 0); + + expect("1").toEqual(a.toString()); + }); + + it("toString2", () => { + const a = new Complex(0, 1); + + expect("1i").toEqual(a.toString()); + }); + + it("toString3", () => { + const a = new Complex(-2.4, 1.5); + + expect("-2.4+1.5i").toEqual(a.toString()); + }); + + it("toString4", () => { + const a = new Complex(2.4, -1.5); + + expect("2.4-1.5i").toEqual(a.toString()); + }); + + it("toString5", () => { + const a = new Complex(0, 0); + + expect("0").toEqual(a.toString()); + }); + + it("defaultConstructor", () => { + const c = new Complex(); + + expect(0).toBeCloseTo(c.getReal()); + expect(0).toBeCloseTo(c.getImag()); + }); + + it("constructor", () => { + const c = new Complex(1, 0); + + expect(1).toBeCloseTo(c.getReal()); + expect(0).toBeCloseTo(c.getImag()); + }); + + it("fromString1", () => { + const s = "-1.3"; + const c = Complex.fromString(s); + + expect(-1.3).toBeCloseTo(c.getReal()); + expect(0).toBeCloseTo(c.getImag()); + }); + + it("fromString2", () => { + const s = "2.5i"; + const c = Complex.fromString(s); + + expect(0).toBeCloseTo(c.getReal()); + expect(2.5).toBeCloseTo(c.getImag()); + }); + + it("fromString3", () => { + const s = "1.3-2.5i"; + const c = Complex.fromString(s); + + expect(1.3).toBeCloseTo(c.getReal()); + expect(-2.5).toBeCloseTo(c.getImag()); + }); + + it("fromString4", () => { + const s = "1"; + const c = Complex.fromString(s); + + expect(1).toBeCloseTo(c.getReal()); + expect(0).toBeCloseTo(c.getImag()); + }); + + it("fromString5", () => { + const f = () => Complex.fromString("gdc"); + expect(f).toThrow(); + }); + + it("fromString6", () => { + const f = () => Complex.fromString("1.3-2.5"); + expect(f).toThrow(); + }); + + it("fromString7", () => { + const f = () => Complex.fromString("1.3i-2.5"); + expect(f).toThrow(); + }); + + it("fromString8", () => { + const f = () => Complex.fromString("1.3ij"); + expect(f).toThrow(); + }); + + it("fromString9", () => { + const f = () => Complex.fromString("1.3+3.5546ij"); + expect(f).toThrow(); + }); + + it("fromString10", () => { + const f = () => Complex.fromString("1.3ji"); + expect(f).toThrow(); + }); + + it("fromString11", () => { + const f = () => Complex.fromString("1.3+3.5546ji"); + expect(f).toThrow(); + }); + + it("fromString12", () => { + const s = "i"; + const c = Complex.fromString(s); + + expect(0).toBeCloseTo(c.getReal()); + expect(1).toBeCloseTo(c.getImag()); + }); + + it("fromString13", () => { + const s = "-i"; + const c = Complex.fromString(s); + + expect(0).toBeCloseTo(c.getReal()); + expect(-1).toBeCloseTo(c.getImag()); + }); + + it("fromString14", () => { + const s = "0.5+i"; + const c = Complex.fromString(s); + + expect(0.5).toBeCloseTo(c.getReal()); + expect(1).toBeCloseTo(c.getImag()); + }); + + it("fromString15", () => { + const s = "0.5-i"; + const c = Complex.fromString(s); + + expect(0.5).toBeCloseTo(c.getReal()); + expect(-1).toBeCloseTo(c.getImag()); + }); + + it("fromString16", () => { + const s = "+i"; + const c = Complex.fromString(s); + + expect(0).toBeCloseTo(c.getReal()); + expect(1).toBeCloseTo(c.getImag()); + }); + + it("add", () => { + const a = new Complex(3, -5); + const b = new Complex(4, 2); + const c = Complex.add(a, b); + + expect(7).toBeCloseTo(c.getReal()); + expect(-3).toBeCloseTo(c.getImag()); + }); + + it("multiply", () => { + const a = new Complex(3, 2); + const b = new Complex(1, 7); + const c = Complex.multiply(a, b); + + expect(-11).toBeCloseTo(c.getReal()); + expect(23).toBeCloseTo(c.getImag()); + }); + + it("conjugate", () => { + const a = new Complex(3, 2); + const c = a.conjugate(); + + expect(3).toBeCloseTo(c.getReal()); + expect(-2).toBeCloseTo(c.getImag()); + }); + + it("divide", () => { + const a = new Complex(2, 3); + const b = new Complex(4, -5); + const c = Complex.divide(a, b); + + expect(-7 / 41).toBeCloseTo(c.getReal()); + expect(22 / 41).toBeCloseTo(c.getImag()); + }); +}); diff --git a/Typescript/spec/parameters.spec.ts b/Typescript/spec/parameters.spec.ts new file mode 100644 index 0000000..41702a4 --- /dev/null +++ b/Typescript/spec/parameters.spec.ts @@ -0,0 +1,26 @@ +import { Parameters } from "../src/parameters"; + +describe("parameters tests", () => { + it("defaultParameters", () => { + const p = new Parameters([]); + + expect(p.in).toBe("input.txt"); + expect(p.out).toBe("output.txt"); + expect(p.verbose).toBe(false); + }); + + it("in", () => { + const p = new Parameters(["-in", "in.txt"]); + expect(p.in).toBe("in.txt"); + }); + + it("out", () => { + const p = new Parameters(["-out", "out2.txt"]); + expect(p.out).toBe("out2.txt"); + }); + + it("verbose", () => { + const p = new Parameters(["-verbose"]); + expect(p.verbose).toBe(true); + }); +}); diff --git a/Typescript/spec/solver.spec.ts b/Typescript/spec/solver.spec.ts new file mode 100644 index 0000000..76bcc9f --- /dev/null +++ b/Typescript/spec/solver.spec.ts @@ -0,0 +1,421 @@ +import { Complex } from "../src/complex"; +import { NumberSolutions } from "../src/numberSolutions"; +import { Solver } from "../src/solver"; + +describe("solver tests", () => { + it("types1", () => { + const f = () => { + const p = new Solver("1 1\n1 2"); + p.solve(); + let n = p.getNumberSolutions(); + expect(n).toBe(NumberSolutions.ONE); + n = NumberSolutions.MANY; + expect(p.getNumberSolutions()).toBe(NumberSolutions.ONE); + }; + expect(f).not.toThrow(); + }); + + it("types2", () => { + const f = () => { + const p = new Solver("1 1\n1 2"); + p.solve(); + let array = p.getSolutionPartial(); + const expected = new Complex(2.0, 0.0); + expect(array !== undefined).toBe(true); + expect(expected.equals(array![0])).toBe(true); + array![0] = new Complex(); + array = p.getSolutionPartial(); + expect(expected.equals(array![0])).toBe(true); + }; + expect(f).not.toThrow(); + }); + + it("types3", () => { + const f = () => { + const p = new Solver("1 1\n0 0"); + p.solve(); + let array = p.getSolutionGeneral(); + const expected = "x1"; + expect(array !== undefined).toBe(true); + expect(expected).toBe(array![0]); + array![0] = "hello"; + array = p.getSolutionGeneral(); + expect(expected).toBe(array![0]); + }; + expect(f).not.toThrow(); + }); + + it("constructor1", () => { + const f = () => new Solver("1 1\n2 2"); + expect(f).not.toThrow(); + }); + + it("constructor2", () => { + const f = () => new Solver("1 1\nab 2"); + expect(f).toThrow(); + }); + + it("constructor3", () => { + const f = () => new Solver("-1 1\n2 2"); + expect(f).toThrow(); + }); + + it("constructor4", () => { + const f = () => new Solver("1 -1\n2 2"); + expect(f).toThrow(); + }); + + it("constructor5", () => { + const f = () => new Solver("1 1\n2"); + expect(f).toThrow(); + }); + + it("constructor6", () => { + const f = () => new Solver("0 1\n2 2"); + expect(f).toThrow(); + }); + + it("constructor7", () => { + const f = () => new Solver("1 0\n2 2"); + expect(f).toThrow(); + }); + + it("solve: allow multiple delimiters", () => { + const s = "1 1 \n\n 2 4"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(2, 0)]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.ONE).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(undefined).toBe(actualGeneralSolution); + } + }); + + it("solve1", () => { + const s = "1 1\n2 4"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(2, 0)]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.ONE).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(undefined).toBe(actualGeneralSolution); + } + }); + + it("solve2", () => { + const s = "2 2\n1 2 3\n4 5 6"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(-1, 0), new Complex(2, 0)]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.ONE).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(undefined).toBe(actualGeneralSolution); + } + }); + + it("solve3", () => { + const s = "2 2\n4 5 7\n3 9 9"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(0.85714, 0), new Complex(0.71429, 0)]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.ONE).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(undefined).toBe(actualGeneralSolution); + } + }); + + it("solve4", () => { + const s = "3 3\n1 1 2 9\n2 4 -3 1\n3 6 -5 0"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(1, 0), new Complex(2, 0), new Complex(3, 0)]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.ONE).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(undefined).toBe(actualGeneralSolution); + } + }); + + it("solve5", () => { + const s = "2 2\n0 1 1\n1 0 1"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(1, 0), new Complex(1, 0)]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.ONE).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(undefined).toBe(actualGeneralSolution); + } + }); + + it("solve6", () => { + const s = "2 2\n0 1 1\n0 2 2"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(0, 0), new Complex(1, 0)]; + const expectedGeneralSolution = ["x1", "1"]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution === undefined) { + fail(); + } else { + expect(NumberSolutions.MANY).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(expectedGeneralSolution).toEqual(actualGeneralSolution); + } + }); + + it("solve7", () => { + const s = "2 2\n0 1 1\n0 2 3"; + const p = new Solver(s); + p.solve(); + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution !== undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.NONE).toBe(p.getNumberSolutions()); + } + }); + + it("solve8", () => { + const s = "3 4\n0 1 2 9\n0 1 3 1\n1 0 6 0\n2 0 2 0"; + const p = new Solver(s); + p.solve(); + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution !== undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.NONE).toBe(p.getNumberSolutions()); + } + }); + + it("solve9", () => { + const s = "3 1\n1 1 2 9"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(9, 0), new Complex(0, 0), new Complex(0, 0)]; + const expectedGeneralSolution = ["9 - x2 - x3 * (2)", "x2", "x3"]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution === undefined) { + fail(); + } else { + expect(NumberSolutions.MANY).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(expectedGeneralSolution).toEqual(actualGeneralSolution); + } + }); + + it("solve10", () => { + const s = "4 4\n1 0 0 5 0\n0 0 0 0 0\n0 0 1 4 6\n0 0 5 5 5"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = + [new Complex(-8.3333333, 0), new Complex(0, 0), new Complex(-0.6666667, 0), new Complex(1.6666667, 0)]; + const expectedGeneralSolution = ["-8.3333", "x2", "-0.6667", "1.6667"]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution === undefined) { + fail(); + } else { + expect(NumberSolutions.MANY).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(expectedGeneralSolution).toEqual(actualGeneralSolution); + } + }); + + it("solve11", () => { + const s = "4 4\n2 3 -1 1 1\n8 12 -9 8 3\n4 6 3 -2 3\n2 3 9 -7 3"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = + [new Complex(0.6, 0), new Complex(0, 0), new Complex(0.2, 0), new Complex(0, 0)]; + const expectedGeneralSolution = + ["0.6 - x2 * (1.5) - x4 * (0.1)", "x2", "0.2 - x4 * (-0.8)", "x4"]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution === undefined) { + fail(); + } else { + expect(NumberSolutions.MANY).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(expectedGeneralSolution).toEqual(actualGeneralSolution); + } + }); + + it("solve12", () => { + const s = "3 3\n1+2i -1.5-1.1i 2.12 91+5i\n-1+3i 1.2+3.5i -3.3 1+15i\n12.31 1.3-5i 12.3i -78.3i"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(6.73335286, -22.99754223), + new Complex(-1.7976071, 2.08404919), new Complex(15.69938581, 7.3960106)]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.ONE).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(undefined).toBe(actualGeneralSolution); + } + }); + + it("solve13", () => { + const s = "1\t1\t2\t4"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(2, 0)]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.ONE).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(undefined).toBe(actualGeneralSolution); + } + }); + + it("solve14", () => { + const s = "1 1\r\n2 4"; + const p = new Solver(s); + p.solve(); + + const expectedPartialSolution = [new Complex(2, 0)]; + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution === undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.ONE).toBe(p.getNumberSolutions()); + expect(expectedPartialSolution.length).toBe(actualPartialSolution.length); + for (let i = 0; i < expectedPartialSolution.length; i += 1) { + expect(expectedPartialSolution[i].equals(actualPartialSolution[i])).toBe(true); + } + expect(undefined).toBe(actualGeneralSolution); + } + }); + + it("solve15", () => { + const s = "3 4\n1 1 2 9\n0 1 3 1\n0 2 6 1\n0 0 0 0"; + const p = new Solver(s); + p.solve(); + + const actualPartialSolution = p.getSolutionPartial(); + const actualGeneralSolution = p.getSolutionGeneral(); + + if (actualPartialSolution !== undefined || actualGeneralSolution !== undefined) { + fail(); + } else { + expect(NumberSolutions.NONE).toBe(p.getNumberSolutions()); + } + }); +}); diff --git a/Typescript/spec/support/jasmine.json b/Typescript/spec/support/jasmine.json new file mode 100644 index 0000000..c6cd880 --- /dev/null +++ b/Typescript/spec/support/jasmine.json @@ -0,0 +1,11 @@ +{ + "spec_dir": "spec", + "spec_files": [ + "*.spec.js" + ], + "helpers": [ + "helpers/**/*.js" + ], + "stopSpecOnExpectationFailure": false, + "random": true +} diff --git a/Typescript/src/complex.ts b/Typescript/src/complex.ts new file mode 100644 index 0000000..712e501 --- /dev/null +++ b/Typescript/src/complex.ts @@ -0,0 +1,107 @@ +const restoreOmittedImaginaryCoefficient = (s: string): string => { + if (s === "i") { + return "1i"; + } + let result = s.replace("+i", "+1i"); + result = result.replace("-i", "-1i"); + + return result; +}; + +const split = (str: string): string[] => { + const s = restoreOmittedImaginaryCoefficient(str); + let realString = "0"; + let imagString = "0"; + let i = 1; + for (; i < s.length; i += 1) { + if (s.charAt(i) === "+" || s.charAt(i) === "-") { + realString = s.substring(0, i); + imagString = s.substring(i, s.length - 1); + if (s.charAt(s.length - 1) !== "i") { + throw new Error("can't parse complex"); + } + break; + } + if (s.charAt(i) === "i") { + if (i !== s.length - 1) { + throw new Error("can't parse complex"); + } + imagString = s.substring(0, i); + break; + } + } + if (i === s.length) { + realString = s; + } + + return [realString, imagString]; +}; + +const strongParseFloat = (s: string): number => { + if (/^(\-|\+)?([0-9]+(\.[0-9]+)?|Infinity)$/.test(s)) { + return Number.parseFloat(s); + } + + return NaN; +}; + +export class Complex { + public static readonly EPSILON = 0.00001; + + public static readonly add = (a: Complex, b: Complex) => + new Complex(a.real + b.real, a.imag + b.imag) + + public static readonly divide = (a: Complex, b: Complex): Complex => { + const bConjugate = b.conjugate(); + const a1 = Complex.multiply(a, bConjugate); + const b1 = Complex.multiply(b, bConjugate); + + return new Complex(a1.real / b1.real, a1.imag / b1.real); + } + + public static readonly fromString = (s: string): Complex => { + const strs = split(s); + const real = strongParseFloat(strs[0]); + const imag = strongParseFloat(strs[1]); + if (Number.isNaN(real) || Number.isNaN(imag)) { + throw new Error("can't parse complex"); + } + + return new Complex(real, imag); + } + + public static readonly multiply = (a: Complex, b: Complex) => + new Complex(a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real) + + private imag: number; + private real: number; + public constructor(real = 0, imag = 0) { + this.real = real; + this.imag = imag; + } + + public readonly conjugate = () => new Complex(this.real, -this.imag); + + public readonly equals = (o: Complex): boolean => + Math.abs(o.imag - this.imag) < Complex.EPSILON && + Math.abs(o.real - this.real) < Complex.EPSILON + + public readonly getImag = () => this.imag; + + public readonly getReal = () => this.real; + + public readonly toString = (): string => { + const real = (Math.round(this.real * 10000) / 10000).toString(); + const imag = (Math.round(this.imag * 10000) / 10000).toString(); + + if (Math.abs(this.imag) < Complex.EPSILON) { + return real; + } + if (Math.abs(this.real) < Complex.EPSILON) { + return `${imag}i`; + } + const prefix = (this.imag > 0) ? "+" : ""; + + return `${real}${prefix}${imag}i`; + } +} diff --git a/Typescript/src/main.ts b/Typescript/src/main.ts new file mode 100644 index 0000000..6300e44 --- /dev/null +++ b/Typescript/src/main.ts @@ -0,0 +1,11 @@ +import * as fs from "fs"; +import { Parameters } from "./parameters"; +import { Solver } from "./solver"; +try { + const p = new Parameters(process.argv); + const s = new Solver(fs.readFileSync(p.in, "utf8"), p.verbose); + s.solve(); + s.writeSolutionToFile(p.out); +} catch (e) { + console.error(`An exception occurs ${(e as Error).message}`); +} diff --git a/Typescript/src/numberSolutions.ts b/Typescript/src/numberSolutions.ts new file mode 100644 index 0000000..0401fb6 --- /dev/null +++ b/Typescript/src/numberSolutions.ts @@ -0,0 +1,5 @@ +export enum NumberSolutions { + NONE, + ONE, + MANY, +} diff --git a/Typescript/src/parameters.ts b/Typescript/src/parameters.ts new file mode 100644 index 0000000..a63ce97 --- /dev/null +++ b/Typescript/src/parameters.ts @@ -0,0 +1,33 @@ +export class Parameters { + public readonly in: string; + public readonly out: string; + public readonly verbose: boolean; + + public constructor(args: string[]) { + let needAssignedIn = true; + let inTemp = "input.txt"; + let needAssignedOut = true; + let outTemp = "output.txt"; + let verboseTemp = false; + for (let i = 0; i < args.length; i += 1) { + if (needAssignedIn && args[i] === "-in") { + if (i < args.length - 1) { + inTemp = args[i + 1]; + needAssignedIn = false; + i += 1; + } + } else if (needAssignedOut && args[i] === "-out") { + if (i < args.length - 1) { + outTemp = args[i + 1]; + needAssignedOut = false; + i += 1; + } + } else if (!verboseTemp && args[i] === "-verbose") { + verboseTemp = true; + } + } + this.in = inTemp; + this.out = outTemp; + this.verbose = verboseTemp; + } +} diff --git a/Typescript/src/solver.ts b/Typescript/src/solver.ts new file mode 100644 index 0000000..ace22e3 --- /dev/null +++ b/Typescript/src/solver.ts @@ -0,0 +1,284 @@ +import * as fs from "fs"; +import * as os from "os"; +import { Complex } from "./complex"; +import { NumberSolutions } from "./numberSolutions"; + +export class Solver { + private static readonly MINUS_ONE = new Complex(-1, 0); + private static readonly ONE = new Complex(1, 0); + private static readonly ZERO = new Complex(0, 0); + + private readonly matrix: Complex[][]; + private readonly numberEquations: number; + private numberSolutions = NumberSolutions.ONE; + private readonly numberVariables: number; + private readonly solutionGeneral: string[]; + private readonly solutionIndexes: number[]; + private readonly solutionPartial: Complex[]; + private readonly verbose: boolean; + + public constructor(s: string, verbose = false) { + const args = s.split(new RegExp("\r\n|\r|\n| |\t")).filter((x: string) => x.length !== 0); + let argsI = 0; + this.numberVariables = Number.parseInt(args[argsI], 10); + argsI += 1; + const realNumberEquations = Number.parseInt(args[argsI], 10); + argsI += 1; + if (this.numberVariables < 1 || realNumberEquations < 1) { + throw new Error("wrong data"); + } + this.numberEquations = (realNumberEquations < this.numberVariables) ? this.numberVariables + : realNumberEquations; + this.matrix = []; + for (let i = 0; i < realNumberEquations; i += 1) { + this.matrix.push(new Array(this.numberVariables + 1)); + for (let j = 0; j < this.numberVariables + 1; j += 1) { + this.matrix[i][j] = Complex.fromString(args[argsI]); + argsI += 1; + } + } + for (let i = realNumberEquations; i < this.numberEquations; i += 1) { + this.matrix.push(new Array(this.numberVariables + 1)); + for (let j = 0; j < this.numberVariables + 1; j += 1) { + this.matrix[i][j] = new Complex(); + } + } + this.solutionPartial = new Array(this.numberVariables); + this.solutionGeneral = new Array(this.numberVariables); + this.solutionIndexes = new Array(this.numberVariables); + for (let i = 0; i < this.numberVariables; i += 1) { + this.solutionIndexes[i] = i; + } + this.verbose = verbose; + } + + public readonly getNumberSolutions = () => this.numberSolutions; + + public readonly getSolutionGeneral = (): string[] | undefined => { + if (this.numberSolutions !== NumberSolutions.MANY) { + return undefined; + } + + return [...this.solutionGeneral]; + } + + public readonly getSolutionPartial = (): Complex[] | undefined => { + if (this.numberSolutions === NumberSolutions.NONE) { + return undefined; + } + + return [...this.solutionPartial]; + } + + public readonly solve = (): void => { + if (this.verbose) { + console.log("Start solving the equation."); + console.log("Rows manipulation:"); + } + this.gausFirstStep(); + if (this.numberSolutions !== NumberSolutions.NONE) { + this.gausSecondStep(); + this.generateSolutions(); + this.checkThatSolutionIsSane(); + } + this.printSolution(); + } + + public readonly writeSolutionToFile = (out: string): void => { + const file = fs.createWriteStream(out); + this.printSolutionInternal(file); + file.close(); + if (this.verbose) { + console.log(`Saved to file ${out}`); + } + } + + private readonly addKRow1ToRow2 = (k: Complex, row1: number, row2: number): void => { + if (this.verbose) { + console.log(`${k.toString()} * R${row1 + 1} +R${row2 + 1} -> R${row2 + 1}`); + } + for (let i = 0; i < this.numberVariables + 1; i += 1) { + const temp = Complex.multiply(k, this.matrix[row1][i]); + this.matrix[row2][i] = Complex.add(temp, this.matrix[row2][i]); + } + } + + private readonly checkThatSolutionIsSane = (): void => { + for (let i = this.numberVariables; i < this.numberEquations; i += 1) { + let sum = new Complex(0, 0); + for (let j = 0; j < this.numberVariables; j += 1) { + const temp = Complex.multiply( + this.solutionPartial[this.solutionIndexes[j]], + this.matrix[i][this.solutionIndexes[j]]); + sum = Complex.add(sum, temp); + } + if (!sum.equals(this.matrix[i][this.numberVariables])) { + this.numberSolutions = NumberSolutions.NONE; + + return; + } + } + } + + private readonly divideRow = (row: number, k: Complex): void => { + if (this.verbose) { + console.log(`R${row + 1} / ${k.toString()} -> R${row + 1}`); + } + const n = this.matrix[row].length; + for (let i = 0; i < n; i += 1) { + this.matrix[row][i] = Complex.divide(this.matrix[row][i], k); + } + } + + private readonly gausFirstStep = (): void => { + for (let i = 0; i < this.numberVariables; i += 1) { + if (this.matrix[i][i].equals(Solver.ZERO)) { + let foundNonZeroElement = false; + for (let j = i + 1; j < this.numberEquations; j += 1) { + if (!this.matrix[j][i].equals(Solver.ZERO)) { + this.swapRows(i, j); + foundNonZeroElement = true; + break; + } + } + if (!foundNonZeroElement) { + for (let j = i + 1; j < this.numberVariables; j += 1) { + if (!this.matrix[i][j].equals(Solver.ZERO)) { + this.swapColumns(i, j); + foundNonZeroElement = true; + break; + } + } + } + + if (!foundNonZeroElement) { + for (let k = i + 1; !foundNonZeroElement && k < this.numberVariables; k += 1) { + for (let j = i + 1; j < this.numberEquations; j += 1) { + if (!this.matrix[j][k].equals(Solver.ZERO)) { + this.swapColumns(k, i); + this.swapRows(j, i); + foundNonZeroElement = true; + break; + } + } + } + } + + if (!foundNonZeroElement) { + if (this.matrix[i][this.numberVariables].equals(Solver.ZERO)) { + this.numberSolutions = NumberSolutions.MANY; + continue; + } else { + this.numberSolutions = NumberSolutions.NONE; + + return; + } + } + } + + if (!this.matrix[i][i].equals(Solver.ONE)) { + this.divideRow(i, this.matrix[i][i]); + } + for (let j = i + 1; j < this.numberEquations && j < this.numberVariables; j += 1) { + const k = Complex.multiply(Solver.MINUS_ONE, this.matrix[j][i]); + if (!k.equals(Solver.ZERO)) { + this.addKRow1ToRow2(k, i, j); + } + } + } + } + + private readonly gausSecondStep = (): void => { + for (let i = this.numberVariables - 1; i >= 0; i -= 1) { + for (let j = i - 1; j >= 0; j -= 1) { + const k = Complex.multiply(Solver.MINUS_ONE, this.matrix[j][i]); + if (!k.equals(Solver.ZERO)) { + this.addKRow1ToRow2(k, i, j); + } + } + } + } + + private readonly generateSolutions = (): void => { + for (let i = 0; i < this.numberEquations && i < this.numberVariables; i += 1) { + this.solutionPartial[this.solutionIndexes[i]] = this.matrix[i][this.numberVariables]; + if (this.matrix[i][i].equals(Solver.ZERO)) { + this.solutionGeneral[this.solutionIndexes[i]] = `x${this.solutionIndexes[i] + 1}`; + } else { + this.solutionGeneral[this.solutionIndexes[i]] = this.matrix[i][this.numberVariables].toString(); + for (let j = i + 1; j < this.numberVariables; j += 1) { + if (this.matrix[i][j].equals(Solver.ONE)) { + this.solutionGeneral[this.solutionIndexes[i]] = + `${this.solutionGeneral[this.solutionIndexes[i]]} - x${this.solutionIndexes[j] + 1}`; + } else if (!this.matrix[i][j].equals(Solver.ZERO)) { + this.solutionGeneral[this.solutionIndexes[i]] = + // tslint:disable-next-line:max-line-length + `${this.solutionGeneral[this.solutionIndexes[i]]} - x${this.solutionIndexes[j] + 1} * (${this.matrix[i][j].toString()})`; + } + } + } + } + } + + private readonly printSolution = (): void => { + if (this.verbose) { + this.printSolutionInternal(); + } + } + + private readonly printSolutionInternal = (writer: fs.WriteStream | undefined = undefined): void => { + let result: string; + switch (this.numberSolutions) { + case NumberSolutions.NONE: + result = "There are no solutions"; + break; + case NumberSolutions.ONE: + result = `(${this.solutionPartial[0].toString()}`; + for (let i = 1; i < this.solutionPartial.length; i += 1) { + result += `, ${this.solutionPartial[i].toString()}`; + } + result += ")"; + break; + case NumberSolutions.MANY: + result = `(${this.solutionGeneral[0]}`; + for (let i = 1; i < this.solutionPartial.length; i += 1) { + result += `, ${this.solutionGeneral[i]}`; + } + result += ")"; + break; + default: + throw new Error("Never should happend"); + } + if (writer instanceof fs.WriteStream) { + writer.end(`${result}${os.EOL}`); + } else { + console.log(result); + } + } + + private readonly swapColumns = (column1: number, column2: number): void => { + if (this.verbose) { + console.log(`C${column1 + 1} <-> C${column2 + 1}`); + } + const n = this.matrix.length; + for (let i = 0; i < n; i += 1) { + const temp1 = this.matrix[i][column1]; + this.matrix[i][column1] = this.matrix[i][column2]; + this.matrix[i][column2] = temp1; + } + const temp2 = this.solutionIndexes[column1]; + this.solutionIndexes[column1] = this.solutionIndexes[column2]; + this.solutionIndexes[column2] = temp2; + } + + private readonly swapRows = (row1: number, row2: number): void => { + if (this.verbose) { + console.log(`R${row1 + 1} <-> R${row2 + 1}`); + } + for (let i = 0; i < this.numberVariables + 1; i += 1) { + const temp = this.matrix[row1][i]; + this.matrix[row1][i] = this.matrix[row2][i]; + this.matrix[row2][i] = temp; + } + } +} diff --git a/Typescript/tsconfig.json b/Typescript/tsconfig.json new file mode 100644 index 0000000..bc59330 --- /dev/null +++ b/Typescript/tsconfig.json @@ -0,0 +1,58 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + }, + "exclude": [ "node_modules"] +} \ No newline at end of file diff --git a/Typescript/tslint.json b/Typescript/tslint.json new file mode 100644 index 0000000..2db6819 --- /dev/null +++ b/Typescript/tslint.json @@ -0,0 +1,18 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:all" + ], + "jsRules": {}, + "rules": { + "no-console": false, + "no-empty": false, + "typedef": false, + "linebreak-style": false, + "no-bitwise": false, + "no-magic-numbers": false, + "newline-per-chained-call": false, + "no-require-imports": false + }, + "rulesDirectory": [] +} diff --git a/Vala/.astylerc b/Vala/.astylerc new file mode 100644 index 0000000..ad2c400 --- /dev/null +++ b/Vala/.astylerc @@ -0,0 +1,21 @@ + +############################################################## +# Documentation is available from # +# http://astyle.sourceforge.net/astyle.html # +############################################################## + +### Options ### +--pad-header +--pad-paren +--suffix=none +--convert-tabs +--attach-inlines +--attach-classes +--attach-namespaces + +### Settings ### +--style=java +--indent=spaces=4 +--indent-namespaces +--lineend=windows +--min-conditional-indent=0 diff --git a/Vala/acceptance tests/in.txt b/Vala/acceptance tests/in.txt new file mode 100644 index 0000000..b1db2cf --- /dev/null +++ b/Vala/acceptance tests/in.txt @@ -0,0 +1,4 @@ +3 3 +1 1 2 9 +2 4 -3 1 +3 6 -5 0 diff --git a/Vala/acceptance tests/in1.txt b/Vala/acceptance tests/in1.txt new file mode 100644 index 0000000..112d10d --- /dev/null +++ b/Vala/acceptance tests/in1.txt @@ -0,0 +1,5 @@ +3 4 +0 1 2 9 +0 1 3 1 +1 0 6 0 +2 0 2 0 \ No newline at end of file diff --git a/Vala/acceptance tests/in2.txt b/Vala/acceptance tests/in2.txt new file mode 100644 index 0000000..512957d --- /dev/null +++ b/Vala/acceptance tests/in2.txt @@ -0,0 +1,5 @@ +4 4 +1 0 0 5 0 +0 0 0 0 0 +0 0 1 4 6 +0 0 5 5 5 \ No newline at end of file diff --git a/Vala/acceptance tests/in3.txt b/Vala/acceptance tests/in3.txt new file mode 100644 index 0000000..3b20f11 --- /dev/null +++ b/Vala/acceptance tests/in3.txt @@ -0,0 +1,4 @@ +3 3 +1+2i -1.5-1.1i 2.12 91+5i +-1+3i 1.2+3.5i -3.3 1+15i +12.31 1.3-5i 12.3i -78.3i \ No newline at end of file diff --git a/Vala/acceptance tests/tests.ps1 b/Vala/acceptance tests/tests.ps1 new file mode 100755 index 0000000..5f3c50e --- /dev/null +++ b/Vala/acceptance tests/tests.ps1 @@ -0,0 +1,89 @@ +#!/usr/bin/env pwsh +Describe CppAcceptanceTests { + It 'single solution' { + Remove-Item "$PSScriptRoot/out.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_vala" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out.txt" -verbose > "$PSScriptRoot/stdout.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(1, 2, 3)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "-2 * R1 +R2 -> R2", "-3 * R1 +R3 -> R3", + "R2 / 2 -> R2", "-3 * R2 +R3 -> R3", "R3 / -0.5 -> R3", + "3.5 * R3 +R2 -> R2", "-2 * R3 +R1 -> R1", "-1 * R2 +R1 -> R1", + "(1, 2, 3)", "Saved to file $PSScriptRoot/out.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no solution' { + Remove-Item "$PSScriptRoot/out1.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout1.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_vala" -in "$PSScriptRoot/in1.txt" -out "$PSScriptRoot/out1.txt" -verbose > "$PSScriptRoot/stdout1.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out1.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "There are no solutions" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout1.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 <-> R3", "-1 * R2 +R3 -> R3", "R3 / -1 -> R3", + "-3 * R3 +R2 -> R2", "-6 * R3 +R1 -> R1", "There are no solutions", "Saved to file $PSScriptRoot/out1.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'many solutions' { + Remove-Item "$PSScriptRoot/out2.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout2.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_vala" -in "$PSScriptRoot/in2.txt" -out "$PSScriptRoot/out2.txt" -verbose > "$PSScriptRoot/stdout2.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out2.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(-8.3333, x2, -0.6667, 1.6667)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout2.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "C3 <-> C2", "R3 <-> R2", "-5 * R2 +R4 -> R4", + "C4 <-> C3", "R4 <-> R3", "R3 / -15 -> R3", "-4 * R3 +R2 -> R2", + "-5 * R3 +R1 -> R1", "(-8.3333, x2, -0.6667, 1.6667)","Saved to file $PSScriptRoot/out2.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'single solution complex numbers' { + Remove-Item "$PSScriptRoot/out3.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout3.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_vala" -in "$PSScriptRoot/in3.txt" -out "$PSScriptRoot/out3.txt" -verbose > "$PSScriptRoot/stdout3.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out3.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout3.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 / 1+2i -> R1", "1-3i * R1 +R2 -> R2", "-12.31 * R1 +R3 -> R3", + "R2 / 1.6+6.1i -> R2", "-10.4094+9.6778i * R2 +R3 -> R3", "R3 / -6.7848+9.7158i -> R3", + "0.5432-0.746i * R3 +R2 -> R2", "-0.424+0.848i * R3 +R1 -> R1", "0.74-0.38i * R2 +R1 -> R1", + "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)", "Saved to file $PSScriptRoot/out3.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no output without -verbose' { + Remove-Item "$PSScriptRoot/out4.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout4.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../bin/solution_vala" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out4.txt" > "$PSScriptRoot/stdout4.txt" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout4.txt") + $stdoutLines.Count | Should Be 0 + } +} diff --git a/Vala/acceptance tests/tests_win.ps1 b/Vala/acceptance tests/tests_win.ps1 new file mode 100644 index 0000000..1ab11d1 --- /dev/null +++ b/Vala/acceptance tests/tests_win.ps1 @@ -0,0 +1,88 @@ +Describe CppAcceptanceTests { + It 'single solution' { + Remove-Item "$PSScriptRoot/out.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out.txt" -verbose > "$PSScriptRoot/stdout.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(1, 2, 3)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "-2 * R1 +R2 -> R2", "-3 * R1 +R3 -> R3", + "R2 / 2 -> R2", "-3 * R2 +R3 -> R3", "R3 / -0.5 -> R3", + "3.5 * R3 +R2 -> R2", "-2 * R3 +R1 -> R1", "-1 * R2 +R1 -> R1", + "(1, 2, 3)", "Saved to file $PSScriptRoot/out.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no solution' { + Remove-Item "$PSScriptRoot/out1.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout1.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in1.txt" -out "$PSScriptRoot/out1.txt" -verbose > "$PSScriptRoot/stdout1.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out1.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "There are no solutions" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout1.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 <-> R3", "-1 * R2 +R3 -> R3", "R3 / -1 -> R3", + "-3 * R3 +R2 -> R2", "-6 * R3 +R1 -> R1", "There are no solutions", "Saved to file $PSScriptRoot/out1.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'many solutions' { + Remove-Item "$PSScriptRoot/out2.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout2.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in2.txt" -out "$PSScriptRoot/out2.txt" -verbose > "$PSScriptRoot/stdout2.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out2.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(-8.3333, x2, -0.6667, 1.6667)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout2.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "C3 <-> C2", "R3 <-> R2", "-5 * R2 +R4 -> R4", + "C4 <-> C3", "R4 <-> R3", "R3 / -15 -> R3", "-4 * R3 +R2 -> R2", + "-5 * R3 +R1 -> R1", "(-8.3333, x2, -0.6667, 1.6667)","Saved to file $PSScriptRoot/out2.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'single solution complex numbers' { + Remove-Item "$PSScriptRoot/out3.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout3.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in3.txt" -out "$PSScriptRoot/out3.txt" -verbose > "$PSScriptRoot/stdout3.txt" + + [String[]]$lines = [System.IO.File]::ReadLines("$PSScriptRoot/out3.txt") + $lines.Count | Should Be 1 + $lines[0] | Should Be "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout3.txt") + [String[]]$expectedOutput = [String[]]("Start solving the equation.", + "Rows manipulation:", "R1 / 1+2i -> R1", "1-3i * R1 +R2 -> R2", "-12.31 * R1 +R3 -> R3", + "R2 / 1.6+6.1i -> R2", "-10.4094+9.6778i * R2 +R3 -> R3", "R3 / -6.7848+9.7158i -> R3", + "0.5432-0.746i * R3 +R2 -> R2", "-0.424+0.848i * R3 +R1 -> R1", "0.74-0.38i * R2 +R1 -> R1", + "(6.7334-22.9975i, -1.7976+2.084i, 15.6994+7.396i)", "Saved to file $PSScriptRoot/out3.txt") + [bool]$areEqual = @(Compare-Object $expectedOutput $stdoutLines -SyncWindow 0).Length -eq 0 + $areEqual | Should Be $true + } + + It 'no output without -verbose' { + Remove-Item "$PSScriptRoot/out4.txt" -ErrorAction SilentlyContinue + Remove-Item "$PSScriptRoot/stdout4.txt" -ErrorAction SilentlyContinue + + & "$PSScriptRoot/../msvc2017/Test/Release/Solution.exe" -in "$PSScriptRoot/in.txt" -out "$PSScriptRoot/out4.txt" > "$PSScriptRoot/stdout4.txt" + + [String[]]$stdoutLines = [System.IO.File]::ReadLines("$PSScriptRoot/stdout4.txt") + $stdoutLines.Count | Should Be 0 + } +} diff --git a/Vala/analyze.sh b/Vala/analyze.sh new file mode 100755 index 0000000..d4e4a5f --- /dev/null +++ b/Vala/analyze.sh @@ -0,0 +1 @@ +io.elementary.vala-lint -d . diff --git a/Vala/bin/.do_not_delete.txt b/Vala/bin/.do_not_delete.txt new file mode 100644 index 0000000..e69de29 diff --git a/Vala/drd.sh b/Vala/drd.sh new file mode 100755 index 0000000..377baac --- /dev/null +++ b/Vala/drd.sh @@ -0,0 +1,12 @@ +OS="`uname`" +case $OS in + 'Linux') + alias make='make' + ;; + 'FreeBSD') + alias make='gmake' + ;; + *) ;; +esac + +make clean && VALGRIND=1 make && valgrind --log-file=drd.txt --read-var-info=yes --tool=drd bin/test_vala diff --git a/Vala/helgrind.sh b/Vala/helgrind.sh new file mode 100755 index 0000000..3b2f3a0 --- /dev/null +++ b/Vala/helgrind.sh @@ -0,0 +1,12 @@ +OS="`uname`" +case $OS in + 'Linux') + alias make='make' + ;; + 'FreeBSD') + alias make='gmake' + ;; + *) ;; +esac + +make clean && VALGRIND=1 make && valgrind --log-file=helgrind.txt --read-var-info=yes --tool=helgrind bin/test_vala diff --git a/Vala/makefile b/Vala/makefile new file mode 100644 index 0000000..3e039f4 --- /dev/null +++ b/Vala/makefile @@ -0,0 +1,22 @@ +include mk/init.mk + +SRC_VALA = src/main.vala src/error.vala src/util.vala src/complex.vala src/parameters.vala src/solver.vala src/number_solutions.vala + +SRC_TEST_VALA += src/error.vala src/util.vala src/complex.vala src/parameters.vala src/solver.vala src/number_solutions.vala \ + test/test_util.vala test/parameters.test.vala test/complex.test.vala test/util.test.vala test/solver.test.vala test/main.vala + + +all: test + +release: bin/solution_vala$(EXEEXT) + +test: bin/test_vala$(EXEEXT) + +thread_test: bin/thread_test_vala$(EXEEXT) + +clean: clean_details + +help: help_details + +include mk/targets.mk + diff --git a/Vala/mk/detect_os.mk b/Vala/mk/detect_os.mk new file mode 100644 index 0000000..074c14b --- /dev/null +++ b/Vala/mk/detect_os.mk @@ -0,0 +1,70 @@ +OS?= +ifeq ($(OS),Windows_NT) + PLATFORM := $(shell uname 2>NUL; false) + ifeq ($(findstring MINGW,$(PLATFORM)),MINGW) + DEL_NUL := $(shell rm -f NUL; false) + ifeq ($(findstring MINGW64,$(PLATFORM)),MINGW64) + BITS = "64" + else + BITS = "32" + endif + else + PLATFORM = "Windows" + endif +else + PLATFORM = $(shell uname) +endif + +include mk/vala.mk + +OS_SUPPORTED = false + +ifeq ($(findstring Haiku, $(PLATFORM)), Haiku) + include mk/haiku_clang.mk + OS_SUPPORTED = true +endif + +ifeq ($(findstring DragonFly, $(PLATFORM)), DragonFly) + include mk/dragonfly_gcc.mk + OS_SUPPORTED = true +endif + +ifeq ($(findstring NetBSD, $(PLATFORM)), NetBSD) + include mk/netbsd_gcc.mk + OS_SUPPORTED = true +endif + +ifeq ($(findstring OpenBSD, $(PLATFORM)), OpenBSD) + include mk/openbsd_clang.mk + OS_SUPPORTED = true +endif + +ifeq ($(findstring SunOS, $(PLATFORM)), SunOS) + include mk/openindiana_gcc.mk + OS_SUPPORTED = true +endif + +ifeq ($(findstring FreeBSD, $(PLATFORM)), FreeBSD) + include mk/freebsd_clang.mk + OS_SUPPORTED = true +endif + +ifeq ($(findstring Linux, $(PLATFORM)), Linux) + include mk/linux_gcc.mk + OS_SUPPORTED = true +endif + +ifeq ($(findstring MINGW, $(PLATFORM)), MINGW) + include mk/mingw_gcc.mk + EXEEXT = .exe + OS_SUPPORTED = true +endif + +ifeq ($(findstring Windows, $(PLATFORM)),Windows) + $(error "install msys2: http://www.msys2.org/") +endif + +ifeq ($(OS_SUPPORTED),false) + $(error "OS is not supported") +endif + diff --git a/Vala/mk/disable_sanitizers_if_enabled_valgrind.mk b/Vala/mk/disable_sanitizers_if_enabled_valgrind.mk new file mode 100644 index 0000000..451b4bb --- /dev/null +++ b/Vala/mk/disable_sanitizers_if_enabled_valgrind.mk @@ -0,0 +1,4 @@ +ifeq ($(VALGRIND), 1) + SANITIZERS = + LIBS_SANITIZERS = +endif diff --git a/Vala/mk/dragonfly_gcc.mk b/Vala/mk/dragonfly_gcc.mk new file mode 100644 index 0000000..76ffce9 --- /dev/null +++ b/Vala/mk/dragonfly_gcc.mk @@ -0,0 +1,31 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -w +LTO = -flto-partition=none -flto -ffat-lto-objects +SECURITY = +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CSTANDARD = -std=c89 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = -flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread + +FLAGS = $(OPTIMIZE) $(LTO) $(DEFINES) $(OPENMP) $(SECURITY) $(DEBUG) +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/Vala/mk/freebsd_clang.mk b/Vala/mk/freebsd_clang.mk new file mode 100644 index 0000000..78fd8a6 --- /dev/null +++ b/Vala/mk/freebsd_clang.mk @@ -0,0 +1,30 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -w +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CSTANDARD = -std=c89 + +SANITIZERS = -fsanitize=address -fsanitize=undefined -fsanitize=leak -fno-omit-frame-pointer +THREAD_SANITIZER = -fsanitize=thread -fno-omit-frame-pointer + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp=libiomp5 +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread + +FLAGS = $(OPTIMIZE) $(LTO) $(DEFINES) $(OPENMP) $(SECURITY) $(DEBUG) +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/Vala/mk/haiku_clang.mk b/Vala/mk/haiku_clang.mk new file mode 100644 index 0000000..8520e9b --- /dev/null +++ b/Vala/mk/haiku_clang.mk @@ -0,0 +1,30 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -w +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CSTANDARD = -std=c89 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = +LIBS_SYSTEM = -lm +LIBS_THREAD = + +FLAGS = $(OPTIMIZE) $(LTO) $(DEFINES) $(OPENMP) $(SECURITY) $(DEBUG) +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/Vala/mk/init.mk b/Vala/mk/init.mk new file mode 100644 index 0000000..bf6b995 --- /dev/null +++ b/Vala/mk/init.mk @@ -0,0 +1,23 @@ +VALGRIND ?= 0 +EXEEXT = + +SRC_C_VALA = $(SRC_VALA:.vala=.c) +OBJ_VALA = $(SRC_VALA:.vala=.o) + +SRC_C_TEST_VALA = $(SRC_TEST_VALA:.vala=.c) +OBJ_TEST_VALA = $(SRC_TEST_VALA:.vala=.o) + +OBJS = $(OBJ_TEST_VALA) $(OBJ_VALA) + +include mk/detect_os.mk +include mk/optional_ccache.mk +include mk/disable_sanitizers_if_enabled_valgrind.mk + +COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c + +%.o : %.c +%.o : %.c %.d + $(COMPILE.c) $(OUTPUT_OPTION) $< + +%.d: ; +.PRECIOUS: %.d diff --git a/Vala/mk/linux_gcc.mk b/Vala/mk/linux_gcc.mk new file mode 100644 index 0000000..7401104 --- /dev/null +++ b/Vala/mk/linux_gcc.mk @@ -0,0 +1,32 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -w +LTO = -flto-partition=none -flto -ffat-lto-objects +SECURITY = -fPIC -fstack-protector-all --param ssp-buffer-size=4 -fstack-check\ + -mindirect-branch=thunk -fPIE -Wa,--noexecstack +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CSTANDARD = -std=c89 + +SANITIZERS = -fsanitize=address -fsanitize=undefined -fsanitize=leak -fno-omit-frame-pointer +THREAD_SANITIZER = -fsanitize=thread -fno-omit-frame-pointer + +LD_LTO = -flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = +LD_SECURITY = -pie -Wl,-z,relro,-z,now -Wl,-z,noexecstack +LD_SYSTEM = -Wl,-O1 -rdynamic + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread -Wl,--no-as-needed -lpthread + +FLAGS = $(OPTIMIZE) $(LTO) $(DEFINES) $(OPENMP) $(SECURITY) $(DEBUG) +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/Vala/mk/mingw_gcc.mk b/Vala/mk/mingw_gcc.mk new file mode 100644 index 0000000..f023cc8 --- /dev/null +++ b/Vala/mk/mingw_gcc.mk @@ -0,0 +1,33 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -w +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CSTANDARD = -std=c89 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = -Wl,--dynamicbase -Wl,--nxcompat +ifeq ($(findstring 64,$(BITS)),64) + LD_SECURITY += -Wl,--high-entropy-va +endif +LD_SYSTEM = -Wl,-subsystem,console -Wl,-O1 + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread -Wl,--no-as-needed -lpthread + +FLAGS = $(OPTIMIZE) $(LTO) $(DEFINES) $(OPENMP) $(SECURITY) $(DEBUG) +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/Vala/mk/netbsd_gcc.mk b/Vala/mk/netbsd_gcc.mk new file mode 100644 index 0000000..76ffce9 --- /dev/null +++ b/Vala/mk/netbsd_gcc.mk @@ -0,0 +1,31 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -w +LTO = -flto-partition=none -flto -ffat-lto-objects +SECURITY = +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CSTANDARD = -std=c89 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = -flto-partition=none -flto -ffat-lto-objects +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread + +FLAGS = $(OPTIMIZE) $(LTO) $(DEFINES) $(OPENMP) $(SECURITY) $(DEBUG) +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/Vala/mk/openbsd_clang.mk b/Vala/mk/openbsd_clang.mk new file mode 100644 index 0000000..a20287e --- /dev/null +++ b/Vala/mk/openbsd_clang.mk @@ -0,0 +1,30 @@ +CCACHE = ccache +CC = $(CCACHE) clang +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -w +LTO = +SECURITY = +DEFINES = +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CSTANDARD = -std=c89 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp=libiomp5 +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread + +FLAGS = $(OPTIMIZE) $(LTO) $(DEFINES) $(OPENMP) $(SECURITY) $(DEBUG) +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) diff --git a/Vala/mk/openindiana_gcc.mk b/Vala/mk/openindiana_gcc.mk new file mode 100644 index 0000000..ffb27a1 --- /dev/null +++ b/Vala/mk/openindiana_gcc.mk @@ -0,0 +1,31 @@ +CCACHE = ccache +CC = $(CCACHE) gcc +CPPFLAGS = -MT $@ -MMD -MP +TARGET_ARCH ?= + +WARNINGS = -w +LTO = +SECURITY = +DEFINES = -D_FORTIFY_SOURCE=2 +DEBUG = -g3 +OPENMP = -fopenmp +OPTIMIZE = -O3 -fstrict-aliasing -funsafe-math-optimizations -ftracer +CSTANDARD = -std=c89 + +SANITIZERS = +THREAD_SANITIZER = + +LD_LTO = +LD_INCLUDE = +LD_SECURITY = +LD_SYSTEM = + +LIBS_OPENMP = -fopenmp +LIBS_SYSTEM = -lm +LIBS_THREAD = -pthread + +FLAGS = $(OPTIMIZE) $(LTO) $(DEFINES) $(OPENMP) $(SECURITY) $(DEBUG) +CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS) +LDFLAGS = $(LD_INCLUDE) $(LD_SECURITY) $(LD_LTO) $(LD_SYSTEM) $(DEBUG) +LIBS = $(LIBS_OPENMP) $(LIBS_SYSTEM) $(LIBS_THREAD) + diff --git a/Vala/mk/optional_ccache.mk b/Vala/mk/optional_ccache.mk new file mode 100644 index 0000000..2b7ace5 --- /dev/null +++ b/Vala/mk/optional_ccache.mk @@ -0,0 +1,4 @@ +CCACHE_VER := $(shell $(CCACHE) -V 2>/dev/null; false) +ifeq ($(CCACHE_VER),) + CCACHE = +endif diff --git a/Vala/mk/targets.mk b/Vala/mk/targets.mk new file mode 100644 index 0000000..fda4869 --- /dev/null +++ b/Vala/mk/targets.mk @@ -0,0 +1,39 @@ +include mk/vala_gen.mk + +./bin/solution_vala$(EXEEXT) : CFLAGS += $(VALA_C_FLAGS) +./bin/solution_vala$(EXEEXT) : LIBS += $(VALA_C_LIBS) +./bin/solution_vala$(EXEEXT) : $(SRC_C_VALA) $(OBJ_VALA) + $(CC) -o $@ $(OBJ_VALA) $(LDFLAGS) $(LIBS) + +./bin/test_vala$(EXEEXT) : CFLAGS += $(SANITIZERS) $(VALA_C_FLAGS) +./bin/test_vala$(EXEEXT) : LIBS += $(VALA_C_LIBS) +./bin/test_vala$(EXEEXT) : $(SRC_C_TEST_VALA) $(OBJ_TEST_VALA) + $(CC) -o $@ $(OBJ_TEST_VALA) $(LDFLAGS) $(LIBS) $(SANITIZERS) + +./bin/thread_test_vala$(EXEEXT) : CFLAGS += $(THREAD_SANITIZER) $(VALA_C_FLAGS) +./bin/thread_test_vala$(EXEEXT) : LIBS += $(VALA_C_LIBS) +./bin/thread_test_vala$(EXEEXT) : $(SRC_C_TEST_VALA) $(OBJ_TEST_VALA) + $(CC) -o $@ $(OBJ_TEST_VALA) $(LDFLAGS) $(LIBS) $(THREAD_SANITIZER) + +clean_details: + rm -f $(SRC_C_TEST_VALA) + rm -f $(SRC_C_VALA) + find . -name "*.o" ! -path "./.git/*" ! -path "./msvc_2017/*" -type f -delete + find . -name "*.d" ! -path "./.git/*" ! -path "./msvc_2017/*" -type f -delete + find . -name "*.orig" ! -path "./.git/*" ! -path "./msvc_2017/*" -type f -delete + rm -f "bin/test_vala$(EXEEXT)" + rm -f "bin/thread_test_vala$(EXEEXT)" + rm -f "bin/solution_vala$(EXEEXT)" + +help_details: + @echo "The following are some of the valid targets for this makefile:" + @echo " all (the default if no target is provided)(=test)" + @echo " release" + @echo " test (with msan)" + @echo " thread_test (searching thread races with tsan)" + @echo " clean" + @echo " help" + +.PHONY: all help help_details clean clean_details + +include $(wildcard $(patsubst %, %.d,$(basename $(OBJS)))) diff --git a/Vala/mk/vala.mk b/Vala/mk/vala.mk new file mode 100644 index 0000000..ce6edbe --- /dev/null +++ b/Vala/mk/vala.mk @@ -0,0 +1,6 @@ +VALAC = valac +PKGS = +PKG_CONFIG = pkg-config +VALA_C_FLAGS = `$(PKG_CONFIG) --cflags ${PKGS} glib-2.0 gobject-2.0` +VALA_C_LIBS = `$(PKG_CONFIG) --libs ${PKGS} glib-2.0 gobject-2.0` +VALA_FLAGS = -g -C $(addprefix --pkg ,${PKGS}) --pkg posix --fatal-warnings --enable-checking diff --git a/Vala/mk/vala_gen.mk b/Vala/mk/vala_gen.mk new file mode 100644 index 0000000..6655345 --- /dev/null +++ b/Vala/mk/vala_gen.mk @@ -0,0 +1,7 @@ +$(SRC_C_TEST_VALA) : $(SRC_TEST_VALA) + @rm -f $(SRC_C_TEST_VALA) + @$(VALAC) $^ $(VALA_FLAGS) + +src/main.c : $(SRC_VALA) + @rm -f $(SRC_C_VALA) + @$(VALAC) $^ $(VALA_FLAGS) diff --git a/Vala/msvc2017/Solution/Solution/Solution.vcxproj b/Vala/msvc2017/Solution/Solution/Solution.vcxproj new file mode 100644 index 0000000..e51f9bb --- /dev/null +++ b/Vala/msvc2017/Solution/Solution/Solution.vcxproj @@ -0,0 +1,172 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + 15.0 + {5716832B-1FBD-40FA-B9C3-5A981F75023B} + Solution + 10.0.16299.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + Solution.ruleset + false + + + Solution.ruleset + false + + + Solution.ruleset + + + Solution.ruleset + + + + TurnOffAllWarnings + MaxSpeed + true + true + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + Speed + true + Fast + true + stdcpp17 + false + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + Console + + + + + TurnOffAllWarnings + Disabled + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + + + + + TurnOffAllWarnings + Disabled + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + stdcpp17 + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + + + + + TurnOffAllWarnings + MaxSpeed + true + true + false + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + true + Speed + true + Fast + true + stdcpp17 + false + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + Console + + + + + + \ No newline at end of file diff --git a/Vala/msvc2017/Solution/Solution/Solution.vcxproj.filters b/Vala/msvc2017/Solution/Solution/Solution.vcxproj.filters new file mode 100644 index 0000000..dec39ee --- /dev/null +++ b/Vala/msvc2017/Solution/Solution/Solution.vcxproj.filters @@ -0,0 +1,40 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + \ No newline at end of file diff --git a/Vala/msvc2017/Test/Test.sln b/Vala/msvc2017/Test/Test.sln new file mode 100644 index 0000000..4f3b0f9 --- /dev/null +++ b/Vala/msvc2017/Test/Test.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27520.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{A7F93A37-D503-4669-AE95-CE0A247A9EF0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Solution", "..\Solution\Solution\Solution.vcxproj", "{5716832B-1FBD-40FA-B9C3-5A981F75023B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x64.ActiveCfg = Debug|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x64.Build.0 = Debug|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x86.ActiveCfg = Debug|Win32 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Debug|x86.Build.0 = Debug|Win32 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x64.ActiveCfg = Release|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x64.Build.0 = Release|x64 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x86.ActiveCfg = Release|Win32 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0}.Release|x86.Build.0 = Release|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x64.ActiveCfg = Debug|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x64.Build.0 = Debug|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x86.ActiveCfg = Debug|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Debug|x86.Build.0 = Debug|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x64.ActiveCfg = Release|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x64.Build.0 = Release|x64 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x86.ActiveCfg = Release|Win32 + {5716832B-1FBD-40FA-B9C3-5A981F75023B}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DE43A559-CB9E-40B7-8806-BF60F337E07F} + EndGlobalSection +EndGlobal diff --git a/Vala/msvc2017/Test/Test/Test.vcxproj b/Vala/msvc2017/Test/Test/Test.vcxproj new file mode 100644 index 0000000..d0ee8b5 --- /dev/null +++ b/Vala/msvc2017/Test/Test/Test.vcxproj @@ -0,0 +1,195 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + 15.0 + {A7F93A37-D503-4669-AE95-CE0A247A9EF0} + Win32Proj + Test + 10.0.16299.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + AllRules.ruleset + false + + + true + AllRules.ruleset + false + + + NativeRecommendedRules.ruleset + false + + + NativeRecommendedRules.ruleset + false + + + + NotUsing + TurnOffAllWarnings + Disabled + true + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + false + stdcpp17 + Caret + + + Console + true + + + + + NotUsing + TurnOffAllWarnings + Disabled + true + _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + false + stdcpp17 + Caret + + + Console + true + + + + + NotUsing + TurnOffAllWarnings + MaxSpeed + true + true + WIN32;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + false + stdcpp17 + Caret + true + true + true + Speed + true + Fast + + + Console + true + true + true + + + + + NotUsing + TurnOffAllWarnings + MaxSpeed + true + true + _CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + $(ProjectDir)..\..\..\3rd;$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories) + false + stdcpp17 + Caret + true + true + true + Speed + true + Fast + + + Console + true + true + true + + + + + \ No newline at end of file diff --git a/Vala/msvc2017/Test/Test/Test.vcxproj.filters b/Vala/msvc2017/Test/Test/Test.vcxproj.filters new file mode 100644 index 0000000..2113bfb --- /dev/null +++ b/Vala/msvc2017/Test/Test/Test.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + Исходные файлы + + + \ No newline at end of file diff --git a/Vala/runastyle.sh b/Vala/runastyle.sh new file mode 100755 index 0000000..0cb2c64 --- /dev/null +++ b/Vala/runastyle.sh @@ -0,0 +1,13 @@ +VALA_FILES_NUMBER=`find src -type f -name "*.vala" -printf x 2> /dev/null | wc -c` +TEST_VALA_FILES_NUMBER=`find test -type f -name "*.vala" -printf x 2> /dev/null | wc -c` + +RCFILE=.astylerc +ASTYLE="astyle --options=$RCFILE" + +if [ $VALA_FILES_NUMBER -gt 0 ]; then + $ASTYLE --recursive "src/*.vala" +fi + +if [ $TEST_VALA_FILES_NUMBER -gt 0 ]; then + $ASTYLE --recursive "test/*.vala" +fi diff --git a/Vala/src/complex.vala b/Vala/src/complex.vala new file mode 100644 index 0000000..6b6c341 --- /dev/null +++ b/Vala/src/complex.vala @@ -0,0 +1,105 @@ +// не можем использовать имя Complex, так как _Complex - это ключевое слово в С +public class ComplexNumber { + public const double EPSILON = 0.00001; + + public static ComplexNumber add ( ComplexNumber a, ComplexNumber b ) + requires ( a != null ) + requires ( b != null ) { + return new ComplexNumber ( a.real + b.real, a.imag + b.imag ); + } + + public static ComplexNumber divide ( ComplexNumber a, ComplexNumber b ) + requires ( a != null ) + requires ( b != null ) { + ComplexNumber bConjugate = b.conjugate (); + ComplexNumber a1 = ComplexNumber.multiply ( a, bConjugate ); + ComplexNumber b1 = ComplexNumber.multiply ( b, bConjugate ); + + return new ComplexNumber ( a1.real / b1.real, a1.imag / b1.real ); + } + + public static ComplexNumber multiply ( ComplexNumber a, ComplexNumber b ) + requires ( a != null ) + requires ( b != null ) { + return new ComplexNumber ( a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real ); + } + + public double real {get; private set; } + public double imag {get; private set; } + + public ComplexNumber ( double real = 0.0, double imag = 0.0 ) { + this.real = real; + this.imag = imag; + } + + public ComplexNumber.from_string ( string s ) throws Error + requires ( s != null ) { + string c = "__"; + double real = 0.0; + double imag = 0.0; + int result = s.scanf ( "%lg%lg%2s", &real, &imag, c ); + if ( result != 3 ) { + real = 0.0; + result = s.scanf ( "%lg%2s", &imag, c ); + if ( result != 2 ) { + c = "__"; + imag = 0.0; + result = s.scanf ( "%lg", &real ); + if ( result == 1 ) { + c = "i"; + } else { + result = s.scanf ( "%2s", c ); + if ( result == 1 ) { + if ( c == "i" || c == "+i" ) { + imag = 1.0; + c = "i"; + } else if ( c == "-i" ) { + imag = -1.0; + c = "i"; + } + } + } + } else { + if ( c == "+i" ) { + real = imag; + imag = 1.0; + c = "i"; + } else if ( c == "-i" ) { + real = imag; + imag = -1.0; + c = "i"; + } + } + } + if ( c != "i" ) { + throw new Error.PARSE_COMPLEX ( "can't parse complex" ); + } + this.real = real; + this.imag = imag; + } + + public ComplexNumber conjugate () { + return new ComplexNumber ( real, -imag ); + } + + public bool equals ( ComplexNumber o ) + requires ( o != null ) { + return Math.fabs ( o.imag - imag ) < EPSILON && Math.fabs ( o.real - real ) < EPSILON; + } + + public string to_string () { + string result = ""; + double real = Util.round ( this.real * 10000.0 ) / 10000.0; + double imag = Util.round ( this.imag * 10000.0 ) / 10000.0; + if ( Math.fabs ( imag ) < EPSILON ) { + result = "%g".printf ( real ); + } else if ( Math.fabs ( real ) < EPSILON ) { + result = "%gi".printf ( imag ); + } else { + unowned string prefix = ( imag > 0 ) ? "+" : ""; + result = "%g%s%gi".printf ( real, prefix, imag ); + } + + return result; + } +} diff --git a/Vala/src/error.vala b/Vala/src/error.vala new file mode 100644 index 0000000..0ba0f92 --- /dev/null +++ b/Vala/src/error.vala @@ -0,0 +1,6 @@ +public errordomain Error { + PARSE_COMPLEX, + WRONG_DATA, + FILE_NOT_FOUND, + FILE_CANT_CREATE, +} \ No newline at end of file diff --git a/Vala/src/main.vala b/Vala/src/main.vala new file mode 100644 index 0000000..96a959b --- /dev/null +++ b/Vala/src/main.vala @@ -0,0 +1,14 @@ +void main ( string[] args ) { + try { + Parameters p = new Parameters ( args ); + FileStream f = FileStream.open ( p.in, "r" ); + if ( f == null ) { + throw new Error.FILE_NOT_FOUND ( "file not found" ); + } + Solver s = new Solver ( f, p.verbose ); + s.solve (); + s.write_solution_to_file ( p.out ); + } catch ( Error e ) { + stderr.printf ( "An exception occurs %s\n", e.message ); + } +} diff --git a/Vala/src/number_solutions.vala b/Vala/src/number_solutions.vala new file mode 100644 index 0000000..dd796bd --- /dev/null +++ b/Vala/src/number_solutions.vala @@ -0,0 +1,5 @@ +public enum NumberSolutions { + NONE, + ONE, + MANY +} \ No newline at end of file diff --git a/Vala/src/parameters.vala b/Vala/src/parameters.vala new file mode 100644 index 0000000..53d35d6 --- /dev/null +++ b/Vala/src/parameters.vala @@ -0,0 +1,27 @@ +public class Parameters { + public string in {get; private set; default = "input.txt";} + public string out {get; private set; default = "output.txt";} + public bool verbose {get; private set; default = false;} + public Parameters ( string[] args ) + requires ( args != null ) { + bool need_assign_in = true; + bool need_assign_out = true; + for ( int i = 0; i < args.length; ++i ) { + if ( need_assign_in && ( "-in" == args[i] ) ) { + if ( i < args.length - 1 ) { + in = args[i + 1]; + need_assign_in = false; + ++i; + } + } else if ( need_assign_out && ( "-out" == args[i] ) ) { + if ( i < args.length - 1 ) { + out = args[i + 1]; + need_assign_out = false; + ++i; + } + } else if ( !verbose && ( "-verbose" == args[i] ) ) { + verbose = true; + } + } + } +} diff --git a/Vala/src/solver.vala b/Vala/src/solver.vala new file mode 100644 index 0000000..7c8f891 --- /dev/null +++ b/Vala/src/solver.vala @@ -0,0 +1,271 @@ +public class Solver { + private ComplexNumber ZERO = new ComplexNumber ( 0.0, 0.0 ); + private ComplexNumber ONE = new ComplexNumber ( 1.0, 0.0 ); + private ComplexNumber MINUS_ONE = new ComplexNumber ( -1.0, 0.0 ); + + private int number_equations; + private int number_variables; + private ComplexNumber[,] matrix; + private ComplexNumber[] solution_partial; + private string[] solution_general; + private int[] solution_indexes; + private bool verbose; + public NumberSolutions number_solutions {get; private set; default = NumberSolutions.ONE;} + + public Solver ( FileStream in, bool verbose = false ) throws Error + requires ( in != null ) { + int real_number_equations = -1; + int result = in.scanf ( "%d%d", &number_variables, &real_number_equations ); + if ( result != 2 || number_variables <= 0 || real_number_equations <= 0 ) { + throw new Error.WRONG_DATA ( "wrong data" ); + } + number_equations = ( real_number_equations < number_variables ) ? number_variables : + real_number_equations; + matrix = new ComplexNumber[number_equations, number_variables + 1]; + for ( int i = 0; i < real_number_equations; ++i ) { + for ( int j = 0; j < number_variables + 1; ++j ) { + string ? temp = Util.read_next ( in ); + if ( temp == null ) { + throw new Error.WRONG_DATA ( "wrong data" ); + } + matrix[i, j] = new ComplexNumber.from_string ( temp ); + } + } + for ( int i = real_number_equations; i < number_equations; ++i ) { + for ( int j = 0; j < number_variables + 1; ++j ) { + matrix[i, j] = new ComplexNumber (); + } + } + solution_partial = new ComplexNumber[number_variables]; + solution_general = new string[number_variables]; + solution_indexes = new int[number_variables]; + for ( int i = 0; i < number_variables; ++i ) { + solution_indexes[i] = i; + } + this.verbose = verbose; + } + + public string[] ? get_solution_general () { + if ( number_solutions != NumberSolutions.MANY ) { + return null; + } + return solution_general; + } + + public ComplexNumber[] ? get_solution_partial () { + if ( number_solutions == NumberSolutions.NONE ) { + return null; + } + return solution_partial; + } + + public void solve () { + if ( verbose ) { + stdout.printf ( "Start solving the equation.\n" ); + stdout.printf ( "Rows manipulation:\n" ); + } + gaus_first_step (); + if ( number_solutions != NumberSolutions.NONE ) { + gaus_second_step (); + generate_solutions (); + check_that_solution_is_sane (); + } + print_solution (); + } + + public void write_solution_to_file ( string o ) throws Error + requires ( o != null ) { + FileStream file = FileStream.open ( o, "w" ); + if ( file == null ) { + throw new Error.FILE_CANT_CREATE ( "can't create file" ); + } + print_solution_internal ( file ); + file.flush (); + if ( verbose ) { + stdout.printf ( "Saved to file %s\n", o ); + } + } + + private void add_k_row1_to_row2 ( ComplexNumber k, int row1, int row2 ) + requires ( k != null ) { + if ( verbose ) { + stdout.printf ( "%s * R%d +R%d -> R%d\n", k.to_string (), row1 + 1, row2 + 1, row2 + 1 ); + } + for ( int i = 0; i < number_variables + 1; ++i ) { + var temp = ComplexNumber.multiply ( k, matrix[row1, i] ); + matrix[row2, i] = ComplexNumber.add ( temp, matrix[row2, i] ); + } + } + + private void check_that_solution_is_sane () { + for ( int i = number_variables; i < number_equations; ++i ) { + ComplexNumber sum = new ComplexNumber ( 0.0, 0.0 ); + for ( int j = 0; j < number_variables; ++j ) { + var temp = ComplexNumber.multiply ( solution_partial[solution_indexes[j]], matrix[i, + solution_indexes[j]] ); + sum = ComplexNumber.add ( sum, temp ); + } + if ( !sum.equals ( matrix[i, number_variables] ) ) { + number_solutions = NumberSolutions.NONE; + return; + } + } + } + + private void divide_row ( int row, ComplexNumber k ) + requires ( k != null ) { + if ( verbose ) { + stdout.printf ( "R%d / %s -> R%d\n", row + 1, k.to_string (), row + 1 ); + } + for ( int i = 0; i < number_variables + 1; ++i ) { + matrix[row, i] = ComplexNumber.divide ( matrix[row, i], k ); + } + } + + private void gaus_first_step () { + for ( int i = 0; i < number_variables; ++i ) { + if ( matrix[i, i].equals ( ZERO ) ) { + bool found_non_zero_element = false; + for ( int j = i + 1; j < number_equations; ++j ) { + if ( !matrix[j, i].equals ( ZERO ) ) { + swap_rows ( i, j ); + found_non_zero_element = true; + break; + } + } + if ( !found_non_zero_element ) { + for ( int j = i + 1; j < number_variables; ++j ) { + if ( !matrix[i, j].equals ( ZERO ) ) { + swap_columns ( i, j ); + found_non_zero_element = true; + break; + } + } + } + + if ( !found_non_zero_element ) { + for ( int k = i + 1; !found_non_zero_element && k < number_variables; ++k ) { + for ( int j = i + 1; j < number_equations; ++j ) { + if ( !matrix[j, k].equals ( ZERO ) ) { + swap_columns ( k, i ); + swap_rows ( j, i ); + found_non_zero_element = true; + break; + } + } + } + } + + if ( !found_non_zero_element ) { + if ( matrix[i, number_variables].equals ( ZERO ) ) { + number_solutions = NumberSolutions.MANY; + continue; + } else { + number_solutions = NumberSolutions.NONE; + return; + } + } + } + + if ( !matrix[i, i].equals ( ONE ) ) { + var k = matrix[i, i]; + divide_row ( i, k ); + } + for ( int j = i + 1; j < number_equations && j < number_variables; ++j ) { + var k = ComplexNumber.multiply ( MINUS_ONE, matrix[j, i] ); + if ( !k.equals ( ZERO ) ) { + add_k_row1_to_row2 ( k, i, j ); + } + } + } + } + + private void gaus_second_step () { + for ( int i = number_variables - 1; i >= 0; --i ) { + for ( int j = i - 1; j >= 0; --j ) { + var k = ComplexNumber.multiply ( MINUS_ONE, matrix[j, i] ); + if ( !k.equals ( ZERO ) ) { + add_k_row1_to_row2 ( k, i, j ); + } + } + } + } + + private void generate_solutions () { + for ( int i = 0; i < number_equations && i < number_variables; ++i ) { + solution_partial[solution_indexes[i]] = matrix[i, number_variables]; + if ( matrix[i, i].equals ( ZERO ) ) { + solution_general[solution_indexes[i]] = "x%d".printf ( solution_indexes[i] + 1 ); + } else { + solution_general[solution_indexes[i]] = matrix[i, number_variables].to_string (); + for ( int j = i + 1; j < number_variables; ++j ) { + if ( matrix[i, j].equals ( ONE ) ) { + solution_general[solution_indexes[i]] = "%s - x%d".printf ( + solution_general[solution_indexes[i]], ( solution_indexes[j] + 1 ) ); + } else if ( !matrix[i, j].equals ( ZERO ) ) { + solution_general[solution_indexes[i]] = "%s - x%d * (%s)".printf ( + solution_general[solution_indexes[i]], ( solution_indexes[j] + 1 ), + matrix[i, j].to_string () ); + } + } + } + } + } + + private void print_solution () { + if ( verbose ) { + print_solution_internal ( stdout ); + } + } + + private void print_solution_internal ( FileStream out ) + requires ( out != null ) { + switch ( number_solutions ) { + case NumberSolutions.NONE: + out.printf ( "There are no solutions\n" ); + break; + case NumberSolutions.ONE: + out.printf ( "(%s", solution_partial[0].to_string () ); + for ( int i = 1; i < solution_partial.length; ++i ) { + out.printf ( ", %s", solution_partial[i].to_string () ); + } + out.printf ( ")\n" ); + break; + case NumberSolutions.MANY: + out.printf ( "(%s", solution_general[0] ); + for ( int i = 1; i < solution_general.length; ++i ) { + out.printf ( ", %s", solution_general[i] ); + } + out.printf ( ")\n" ); + break; + default: + assert ( false ); + break; + } + } + + private void swap_columns ( int column1, int column2 ) { + if ( verbose ) { + stdout.printf ( "C%d <-> C%d\n", column1 + 1, column2 + 1 ); + } + for ( int i = 0; i < number_equations; ++i ) { + var temp1 = matrix[i, column1]; + matrix[i, column1] = matrix[i, column2]; + matrix[i, column2] = temp1; + } + int temp2 = solution_indexes[column1]; + solution_indexes[column1] = solution_indexes[column2]; + solution_indexes[column2] = temp2; + } + + private void swap_rows ( int row1, int row2 ) { + if ( verbose ) { + stdout.printf ( "R%d <-> R%d\n", row1 + 1, row2 + 1 ); + } + for ( int i = 0; i < number_variables + 1; ++i ) { + var temp = matrix[row1, i]; + matrix[row1, i] = matrix[row2, i]; + matrix[row2, i] = temp; + } + } +} diff --git a/Vala/src/util.vala b/Vala/src/util.vala new file mode 100644 index 0000000..b84749d --- /dev/null +++ b/Vala/src/util.vala @@ -0,0 +1,32 @@ +namespace Util { + string ? read_next ( FileStream in ) + requires ( in != null ) { + int c; + StringBuilder ? ret = null; + while ( true ) { + c = in.getc (); + if ( c == FileStream.EOF ) { + break; + } + if ( ( ( char ) c ).isspace () ) { + if ( ret != null ) { + break; + } + continue; + } else { + if ( ret == null ) { + ret = new StringBuilder (); + } + ( ( ! ) ( ret ) ).append_c ( ( char ) c ); + } + } + if ( ret == null ) { + return null; + } + return ( ( ! ) ( ret ) ).str; + } + + double round ( double x ) { + return x >= 0.0 ? Math.floor ( x + 0.5 ) : Math.ceil ( x - 0.5 ); + } +} diff --git a/Vala/test/complex.test.vala b/Vala/test/complex.test.vala new file mode 100644 index 0000000..f7da06b --- /dev/null +++ b/Vala/test/complex.test.vala @@ -0,0 +1,320 @@ +void complex_tests () { + Test.add_func ( "/equals1_complex_test", equals1_complex_test ); + Test.add_func ( "/equals2_complex_test", equals2_complex_test ); + Test.add_func ( "/equals3_complex_test", equals3_complex_test ); + Test.add_func ( "/default_constructor_complex_test", default_constructor_complex_test ); + Test.add_func ( "/constructor1_complex_test", constructor1_complex_test ); + Test.add_func ( "/to_string1_complex_test", to_string1_complex_test ); + Test.add_func ( "/to_string2_complex_test", to_string2_complex_test ); + Test.add_func ( "/to_string3_complex_test", to_string3_complex_test ); + Test.add_func ( "/to_string4_complex_test", to_string4_complex_test ); + Test.add_func ( "/to_string5_complex_test", to_string5_complex_test ); + Test.add_func ( "/from_string1_complex_test", from_string1_complex_test ); + Test.add_func ( "/from_string2_complex_test", from_string2_complex_test ); + Test.add_func ( "/from_string3_complex_test", from_string3_complex_test ); + Test.add_func ( "/from_string4_complex_test", from_string4_complex_test ); + Test.add_func ( "/from_string5_complex_test", from_string5_complex_test ); + Test.add_func ( "/from_string6_complex_test", from_string6_complex_test ); + Test.add_func ( "/from_string7_complex_test", from_string7_complex_test ); + Test.add_func ( "/from_string8_complex_test", from_string8_complex_test ); + Test.add_func ( "/from_string9_complex_test", from_string9_complex_test ); + Test.add_func ( "/from_string10_complex_test", from_string10_complex_test ); + Test.add_func ( "/from_string11_complex_test", from_string11_complex_test ); + Test.add_func ( "/from_string12_complex_test", from_string12_complex_test ); + Test.add_func ( "/from_string13_complex_test", from_string13_complex_test ); + Test.add_func ( "/from_string14_complex_test", from_string14_complex_test ); + Test.add_func ( "/from_string15_complex_test", from_string15_complex_test ); + Test.add_func ( "/from_string16_complex_test", from_string16_complex_test ); + Test.add_func ( "/add_complex_test", add_complex_test ); + Test.add_func ( "/multiply_complex_test", multiply_complex_test ); + Test.add_func ( "/conjugate_complex_test", conjugate_complex_test ); + Test.add_func ( "/divide_complex_test", divide_complex_test ); +} + +void equals1_complex_test () { + ComplexNumber a = new ComplexNumber ( 1.0, 2.0 ); + ComplexNumber b = new ComplexNumber ( 1.0, 2.0 ); + + assert ( a.equals ( b ) ); +} + +void equals2_complex_test () { + ComplexNumber a = new ComplexNumber ( 1.0, 2.0 ); + ComplexNumber b = new ComplexNumber ( 1.1, 2.0 ); + + assert ( !a.equals ( b ) ); +} + +void equals3_complex_test () { + ComplexNumber a = new ComplexNumber ( 1.0, 2.1 ); + ComplexNumber b = new ComplexNumber ( 1.0, 2.0 ); + + assert ( !a.equals ( b ) ); +} + +void default_constructor_complex_test () { + ComplexNumber a = new ComplexNumber (); + + assert ( Math.fabs ( 0.0 - a.real ) < ComplexNumber.EPSILON ); + assert ( Math.fabs ( 0.0 - a.imag ) < ComplexNumber.EPSILON ); +} + +void constructor1_complex_test () { + ComplexNumber a = new ComplexNumber ( 1.0, 3.5 ); + + assert ( Math.fabs ( 1.0 - a.real ) < ComplexNumber.EPSILON ); + assert ( Math.fabs ( 3.5 - a.imag ) < ComplexNumber.EPSILON ); +} + +void to_string1_complex_test () { + ComplexNumber a = new ComplexNumber ( 1.0, 0.0 ); + + assert ( "1" == a.to_string () ); +} + +void to_string2_complex_test () { + ComplexNumber a = new ComplexNumber ( 0.0, 1.0 ); + + assert ( "1i" == a.to_string () ); +} + +void to_string3_complex_test () { + ComplexNumber a = new ComplexNumber ( -2.4, 1.5 ); + + assert ( "-2.4+1.5i" == a.to_string () ); +} + +void to_string4_complex_test () { + ComplexNumber a = new ComplexNumber ( 2.4, -1.5 ); + + assert ( "2.4-1.5i" == a.to_string () ); +} + +void to_string5_complex_test () { + ComplexNumber a = new ComplexNumber ( 0.0, 0.0 ); + + assert ( "0" == a.to_string () ); +} + +void from_string1_complex_test () { + bool ok = false; + try { + ComplexNumber a = new ComplexNumber.from_string ( "gbc" ); + ( void ) a; + } catch { + ok = true; + } + + assert ( ok ); +} + +void from_string2_complex_test () { + try { + ComplexNumber a = new ComplexNumber.from_string ( "-1.3" ); + ComplexNumber e = new ComplexNumber ( -1.3, 0.0 ); + + assert ( a.equals ( e ) ); + } catch { + assert ( false ); + } +} + +void from_string3_complex_test () { + try { + ComplexNumber a = new ComplexNumber.from_string ( "2.5i" ); + ComplexNumber e = new ComplexNumber ( 0.0, 2.5 ); + + assert ( a.equals ( e ) ); + } catch { + assert ( false ); + } +} + +void from_string4_complex_test () { + try { + ComplexNumber a = new ComplexNumber.from_string ( "1.3-2.5i" ); + ComplexNumber e = new ComplexNumber ( 1.3, -2.5 ); + + assert ( a.equals ( e ) ); + } catch { + assert ( false ); + } +} + +void from_string5_complex_test () { + try { + ComplexNumber a = new ComplexNumber.from_string ( "1" ); + ComplexNumber e = new ComplexNumber ( 1.0, 0.0 ); + + assert ( a.equals ( e ) ); + } catch { + assert ( false ); + } +} + +void from_string6_complex_test () { + bool ok = false; + try { + ComplexNumber a = new ComplexNumber.from_string ( "1.3-2.5" ); + ( void ) a; + } catch { + ok = true; + } + + assert ( ok ); +} + +void from_string7_complex_test () { + bool ok = false; + try { + ComplexNumber a = new ComplexNumber.from_string ( "1.3i-2.5" ); + ( void ) a; + } catch { + ok = true; + } + + assert ( ok ); +} + +void from_string8_complex_test () { + bool ok = false; + try { + ComplexNumber a = new ComplexNumber.from_string ( "1.3ij" ); + ( void ) a; + } catch { + ok = true; + } + + assert ( ok ); +} + +void from_string9_complex_test () { + bool ok = false; + try { + ComplexNumber a = new ComplexNumber.from_string ( "1.3+3.5546ij" ); + ( void ) a; + } catch { + ok = true; + } + + assert ( ok ); +} + +void from_string10_complex_test () { + bool ok = false; + try { + ComplexNumber a = new ComplexNumber.from_string ( "1.3ji" ); + ( void ) a; + } catch { + ok = true; + } + + assert ( ok ); +} + +void from_string11_complex_test () { + bool ok = false; + try { + ComplexNumber a = new ComplexNumber.from_string ( "1.3+3.5546ji" ); + ( void ) a; + } catch { + ok = true; + } + + assert ( ok ); +} + +void from_string12_complex_test () { + try { + ComplexNumber a = new ComplexNumber.from_string ( "i" ); + ComplexNumber e = new ComplexNumber ( 0.0, 1.0 ); + + assert ( a.equals ( e ) ); + } catch { + assert ( false ); + } +} + +void from_string13_complex_test () { + try { + ComplexNumber a = new ComplexNumber.from_string ( "-i" ); + ComplexNumber e = new ComplexNumber ( 0.0, -1.0 ); + + assert ( a.equals ( e ) ); + } catch { + assert ( false ); + } +} + +void from_string14_complex_test () { + try { + ComplexNumber a = new ComplexNumber.from_string ( "0.5+i" ); + ComplexNumber e = new ComplexNumber ( 0.5, 1.0 ); + + assert ( a.equals ( e ) ); + } catch { + assert ( false ); + } +} + +void from_string15_complex_test () { + try { + ComplexNumber a = new ComplexNumber.from_string ( "0.5-i" ); + ComplexNumber e = new ComplexNumber ( 0.5, -1.0 ); + + assert ( a.equals ( e ) ); + } catch { + assert ( false ); + } +} + +void from_string16_complex_test () { + try { + ComplexNumber a = new ComplexNumber.from_string ( "+i" ); + ComplexNumber e = new ComplexNumber ( 0.0, 1.0 ); + + assert ( a.equals ( e ) ); + } catch { + assert ( false ); + } +} + +void add_complex_test () { + ComplexNumber a = new ComplexNumber ( 3.0, -5.0 ); + ComplexNumber b = new ComplexNumber ( 4.0, 2.0 ); + + ComplexNumber expected = new ComplexNumber ( 7.0, -3.0 ); + ComplexNumber actual = ComplexNumber.add ( a, b ); + + assert ( expected.equals ( actual ) ); +} + +void multiply_complex_test () { + ComplexNumber a = new ComplexNumber ( 3.0, 2.0 ); + ComplexNumber b = new ComplexNumber ( 1.0, 7.0 ); + + ComplexNumber expected = new ComplexNumber ( -11.0, 23.0 ); + ComplexNumber actual = ComplexNumber.multiply ( a, b ); + + assert ( expected.equals ( actual ) ); +} + +void conjugate_complex_test () { + ComplexNumber a = new ComplexNumber ( 3.0, 2.0 ); + + ComplexNumber expected = new ComplexNumber ( 3.0, -2.0 ); + ComplexNumber actual = a.conjugate (); + + assert ( expected.equals ( actual ) ); +} + +void divide_complex_test () { + ComplexNumber a = new ComplexNumber ( 2.0, 3.0 ); + ComplexNumber b = new ComplexNumber ( 4.0, -5.0 ); + + ComplexNumber expected = new ComplexNumber ( -7.0 / 41.0, 22.0 / 41.0 ); + ComplexNumber actual = ComplexNumber.divide ( a, b ); + + assert ( expected.equals ( actual ) ); +} + diff --git a/Vala/test/main.vala b/Vala/test/main.vala new file mode 100644 index 0000000..3295c90 --- /dev/null +++ b/Vala/test/main.vala @@ -0,0 +1,8 @@ +void main ( string[] args ) { + Test.init ( ref args ); + parameters_tests (); + complex_tests (); + util_tests (); + solver_tests (); + Test.run (); +} diff --git a/Vala/test/parameters.test.vala b/Vala/test/parameters.test.vala new file mode 100644 index 0000000..9e6445e --- /dev/null +++ b/Vala/test/parameters.test.vala @@ -0,0 +1,32 @@ +void parameters_tests () { + Test.add_func ( "/default_parameters_test", default_parameters_test ); + Test.add_func ( "/in_parameters_test", in_parameters_test ); + Test.add_func ( "/out_parameters_test", out_parameters_test ); + Test.add_func ( "/verbose_parameters_test", verbose_parameters_test ); +} + +void default_parameters_test () { + Parameters p = new Parameters ( new string[] {""} ); + + assert ( "input.txt" == p.in ); + assert ( "output.txt" == p.out ); + assert ( false == p.verbose ); +} + +void in_parameters_test () { + Parameters p = new Parameters ( new string[] {"-in", "in.txt"} ); + + assert ( "in.txt" == p.in ); +} + +void out_parameters_test () { + Parameters p = new Parameters ( new string[] {"-out", "out2.txt"} ); + + assert ( "out2.txt" == p.out ); +} + +void verbose_parameters_test () { + Parameters p = new Parameters ( new string[] {"-verbose"} ); + + assert ( p.verbose ); +} diff --git a/Vala/test/solver.test.vala b/Vala/test/solver.test.vala new file mode 100644 index 0000000..98b75b5 --- /dev/null +++ b/Vala/test/solver.test.vala @@ -0,0 +1,553 @@ +void solver_tests () { + Test.add_func ( "/constructor1_solver_test", constructor1_solver_test ); + Test.add_func ( "/constructor2_solver_test", constructor2_solver_test ); + Test.add_func ( "/constructor3_solver_test", constructor3_solver_test ); + Test.add_func ( "/constructor4_solver_test", constructor4_solver_test ); + Test.add_func ( "/constructor5_solver_test", constructor5_solver_test ); + Test.add_func ( "/constructor6_solver_test", constructor6_solver_test ); + Test.add_func ( "/constructor7_solver_test", constructor7_solver_test ); + Test.add_func ( "/solve0_solver_test", solve0_solver_test ); + Test.add_func ( "/solve1_solver_test", solve1_solver_test ); + Test.add_func ( "/solve2_solver_test", solve2_solver_test ); + Test.add_func ( "/solve3_solver_test", solve3_solver_test ); + Test.add_func ( "/solve4_solver_test", solve4_solver_test ); + Test.add_func ( "/solve5_solver_test", solve5_solver_test ); + Test.add_func ( "/solve6_solver_test", solve6_solver_test ); + Test.add_func ( "/solve7_solver_test", solve7_solver_test ); + Test.add_func ( "/solve8_solver_test", solve8_solver_test ); + Test.add_func ( "/solve9_solver_test", solve9_solver_test ); + Test.add_func ( "/solve10_solver_test", solve10_solver_test ); + Test.add_func ( "/solve11_solver_test", solve11_solver_test ); + Test.add_func ( "/solve12_solver_test", solve12_solver_test ); + Test.add_func ( "/solve13_solver_test", solve13_solver_test ); + Test.add_func ( "/solve14_solver_test", solve14_solver_test ); + Test.add_func ( "/solve15_solver_test", solve15_solver_test ); + Test.add_func ( "/types1_solver_test", types1_solver_test ); + Test.add_func ( "/types2_solver_test", types2_solver_test ); + Test.add_func ( "/types3_solver_test", types3_solver_test ); +} + +void types1_solver_test () { + try { + var in = generate_filestream ( "1 1\n1 2" ); + Solver p = new Solver ( in ); + p.solve (); + NumberSolutions n = p.number_solutions; + assert ( NumberSolutions.ONE == n ); + n = NumberSolutions.MANY; + assert ( NumberSolutions.ONE == p.number_solutions ); + } catch { + assert ( false ); + } +} + +void types2_solver_test () { + try { + var in = generate_filestream ( "1 1\n1 2" ); + Solver p = new Solver ( in ); + p.solve (); + var array = p.get_solution_partial(); + ComplexNumber expected = new ComplexNumber ( 2.0, 0.0 ); + assert ( expected.equals ( array[0] ) ); + array[0] = new ComplexNumber(); + array = p.get_solution_partial(); + assert ( expected.equals ( array[0] ) ); + } catch { + assert ( false ); + } +} + +void types3_solver_test () { + try { + var in = generate_filestream ( "1 1\n0 0" ); + Solver p = new Solver ( in ); + p.solve (); + var array = p.get_solution_general(); + string expected = "x1"; + assert ( expected == array[0] ); + array[0] = "hello"; + array = p.get_solution_general(); + assert ( expected == array[0] ); + } catch { + assert ( false ); + } +} + +void constructor1_solver_test () { + try { + var in = generate_filestream ( "1 1\n1 2" ); + Solver p = new Solver ( in ); + ( void ) p; + } catch { + assert ( false ); + } +} + +void constructor2_solver_test () { + bool ok = false; + try { + var in = generate_filestream ( "1 1\nab 2" ); + Solver p = new Solver ( in ); + ( void ) p; + } catch { + ok = true; + } + assert ( ok ); +} + +void constructor3_solver_test () { + bool ok = false; + try { + var in = generate_filestream ( "-1 1\n2 2" ); + Solver p = new Solver ( in ); + ( void ) p; + } catch { + ok = true; + } + assert ( ok ); +} + +void constructor4_solver_test () { + bool ok = false; + try { + var in = generate_filestream ( "1 -1\n2 2" ); + Solver p = new Solver ( in ); + ( void ) p; + } catch { + ok = true; + } + assert ( ok ); +} + +void constructor5_solver_test () { + bool ok = false; + try { + var in = generate_filestream ( "1 1\n2" ); + Solver p = new Solver ( in ); + ( void ) p; + } catch { + ok = true; + } + assert ( ok ); +} + +void constructor6_solver_test () { + bool ok = false; + try { + var in = generate_filestream ( "0 1\n2 2" ); + Solver p = new Solver ( in ); + ( void ) p; + } catch { + ok = true; + } + assert ( ok ); +} + +void constructor7_solver_test () { + bool ok = false; + try { + var in = generate_filestream ( "1 0\n2 2" ); + Solver p = new Solver ( in ); + ( void ) p; + } catch { + ok = true; + } + assert ( ok ); +} + +void solve0_solver_test () { + try { + var in = generate_filestream ( "1 1 \n\n 2 4" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( 2.0, 0 ) }; + NumberSolutions expected_number_solutions = NumberSolutions.ONE; + string[] ? expected_general_solution = null; + + var actual_partial_solution = p.get_solution_partial (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( expected_general_solution == p.get_solution_general () ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + } catch { + assert ( false ); + } +} + +void solve1_solver_test () { + try { + var in = generate_filestream ( "1 1\n2 4" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( 2.0, 0 ) }; + NumberSolutions expected_number_solutions = NumberSolutions.ONE; + string[] ? expected_general_solution = null; + + var actual_partial_solution = p.get_solution_partial (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( expected_general_solution == p.get_solution_general () ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + } catch { + assert ( false ); + } +} + +void solve2_solver_test () { + try { + var in = generate_filestream ( "2 2\n1 2 3\n4 5 6" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( -1.0, 0 ), + new ComplexNumber ( 2.0, 0 ) + }; + NumberSolutions expected_number_solutions = NumberSolutions.ONE; + string[] ? expected_general_solution = null; + + var actual_partial_solution = p.get_solution_partial (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( expected_general_solution == p.get_solution_general () ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + } catch { + assert ( false ); + } +} + +void solve3_solver_test () { + try { + var in = generate_filestream ( "2 2\n4 5 7\n3 9 9" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( 0.85714, 0 ), + new ComplexNumber ( 0.71429, 0 ) + }; + NumberSolutions expected_number_solutions = NumberSolutions.ONE; + string[] ? expected_general_solution = null; + + var actual_partial_solution = p.get_solution_partial (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( expected_general_solution == p.get_solution_general () ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + } catch { + assert ( false ); + } +} + +void solve4_solver_test () { + try { + var in = generate_filestream ( "3 3\n1 1 2 9\n2 4 -3 1\n3 6 -5 0" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( 1.0, 0 ), + new ComplexNumber ( 2.0, 0 ), new ComplexNumber ( 3.0, 0 ) + }; + NumberSolutions expected_number_solutions = NumberSolutions.ONE; + string[] ? expected_general_solution = null; + + var actual_partial_solution = p.get_solution_partial (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( expected_general_solution == p.get_solution_general () ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + } catch { + assert ( false ); + } +} + +void solve5_solver_test () { + try { + var in = generate_filestream ( "2 2\n0 1 1\n1 0 1" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( 1.0, 0 ), + new ComplexNumber ( 1.0, 0 ) + }; + NumberSolutions expected_number_solutions = NumberSolutions.ONE; + string[] ? expected_general_solution = null; + + var actual_partial_solution = p.get_solution_partial (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( expected_general_solution == p.get_solution_general () ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + } catch { + assert ( false ); + } +} + +void solve6_solver_test () { + try { + var in = generate_filestream ( "2 2\n0 1 1\n0 2 2" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( 0.0, 0 ), + new ComplexNumber ( 1.0, 0 ) + }; + NumberSolutions expected_number_solutions = NumberSolutions.MANY; + string[] expected_general_solution = new string[] {"x1", "1"}; + + var actual_partial_solution = p.get_solution_partial (); + var actual_general_solution = p.get_solution_general (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + assert ( actual_general_solution.length == expected_general_solution.length ); + for ( int i = 0; i < actual_general_solution.length; ++i ) { + assert ( actual_general_solution[i] == expected_general_solution[i] ); + } + } catch { + assert ( false ); + } +} + +void solve7_solver_test () { + try { + var in = generate_filestream ( "2 2\n0 1 1\n0 2 3" ); + Solver p = new Solver ( in ); + p.solve (); + + NumberSolutions expected_number_solutions = NumberSolutions.NONE; + + var actual_partial_solution = p.get_solution_partial (); + var actual_general_solution = p.get_solution_general (); + + assert ( p.number_solutions == expected_number_solutions ); + assert ( actual_partial_solution == null ); + assert ( actual_general_solution == null ); + } catch { + assert ( false ); + } +} + +void solve8_solver_test () { + try { + var in = generate_filestream ( "3 4\n0 1 2 9\n0 1 3 1\n1 0 6 0\n2 0 2 0" ); + Solver p = new Solver ( in ); + p.solve (); + + NumberSolutions expected_number_solutions = NumberSolutions.NONE; + + var actual_partial_solution = p.get_solution_partial (); + var actual_general_solution = p.get_solution_general (); + + assert ( p.number_solutions == expected_number_solutions ); + assert ( actual_partial_solution == null ); + assert ( actual_general_solution == null ); + } catch { + assert ( false ); + } +} + +void solve9_solver_test () { + try { + var in = generate_filestream ( "3 1\n1 1 2 9" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( 9.0, 0 ), + new ComplexNumber ( 0, 0 ), + new ComplexNumber ( 0, 0 ) + }; + NumberSolutions expected_number_solutions = NumberSolutions.MANY; + string[] expected_general_solution = new string[] {"9 - x2 - x3 * (2)", "x2", "x3"}; + + var actual_partial_solution = p.get_solution_partial (); + var actual_general_solution = p.get_solution_general (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + assert ( actual_general_solution.length == expected_general_solution.length ); + for ( int i = 0; i < actual_general_solution.length; ++i ) { + assert ( actual_general_solution[i] == expected_general_solution[i] ); + } + } catch { + assert ( false ); + } +} + +void solve10_solver_test () { + try { + var in = generate_filestream ( "4 4\n1 0 0 5 0\n0 0 0 0 0\n0 0 1 4 6\n0 0 5 5 5" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] { + new ComplexNumber ( -8.3333333, 0 ),new ComplexNumber ( 0, 0 ), + new ComplexNumber ( -0.6666667, 0 ), new ComplexNumber ( 1.6666667, 0 ) + }; + NumberSolutions expected_number_solutions = NumberSolutions.MANY; + string[] expected_general_solution = new string[] {"-8.3333", "x2", "-0.6667", "1.6667"}; + + var actual_partial_solution = p.get_solution_partial (); + var actual_general_solution = p.get_solution_general (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + assert ( actual_general_solution.length == expected_general_solution.length ); + for ( int i = 0; i < actual_general_solution.length; ++i ) { + assert ( actual_general_solution[i] == expected_general_solution[i] ); + } + } catch { + assert ( false ); + } +} + +void solve11_solver_test () { + try { + var in = generate_filestream ( "4 4\n2 3 -1 1 1\n8 12 -9 8 3\n4 6 3 -2 3\n2 3 9 -7 3" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( 0.6, 0 ), + new ComplexNumber ( 0, 0 ), new ComplexNumber ( 0.2, 0 ), new ComplexNumber ( 0, 0 ) + }; + NumberSolutions expected_number_solutions = NumberSolutions.MANY; + string[] expected_general_solution = new string[] {"0.6 - x2 * (1.5) - x4 * (0.1)", "x2", + "0.2 - x4 * (-0.8)", "x4" + }; + + var actual_partial_solution = p.get_solution_partial (); + var actual_general_solution = p.get_solution_general (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + assert ( actual_general_solution.length == expected_general_solution.length ); + for ( int i = 0; i < actual_general_solution.length; ++i ) { + assert ( actual_general_solution[i] == expected_general_solution[i] ); + } + } catch { + assert ( false ); + } +} + +void solve12_solver_test () { + try { + var in = generate_filestream ( "3 3\n1+2i -1.5-1.1i 2.12 91+5i\n" + + "-1+3i 1.2+3.5i -3.3 1+15i\n12.31 1.3-5i 12.3i -78.3i" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] { + new ComplexNumber ( 6.73335286, -22.99754223 ), + new ComplexNumber ( -1.7976071, 2.08404919 ), + new ComplexNumber ( 15.69938581, 7.3960106 ) + }; + NumberSolutions expected_number_solutions = NumberSolutions.ONE; + string[] ? expected_general_solution = null; + + var actual_partial_solution = p.get_solution_partial (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( expected_general_solution == p.get_solution_general () ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + } catch { + assert ( false ); + } +} + +void solve13_solver_test () { + try { + var in = generate_filestream ( "1\t1\t2\t4" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( 2.0, 0 ) }; + NumberSolutions expected_number_solutions = NumberSolutions.ONE; + string[] ? expected_general_solution = null; + + var actual_partial_solution = p.get_solution_partial (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( expected_general_solution == p.get_solution_general () ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + } catch { + assert ( false ); + } +} + +void solve14_solver_test () { + try { + var in = generate_filestream ( "1 1\r\n2 4" ); + Solver p = new Solver ( in ); + p.solve (); + + ComplexNumber[] expected_partial_solution = new ComplexNumber[] {new ComplexNumber ( 2.0, 0 ) }; + NumberSolutions expected_number_solutions = NumberSolutions.ONE; + string[] ? expected_general_solution = null; + + var actual_partial_solution = p.get_solution_partial (); + + assert ( expected_number_solutions == p.number_solutions ); + assert ( expected_general_solution == p.get_solution_general () ); + assert ( actual_partial_solution.length == expected_partial_solution.length ); + for ( int i = 0; i < actual_partial_solution.length; ++i ) { + assert ( actual_partial_solution[i].equals ( expected_partial_solution[i] ) ); + } + } catch { + assert ( false ); + } +} + +void solve15_solver_test () { + try { + var in = generate_filestream ( "3 4\n1 1 2 9\n0 1 3 1\n0 2 6 1\n0 0 0 0" ); + Solver p = new Solver ( in ); + p.solve (); + + NumberSolutions expected_number_solutions = NumberSolutions.NONE; + + var actual_partial_solution = p.get_solution_partial (); + var actual_general_solution = p.get_solution_general (); + + assert ( p.number_solutions == expected_number_solutions ); + assert ( actual_partial_solution == null ); + assert ( actual_general_solution == null ); + } catch { + assert ( false ); + } +} diff --git a/Vala/test/test_util.vala b/Vala/test/test_util.vala new file mode 100644 index 0000000..90719ea --- /dev/null +++ b/Vala/test/test_util.vala @@ -0,0 +1,8 @@ +FileStream generate_filestream ( string s ) { + string tmp_filename = Environment.get_tmp_dir () + "/testXXXXXX"; + int handle_out = FileUtils.mkstemp ( tmp_filename ); + FileStream f = FileStream.fdopen ( handle_out, "w+" ); + f.puts ( s ); + f.rewind (); + return f; +} diff --git a/Vala/test/util.test.vala b/Vala/test/util.test.vala new file mode 100644 index 0000000..3b9b91f --- /dev/null +++ b/Vala/test/util.test.vala @@ -0,0 +1,49 @@ +void util_tests () { + Test.add_func ( "/read_next1_utul_test", read_next1_utul_test ); + Test.add_func ( "/read_next2_utul_test", read_next2_utul_test ); + Test.add_func ( "/round1_utul_test", round1_utul_test ); + Test.add_func ( "/round2_utul_test", round2_utul_test ); + Test.add_func ( "/round3_utul_test", round3_utul_test ); + Test.add_func ( "/round4_utul_test", round4_utul_test ); + +} + +void read_next1_utul_test () { + var in = generate_filestream ( "first second" ); + string ? s = Util.read_next ( in ); + + assert ( s != null ); + assert ( s == "first" ); +} + +void read_next2_utul_test () { + var in = generate_filestream ( "\n\n\t first \n\n\tsecond" ); + string ? s = Util.read_next ( in ); + + assert ( s != null ); + assert ( s == "first" ); +} + +void round1_utul_test () { + double rounded = Util.round ( 2.4 ); + + assert ( rounded == 2.0 ); +} + +void round2_utul_test () { + double rounded = Util.round ( 2.6 ); + + assert ( rounded == 3.0 ); +} + +void round3_utul_test () { + double rounded = Util.round ( -2.4 ); + + assert ( rounded == -2.0 ); +} + +void round4_utul_test () { + double rounded = Util.round ( -2.6 ); + + assert ( rounded == -3.0 ); +} diff --git a/Vala/valgrind.sh b/Vala/valgrind.sh new file mode 100755 index 0000000..a85eff7 --- /dev/null +++ b/Vala/valgrind.sh @@ -0,0 +1,14 @@ +OS="`uname`" +case $OS in + 'Linux') + alias make='make' + ;; + 'FreeBSD') + alias make='gmake' + ;; + *) ;; +esac + +make clean && VALGRIND=1 make && G_DEBUG=resident-modules G_DEBUG=gc-friendly G_SLICE=always-malloc valgrind --log-file=valgrind.txt --leak-resolution=high --num-callers=20 --leak-check=full bin/test_vala + + diff --git a/src/solver/Main.java b/src/solver/Main.java deleted file mode 100644 index 4404714..0000000 --- a/src/solver/Main.java +++ /dev/null @@ -1,7 +0,0 @@ -package solver; - -public class Main { - public static void main(String[] args) { - System.out.print("Hello world!"); - } -} \ No newline at end of file