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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ solutionIndexes
+ solution[
+ solution
+ print
+ printSo
+ System.out
+ -
+ multiplyRow
+ divideRow
+ checkThatSolutionIsSane
+ getS
+ partic
+ "3 3\n1 1 2 9\n2 4 -3 1\n3 6 -5 0"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1545073768711
+
+
+ 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