diff --git a/.gitignore b/.gitignore
index c64fcdf..5596d38 100644
--- a/.gitignore
+++ b/.gitignore
@@ -419,4 +419,4 @@ FodyWeavers.xsd
# Rider
.idea
-.git
\ No newline at end of file
+.git
diff --git a/HW1/HW1.sln b/HW1/HW1.sln
new file mode 100644
index 0000000..3ad542c
--- /dev/null
+++ b/HW1/HW1.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatrixMultiplication", "MatrixMultiplication\MatrixMultiplication.csproj", "{3C1ACBE6-BD12-4934-A58E-10141C3D6419}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "matrixmultiplication.Test", "matrixmultiplication.Test\matrixmultiplication.Test.csproj", "{93242727-EAF9-411B-AFFD-8FFFF083BE84}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3C1ACBE6-BD12-4934-A58E-10141C3D6419}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3C1ACBE6-BD12-4934-A58E-10141C3D6419}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3C1ACBE6-BD12-4934-A58E-10141C3D6419}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3C1ACBE6-BD12-4934-A58E-10141C3D6419}.Release|Any CPU.Build.0 = Release|Any CPU
+ {93242727-EAF9-411B-AFFD-8FFFF083BE84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {93242727-EAF9-411B-AFFD-8FFFF083BE84}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {93242727-EAF9-411B-AFFD-8FFFF083BE84}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {93242727-EAF9-411B-AFFD-8FFFF083BE84}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/HW1/MatrixMultiplication/MatrixBench.cs b/HW1/MatrixMultiplication/MatrixBench.cs
new file mode 100644
index 0000000..c37b03b
--- /dev/null
+++ b/HW1/MatrixMultiplication/MatrixBench.cs
@@ -0,0 +1,89 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+namespace MatrixMultiplication;
+
+using System;
+using System.Diagnostics;
+using System.Linq;
+
+///
+/// Compare the operating speed with the sequential version depending on the matrix sizes.
+///
+public static class MatrixBench
+{
+ ///
+ /// Runs the benchmark for multiple matrix sizes and saves the results to a file.
+ ///
+ public static void RunBenchmark()
+ {
+ int[] sizes = [100, 200, 300, 400, 500];
+ const string filePath = "resultBenchmark.txt";
+
+ File.WriteAllText(filePath, $"{"Size",4} {"Seq_Exp",10} {"Seq_Dev",10} {"Par_Exp",10} {"Par_Dev",10}\n");
+
+ foreach (var size in sizes)
+ {
+ var sequentialResult = BenchmarkMatrixMultiplication(size, false);
+ var parallelResult = BenchmarkMatrixMultiplication(size, true);
+
+ var line =
+ $"{size,4} {sequentialResult.Expectation,10:F4} {sequentialResult.Deviation,10:F4} {parallelResult.Expectation,10:F4} {parallelResult.Deviation,10:F4}";
+
+ File.AppendAllText("resultBenchmark.txt", line + Environment.NewLine);
+ }
+ }
+
+ ///
+ /// Runs a matrix multiplication benchmark and computes mathematical expectation and standard deviation.
+ ///
+ /// The number of rows and columns of the square matrix.
+ /// If true, uses parallel matrix multiplication.
+ /// Number of measurement repetitions for statistics (default 100).
+ ///
+ /// Tuple (expectation, deviation):.
+ /// - Expectation: mathematical expectation time in milliseconds.
+ /// - Deviation: standard deviation time in milliseconds.
+ ///
+ private static (double Expectation, double Deviation) BenchmarkMatrixMultiplication(int size, bool useParallel, int repeat = 10)
+ {
+ var elapsedTimes = new double[repeat];
+ for (var i = 0; i < repeat; i++)
+ {
+ elapsedTimes[i] = PerformSingleRun(size, useParallel);
+ }
+
+ var expectation = elapsedTimes.Average();
+ var deviation = Math.Sqrt(elapsedTimes.Average(t => Math.Pow(t - expectation, 2)));
+
+ return (expectation, deviation);
+ }
+
+ ///
+ /// Performs a single run of matrix multiplication with randomly generated matrix.
+ ///
+ /// The number of rows and columns of the square matrix.
+ /// If true, uses parallel matrix multiplication.
+ /// Elapsed time in milliseconds for a single multiplication.
+ private static long PerformSingleRun(int size, bool useParallel)
+ {
+ var matrix1 = MatrixUtils.GenerateRandomMatrix(size, size);
+ var matrix2 = MatrixUtils.GenerateRandomMatrix(size, size);
+
+ var stopwatch = Stopwatch.StartNew();
+
+ if (useParallel)
+ {
+ MatrixUtils.MultiplyMatrixParallel(matrix1, matrix2);
+ }
+ else
+ {
+ MatrixUtils.MultiplyMatrix(matrix1, matrix2);
+ }
+
+ stopwatch.Stop();
+
+ return stopwatch.ElapsedMilliseconds;
+ }
+}
\ No newline at end of file
diff --git a/HW1/MatrixMultiplication/MatrixFormatException.cs b/HW1/MatrixMultiplication/MatrixFormatException.cs
new file mode 100644
index 0000000..f0ef9c5
--- /dev/null
+++ b/HW1/MatrixMultiplication/MatrixFormatException.cs
@@ -0,0 +1,37 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+namespace MatrixMultiplication;
+
+///
+/// The exception that is thrown when a matrix file has an invalid format.
+///
+public class MatrixFormatException : Exception
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public MatrixFormatException()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a message.
+ ///
+ /// The error message.
+ public MatrixFormatException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a message and inner exception.
+ ///
+ /// The error message.
+ /// The inner exception.
+ public MatrixFormatException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+}
\ No newline at end of file
diff --git a/HW1/MatrixMultiplication/MatrixMultiplication.csproj b/HW1/MatrixMultiplication/MatrixMultiplication.csproj
new file mode 100644
index 0000000..917eeb4
--- /dev/null
+++ b/HW1/MatrixMultiplication/MatrixMultiplication.csproj
@@ -0,0 +1,27 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ true
+ $(NoWarn);1591
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/HW1/MatrixMultiplication/MatrixUtils.cs b/HW1/MatrixMultiplication/MatrixUtils.cs
new file mode 100644
index 0000000..de08e66
--- /dev/null
+++ b/HW1/MatrixMultiplication/MatrixUtils.cs
@@ -0,0 +1,242 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+namespace MatrixMultiplication;
+
+///
+/// Helper static class for working with matrices.
+/// Contains functions for generating, checking, and other matrix operations.
+///
+public static class MatrixUtils
+{
+ ///
+ /// Generates a random integer matrix of the specified size with values in the given range.
+ ///
+ /// Number of rows in the matrix.
+ /// Number of columns in the matrix.
+ /// Minimum value for matrix elements (inclusive).
+ /// Maximum value for matrix elements (exclusive).
+ /// A 2D integer array filled with random values.
+ public static int[,] GenerateRandomMatrix(int rows, int columns, int minValue = -100, int maxValue = 100)
+ {
+ var matrix = new int[rows, columns];
+ var randomNumbers = new Random();
+
+ for (var i = 0; i < rows; i++)
+ {
+ for (var j = 0; j < columns; j++)
+ {
+ matrix[i, j] = randomNumbers.Next(minValue, maxValue);
+ }
+ }
+
+ return matrix;
+ }
+
+ ///
+ /// Multiplies two matrices and returns the result.
+ ///
+ /// First matrix.
+ /// Second matrix.
+ /// Resulting matrix after multiplication.
+ public static int[,] MultiplyMatrix(int[,] matrix1, int[,] matrix2)
+ {
+ var lengthRowMatrix1 = matrix1.GetLength(0);
+ var lengthColumnMatrix1 = matrix1.GetLength(1);
+ var lengthRowMatrix2 = matrix2.GetLength(0);
+ var lengthColumnMatrix2 = matrix2.GetLength(1);
+
+ // Checking the compatibility of matrices for multiplication
+ if (lengthColumnMatrix1 != lengthRowMatrix2)
+ {
+ throw new ArgumentException("The number of columns of the first matrix is not equal to the number of rows of the second one!");
+ }
+
+ var result = new int[lengthRowMatrix1, lengthColumnMatrix2];
+
+ for (var i = 0; i < lengthRowMatrix1; i++)
+ {
+ for (var j = 0; j < lengthColumnMatrix2; j++)
+ {
+ var sum = 0;
+ for (var k = 0; k < lengthColumnMatrix1; k++)
+ {
+ sum += matrix1[i, k] * matrix2[k, j];
+ }
+
+ result[i, j] = sum;
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Multiplies two matrices in parallel.
+ /// Each cell of the result matrix is computed in a separate thread.
+ ///
+ /// First matrix.
+ /// Second matrix.
+ /// Resulting matrix of multiplication.
+ /// Thrown when dimensions are not compatible for multiplication.
+ public static int[,] MultiplyMatrixParallel(int[,] matrix1, int[,] matrix2)
+ {
+ var lengthRowMatrix1 = matrix1.GetLength(0);
+ var lengthColumnMatrix1 = matrix1.GetLength(1);
+ var lengthRowMatrix2 = matrix2.GetLength(0);
+ var lengthColumnMatrix2 = matrix2.GetLength(1);
+
+ // Checking the compatibility of matrices for multiplication
+ if (lengthColumnMatrix1 != lengthRowMatrix2)
+ {
+ throw new ArgumentException("The number of columns of the first matrix is not equal to the number of rows of the second one.");
+ }
+
+ var result = new int[lengthRowMatrix1, lengthColumnMatrix2];
+ var numThreads = Math.Min(Environment.ProcessorCount, lengthRowMatrix1);
+ var threads = new Thread[numThreads];
+
+ for (var t = 0; t < numThreads; t++)
+ {
+ var threadIndex = t;
+ threads[t] = new Thread(() =>
+ {
+ for (var i = threadIndex; i < lengthRowMatrix1; i += numThreads)
+ {
+ for (var j = 0; j < lengthColumnMatrix2; j++)
+ {
+ var sum = 0;
+ for (var k = 0; k < lengthColumnMatrix1; k++)
+ {
+ sum += matrix1[i, k] * matrix2[k, j];
+ }
+
+ result[i, j] = sum;
+ }
+ }
+ });
+ threads[t].Start();
+ }
+
+ for (var i = 0; i < numThreads; i++)
+ {
+ threads[i].Join();
+ }
+
+ return result;
+ }
+
+ ///
+ /// Compares two matrices for equality.
+ ///
+ /// First matrix.
+ /// Second matrix.
+ ///
+ /// true — if the matrices are the same size and all their elements match.
+ /// false — if the dimensions are different or at least one element is different.
+ ///
+ public static bool AreMatrixEqual(int[,] matrix1, int[,] matrix2)
+ {
+ if (matrix1.GetLength(0) != matrix2.GetLength(0) ||
+ matrix1.GetLength(1) != matrix2.GetLength(1))
+ {
+ return false;
+ }
+
+ var rows = matrix1.GetLength(0);
+ var columns = matrix1.GetLength(1);
+
+ for (var i = 0; i < rows; i++)
+ {
+ for (var j = 0; j < columns; j++)
+ {
+ if (matrix1[i, j] != matrix2[i, j])
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ /// Reads a matrix of integers from a text file.
+ ///
+ /// The path to the file containing the matrix.
+ /// matrix from file.
+ public static int[,] ReadMatrixFromFile(string path)
+ {
+ // Checking the existence of the file
+ if (!File.Exists(path))
+ {
+ throw new FileNotFoundException("File not found.");
+ }
+
+ var lines = File.ReadAllLines(path);
+
+ // Checking that the file is not empty
+ if (lines.Length == 0)
+ {
+ throw new MatrixFormatException("Matrix file is empty.");
+ }
+
+ var rows = lines.Length;
+ var columns = lines[0].Split(' ', StringSplitOptions.RemoveEmptyEntries).Length;
+
+ var matrix = new int[rows, columns];
+
+ for (var i = 0; i < rows; i++)
+ {
+ // Check that the string contains only numbers, spaces, and minus signs.
+ if (lines[i].Any(c => !char.IsDigit(c) && c != ' ' && c != '-'))
+ {
+ throw new MatrixFormatException("Invalid character in matrix file: only digits, spaces and minus signs are allowed.");
+ }
+
+ var nums = lines[i].Split(' ', StringSplitOptions.RemoveEmptyEntries)
+ .Select(int.Parse)
+ .ToArray();
+
+ // Checking that all rows and columns in the matrix have the same length
+ if (nums.Length != columns)
+ {
+ throw new MatrixFormatException("Invalid matrix format: the matrix is not complete.");
+ }
+
+ for (var j = 0; j < columns; j++)
+ {
+ matrix[i, j] = nums[j];
+ }
+ }
+
+ return matrix;
+ }
+
+ ///
+ /// Writes a matrix to a text file.
+ ///
+ /// The path to the output file.
+ /// Matrix for writing to file to write.
+ public static void WriteMatrixToFile(string path, int[,] matrix)
+ {
+ var rows = matrix.GetLength(0);
+ var columns = matrix.GetLength(1);
+
+ using var writer = new StreamWriter(path);
+ for (var i = 0; i < rows; i++)
+ {
+ for (var j = 0; j < columns; j++)
+ {
+ writer.Write(matrix[i, j]);
+ if (j < columns - 1)
+ {
+ writer.Write(" ");
+ }
+ }
+
+ writer.WriteLine();
+ }
+ }
+}
\ No newline at end of file
diff --git a/HW1/MatrixMultiplication/Program.cs b/HW1/MatrixMultiplication/Program.cs
new file mode 100644
index 0000000..41ffa23
--- /dev/null
+++ b/HW1/MatrixMultiplication/Program.cs
@@ -0,0 +1,64 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+using MatrixMultiplication;
+
+// 1. To multiply matrices from files:
+// Write dotnet run --
+// Input files must contain matrices as strings of numbers separated by spaces.
+// Each line of the file is a row of the matrix.
+// The program checks the correctness of the matrix sizes and creates a new file with the product.
+// Example:
+// dotnet run -- "TestMatrix/TestFile1.txt" "TestMatrix/TestFile2.txt" "TestMatrix/result.txt"
+//
+// 2. To run the statistics benchmark:
+// dotnet run -- benchmark
+//
+if (args.Length == 1 && args[0].Equals("benchmark", StringComparison.CurrentCultureIgnoreCase))
+{
+ MatrixBench.RunBenchmark();
+}
+else if (args.Length != 3 || string.IsNullOrEmpty(args[0]) || string.IsNullOrEmpty(args[1]) || string.IsNullOrEmpty(args[2]))
+{
+ Console.WriteLine("Invalid arguments");
+ Console.WriteLine(
+ "Usage:\n" +
+ "1) Matrix multiplication:\n" +
+ " dotnet run -- \n" +
+ "2) Run benchmark:\n" +
+ " dotnet run -- benchmark");
+}
+else
+{
+ var matrixPath1 = args[0];
+ var matrixPath2 = args[1];
+ var resultFile = args[2];
+
+ try
+ {
+ var matrix1 = MatrixUtils.ReadMatrixFromFile(matrixPath1);
+ var matrix2 = MatrixUtils.ReadMatrixFromFile(matrixPath2);
+ var matrixResult = MatrixUtils.MultiplyMatrixParallel(matrix1, matrix2);
+
+ MatrixUtils.WriteMatrixToFile(resultFile, matrixResult);
+
+ Console.WriteLine($"Matrix multiplication completed successfully. Result saved in '{resultFile}'.");
+ }
+ catch (MatrixFormatException ex)
+ {
+ Console.WriteLine($"Matrix error: {ex.Message}");
+ }
+ catch (FileNotFoundException ex)
+ {
+ Console.WriteLine($"File error: {ex.Message}");
+ }
+ catch (ArgumentException ex)
+ {
+ Console.WriteLine($"Multiplication error: {ex.Message}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Unexpected error: {ex.Message}");
+ }
+}
diff --git a/HW1/MatrixMultiplication/resultBenchmark.txt b/HW1/MatrixMultiplication/resultBenchmark.txt
new file mode 100644
index 0000000..d85199e
--- /dev/null
+++ b/HW1/MatrixMultiplication/resultBenchmark.txt
@@ -0,0 +1,6 @@
+Size Seq_Exp Seq_Dev Par_Exp Par_Dev
+ 100 9,6000 1,2806 7,7000 2,5710
+ 200 46,6000 6,2960 15,7000 1,2689
+ 300 164,4000 20,0659 97,3000 47,3984
+ 400 1010,1000 55,4084 327,5000 204,1613
+ 500 2477,7000 791,3668 306,6000 30,5817
diff --git a/HW1/MatrixMultiplication/stylecop.json b/HW1/MatrixMultiplication/stylecop.json
new file mode 100644
index 0000000..76c8e76
--- /dev/null
+++ b/HW1/MatrixMultiplication/stylecop.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "documentationRules": {
+ "companyName": "khusainovilas",
+ "copyrightText": "Copyright (c) {companyName}. All rights reserved."
+ }
+ }
+}
\ No newline at end of file
diff --git a/HW1/matrixmultiplication.Test/MatrixmultiplicationTest.cs b/HW1/matrixmultiplication.Test/MatrixmultiplicationTest.cs
new file mode 100644
index 0000000..4dbf6cf
--- /dev/null
+++ b/HW1/matrixmultiplication.Test/MatrixmultiplicationTest.cs
@@ -0,0 +1,93 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+namespace Matrixmultiplication.Test;
+
+using MatrixMultiplication;
+
+///
+/// NUnit tests for matrix multiplication functions.
+/// Tests both sequential and parallel implementations for correctness.
+///
+public class MatrixmultiplicationTest
+{
+ private int[,] matrix1;
+ private int[,] matrix2;
+ private int[,] matrixExpected;
+
+ ///
+ /// Initializes matrices before each test.
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ this.matrix1 = new int[,]
+ {
+ { 1, 2 },
+ { 3, 4 },
+ };
+ this.matrix2 = new int[,]
+ {
+ { 2, 0 },
+ { 1, 2 },
+ };
+ this.matrixExpected = new int[,]
+ {
+ { 4, 4 },
+ { 10, 8 },
+ };
+ }
+
+ ///
+ /// Tests the sequential matrix multiplication function.
+ ///
+ [Test]
+ public void MatrixUtils_MatrixMultiply_Matrix1_Matrix2()
+ {
+ var result = MatrixUtils.MultiplyMatrix(this.matrix1, this.matrix2);
+ Assert.That(MatrixUtils.AreMatrixEqual(result, this.matrixExpected), Is.True);
+ }
+
+ ///
+ /// Tests the parallel matrix multiplication function.
+ ///
+ [Test]
+ public void MatrixUtils_MultiplyMatrixParallel_Matrix1_Matrix2()
+ {
+ var result = MatrixUtils.MultiplyMatrixParallel(this.matrix1, this.matrix2);
+ Assert.That(MatrixUtils.AreMatrixEqual(result, this.matrixExpected), Is.True);
+ }
+
+ ///
+ /// Tests multiplication with 1x1 matrices.
+ ///
+ [Test]
+ public void MultiplyMatrix_OneByOneMatrices_ReturnsCorrectValue()
+ {
+ int[,] a = { { 5 } };
+ int[,] b = { { 3 } };
+ int[,] expected = { { 15 } };
+
+ var resultSeq = MatrixUtils.MultiplyMatrix(a, b);
+ var resultPar = MatrixUtils.MultiplyMatrixParallel(a, b);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(MatrixUtils.AreMatrixEqual(resultSeq, expected), Is.True);
+ Assert.That(MatrixUtils.AreMatrixEqual(resultPar, expected), Is.True);
+ });
+ }
+
+ ///
+ /// Tests multiplication with empty matrices.
+ ///
+ [Test]
+ public void MultiplyMatrix_EmptyMatrices_ThrowsArgumentException()
+ {
+ int[,] empty = new int[0, 0];
+
+ Assert.Throws(() => MatrixUtils.MultiplyMatrix(empty, this.matrix2));
+ Assert.Throws(() => MatrixUtils.MultiplyMatrixParallel(empty, this.matrix2));
+ }
+}
diff --git a/HW1/matrixmultiplication.Test/matrixmultiplication.Test.csproj b/HW1/matrixmultiplication.Test/matrixmultiplication.Test.csproj
new file mode 100644
index 0000000..8f34892
--- /dev/null
+++ b/HW1/matrixmultiplication.Test/matrixmultiplication.Test.csproj
@@ -0,0 +1,36 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/HW1/matrixmultiplication.Test/stylecop.json b/HW1/matrixmultiplication.Test/stylecop.json
new file mode 100644
index 0000000..76c8e76
--- /dev/null
+++ b/HW1/matrixmultiplication.Test/stylecop.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "documentationRules": {
+ "companyName": "khusainovilas",
+ "copyrightText": "Copyright (c) {companyName}. All rights reserved."
+ }
+ }
+}
\ No newline at end of file