diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/.editorconfig b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/.editorconfig new file mode 100644 index 0000000..51a0b79 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/.editorconfig @@ -0,0 +1,125 @@ +[*.cs] + +# SA1600: Elements should be documented +dotnet_diagnostic.SA1600.severity = none + +[*.cs] +#### Стили именования #### + +# Правила именования + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Спецификации символов + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Стили именования + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_indent_labels = one_less_than_current + +[*.vb] +#### Стили именования #### + +# Правила именования + +dotnet_naming_rule.interface_should_be_начинается_с_i.severity = suggestion +dotnet_naming_rule.interface_should_be_начинается_с_i.symbols = interface +dotnet_naming_rule.interface_should_be_начинается_с_i.style = начинается_с_i + +dotnet_naming_rule.типы_should_be_всечастиспрописнойбуквы.severity = suggestion +dotnet_naming_rule.типы_should_be_всечастиспрописнойбуквы.symbols = типы +dotnet_naming_rule.типы_should_be_всечастиспрописнойбуквы.style = всечастиспрописнойбуквы + +dotnet_naming_rule.не_являющиеся_полем_члены_should_be_всечастиспрописнойбуквы.severity = suggestion +dotnet_naming_rule.не_являющиеся_полем_члены_should_be_всечастиспрописнойбуквы.symbols = не_являющиеся_полем_члены +dotnet_naming_rule.не_являющиеся_полем_члены_should_be_всечастиспрописнойбуквы.style = всечастиспрописнойбуквы + +# Спецификации символов + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.типы.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.типы.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.типы.required_modifiers = + +dotnet_naming_symbols.не_являющиеся_полем_члены.applicable_kinds = property, event, method +dotnet_naming_symbols.не_являющиеся_полем_члены.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.не_являющиеся_полем_члены.required_modifiers = + +# Стили именования + +dotnet_naming_style.начинается_с_i.required_prefix = I +dotnet_naming_style.начинается_с_i.required_suffix = +dotnet_naming_style.начинается_с_i.word_separator = +dotnet_naming_style.начинается_с_i.capitalization = pascal_case + +dotnet_naming_style.всечастиспрописнойбуквы.required_prefix = +dotnet_naming_style.всечастиспрописнойбуквы.required_suffix = +dotnet_naming_style.всечастиспрописнойбуквы.word_separator = +dotnet_naming_style.всечастиспрописнойбуквы.capitalization = pascal_case + +dotnet_naming_style.всечастиспрописнойбуквы.required_prefix = +dotnet_naming_style.всечастиспрописнойбуквы.required_suffix = +dotnet_naming_style.всечастиспрописнойбуквы.word_separator = +dotnet_naming_style.всечастиспрописнойбуквы.capitalization = pascal_case + +[*.{cs,vb}] +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion +dotnet_style_namespace_match_folder = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/ParallelMatrixMultiplication.Test.csproj b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/ParallelMatrixMultiplication.Test.csproj new file mode 100644 index 0000000..944a8ea --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/ParallelMatrixMultiplication.Test.csproj @@ -0,0 +1,52 @@ + + + + net9.0 + latest + enable + enable + false + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestLoadFromFile.cs b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestLoadFromFile.cs new file mode 100644 index 0000000..bcc7691 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestLoadFromFile.cs @@ -0,0 +1,54 @@ +// +// Copyright (c) Kalinin Andrew. All rights reserved. +// + +namespace ParallelMatrixMultiplication.Test; + +public class TestLoadFromFile +{ + private Matrix firstExpectedMatrix; + private Matrix secondExpectedMatrix; + + [SetUp] + public void Setup() + { + this.firstExpectedMatrix = new Matrix(new int[,] + { + { 15, 16, 17 }, + { 20, 23, 26 }, + { 29, 32, 35 }, + }); + + this.secondExpectedMatrix = new Matrix(new int[,] + { + { 1, 2, 3, 4, 5 }, + { 6, 7, 8, 9, 10 }, + }); + } + + [Test] + public void LoadFromFile_SquareMatrix_ShouldReturnExpectedResult() + { + var result = Matrix.LoadFromFile("firstTestFileForRead.txt"); + for (int i = 0; i < result.Rows; ++i) + { + for (int j = 0; j < result.Columns; ++j) + { + Assert.That(result[i, j], Is.EqualTo(this.firstExpectedMatrix[i, j])); + } + } + } + + [Test] + public void LoadFromFile_NotSquareMatrix_ShouldReturnExpectedResult() + { + var result = Matrix.LoadFromFile("secondTestFileForRead.txt"); + for (int i = 0; i < result.Rows; ++i) + { + for (int j = 0; j < result.Columns; ++j) + { + Assert.That(result[i, j], Is.EqualTo(this.secondExpectedMatrix[i, j])); + } + } + } +} \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestSaveToFile.cs b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestSaveToFile.cs new file mode 100644 index 0000000..1e4cd5a --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestSaveToFile.cs @@ -0,0 +1,46 @@ +// +// Copyright (c) Kalinin Andrew. All rights reserved. +// + +namespace ParallelMatrixMultiplication.Test; + +public class TestSaveToFile +{ + private Matrix matrixToSave; + private string currentFilePath; + + [SetUp] + public void Setup() + { + this.matrixToSave = new Matrix(new int[,] + { + { 99, 90, 88, 80 }, + { 77, 70, 66, 60 }, + { 55, 50, 44, 40 }, + }); + + this.currentFilePath = "Test_STF.txt"; + } + + [TearDown] + public void Teardown() + { + if (File.Exists(this.currentFilePath)) + { + File.Delete(this.currentFilePath); + } + } + + [Test] + public void SaveToFile_ValidData_ShouldCreateExpectedFile() + { + this.matrixToSave.SaveToFile(this.currentFilePath); + + Assert.That(File.Exists(this.currentFilePath), Is.True); + + string expectedData = File.ReadAllText("expectedForSaveToFileTest.txt"); + string currentData = File.ReadAllText(this.currentFilePath); + + Assert.That(currentData, Is.EqualTo(expectedData)); + } +} \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestsBothMethodsAreSimilar.cs b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestsBothMethodsAreSimilar.cs new file mode 100644 index 0000000..0218d7a --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestsBothMethodsAreSimilar.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) Kalinin Andrew. All rights reserved. +// + +namespace ParallelMatrixMultiplication.Test; + +public class TestsBothMethodsAreSimilar +{ + private Matrix testRandomMatrixA; + private Matrix testRandomMatrixB; + + [SetUp] + public void Setup() + { + this.testRandomMatrixA = Matrix.GenerateRandomMatrix(77, 33); + this.testRandomMatrixB = Matrix.GenerateRandomMatrix(33, 77); + } + + [Test] + public void SequentialAndParallelMultiplication_RandomMatrix_ShouldReturnSameResult() + { + var parallelResult = MatrixMultiplier.ParallelMultiplication(this.testRandomMatrixA, this.testRandomMatrixB, 4); + var sequentialResult = MatrixMultiplier.SequentialMultiplication(this.testRandomMatrixA, this.testRandomMatrixB); + for (int i = 0; i < parallelResult.Rows; ++i) + { + for (int j = 0; j < parallelResult.Columns; ++j) + { + Assert.That(parallelResult[i, j], Is.EqualTo(sequentialResult[i, j])); + } + } + } +} \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestsParallelMultiply.cs b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestsParallelMultiply.cs new file mode 100644 index 0000000..467136c --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestsParallelMultiply.cs @@ -0,0 +1,84 @@ +// +// Copyright (c) Kalinin Andrew. All rights reserved. +// + +namespace ParallelMatrixMultiplication.Test; + +public class TestsParallelMultiply +{ + private Matrix testMatrixA2x2; + private Matrix testMatrixB2x2; + + private Matrix testMatrixA2x3; + private Matrix testMatrixB3x2; + + private Matrix firstExpectedResult; + private Matrix secondExpectedResult; + + [SetUp] + public void Setup() + { + this.testMatrixA2x2 = new Matrix(new int[,] + { + { 9, 4 }, + { 5, 1 }, + }); + + this.testMatrixB2x2 = new Matrix(new int[,] + { + { 5, 3 }, + { 8, 7 }, + }); + + this.testMatrixA2x3 = new Matrix(new int[,] + { + { 2, 1, 0 }, + { 7, -5, 6 }, + }); + + this.testMatrixB3x2 = new Matrix(new int[,] + { + { -2, 6 }, + { 4, 2 }, + { 3, 8 }, + }); + + this.firstExpectedResult = new Matrix(new int[,] + { + { 77, 55 }, + { 33, 22 }, + }); + + this.secondExpectedResult = new Matrix(new int[,] + { + { 0, 14 }, + { -16, 80 }, + }); + } + + [Test] + public void ParallelMultiplication_SquareMatrices_ShouldReturnExpectedResult() + { + var result = MatrixMultiplier.ParallelMultiplication(this.testMatrixA2x2, this.testMatrixB2x2, Environment.ProcessorCount); + for (int i = 0; i < result.Rows; ++i) + { + for (int j = 0; j < result.Columns; ++j) + { + Assert.That(result[i, j], Is.EqualTo(this.firstExpectedResult[i, j])); + } + } + } + + [Test] + public void ParallelMultiplication_NotSquareMatrices_ShouldReturnExpectedResult() + { + var result = MatrixMultiplier.ParallelMultiplication(this.testMatrixA2x3, this.testMatrixB3x2, Environment.ProcessorCount); + for (int i = 0; i < result.Rows; ++i) + { + for (int j = 0; j < result.Columns; ++j) + { + Assert.That(result[i, j], Is.EqualTo(this.secondExpectedResult[i, j])); + } + } + } +} \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestsSequentialMultiply.cs b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestsSequentialMultiply.cs new file mode 100644 index 0000000..1cbf703 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/TestsSequentialMultiply.cs @@ -0,0 +1,84 @@ +// +// Copyright (c) Kalinin Andrew. All rights reserved. +// + +namespace ParallelMatrixMultiplication.Test; + +public class TestsSequentialMultiply +{ + private Matrix testMatrixA2x2; + private Matrix testMatrixB2x2; + + private Matrix testMatrixA2x3; + private Matrix testMatrixB3x2; + + private Matrix firstExpectedResult; + private Matrix secondExpectedResult; + + [SetUp] + public void Setup() + { + this.testMatrixA2x2 = new Matrix(new int[,] + { + { 1, 2 }, + { 3, 4 }, + }); + + this.testMatrixB2x2 = new Matrix(new int[,] + { + { 9, 8 }, + { 7, 6 }, + }); + + this.testMatrixA2x3 = new Matrix(new int[,] + { + { 2, -3, 1 }, + { 5, 4, -2 }, + }); + + this.testMatrixB3x2 = new Matrix(new int[,] + { + { -7, 5 }, + { 2, -1 }, + { 4, 3 }, + }); + + this.firstExpectedResult = new Matrix(new int[,] + { + { 23, 20 }, + { 55, 48 }, + }); + + this.secondExpectedResult = new Matrix(new int[,] + { + { -16, 16 }, + { -35, 15 }, + }); + } + + [Test] + public void SequentialMultiplication_SquareMatrices_ShouldReturnExpectedResult() + { + var result = MatrixMultiplier.SequentialMultiplication(this.testMatrixA2x2, this.testMatrixB2x2); + for (int i = 0; i < result.Rows; ++i) + { + for (int j = 0; j < result.Columns; ++j) + { + Assert.That(result[i, j], Is.EqualTo(this.firstExpectedResult[i, j])); + } + } + } + + [Test] + public void SequentialMultiplication_NotSquareMatrices_ShouldReturnExpectedResult() + { + var result = MatrixMultiplier.SequentialMultiplication(this.testMatrixA2x3, this.testMatrixB3x2); + for (int i = 0; i < result.Rows; ++i) + { + for (int j = 0; j < result.Columns; ++j) + { + Assert.That(result[i, j], Is.EqualTo(this.secondExpectedResult[i, j])); + } + } + } +} \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/expectedForSaveToFileTest.txt b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/expectedForSaveToFileTest.txt new file mode 100644 index 0000000..8a1b8b5 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/expectedForSaveToFileTest.txt @@ -0,0 +1,3 @@ +99 90 88 80 +77 70 66 60 +55 50 44 40 \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/firstTestFileForRead.txt b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/firstTestFileForRead.txt new file mode 100644 index 0000000..dfd68d9 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/firstTestFileForRead.txt @@ -0,0 +1,3 @@ +15 16 17 +20 23 26 +29 32 35 \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/secondTestFileForRead.txt b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/secondTestFileForRead.txt new file mode 100644 index 0000000..ef25eaa --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/secondTestFileForRead.txt @@ -0,0 +1,2 @@ +1 2 3 4 5 +6 7 8 9 10 diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/stylecop.json b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.Test/stylecop.json new file mode 100644 index 0000000..ce12f73 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.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": "Kalinin Andrew", + "copyrightText": "Copyright (c) {companyName}. All rights reserved." + } + } +} diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication.sln b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.sln new file mode 100644 index 0000000..aec2fc3 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35806.99 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParallelMatrixMultiplication", "ParallelMatrixMultiplication\ParallelMatrixMultiplication.csproj", "{96DCD91F-9CF3-4519-8929-C0C38523DBB7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParallelMatrixMultiplication.Test", "ParallelMatrixMultiplication.Test\ParallelMatrixMultiplication.Test.csproj", "{217B9ADC-8DBB-4227-BE0F-6DF9674FF67A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {96DCD91F-9CF3-4519-8929-C0C38523DBB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96DCD91F-9CF3-4519-8929-C0C38523DBB7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96DCD91F-9CF3-4519-8929-C0C38523DBB7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96DCD91F-9CF3-4519-8929-C0C38523DBB7}.Release|Any CPU.Build.0 = Release|Any CPU + {217B9ADC-8DBB-4227-BE0F-6DF9674FF67A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {217B9ADC-8DBB-4227-BE0F-6DF9674FF67A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {217B9ADC-8DBB-4227-BE0F-6DF9674FF67A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {217B9ADC-8DBB-4227-BE0F-6DF9674FF67A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {902A2F58-AB9C-49FA-AD02-157B0D718B30} + EndGlobalSection +EndGlobal diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication/ArgumentParser.cs b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/ArgumentParser.cs new file mode 100644 index 0000000..a321136 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/ArgumentParser.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Kalinin Andrew. All rights reserved. +// + +namespace ParallelMatrixMultiplication; + +/// +/// A class for working with command line arguments. +/// +public static class ArgumentParser +{ + /// + /// Analyzes the command line arguments and determines the execution mode. + /// + /// An array of command line arguments. + /// A tuple containing the execution mode and an array of parameters. + public static (string Mode, string[] Parametrs) Parse(string[] args) + { + if (args == null || args.Length == 0) + { + throw new ArgumentException("Укажите режим работы ('load' или 'matrixTest')"); + } + + string mode = args[0].ToLower(); + string[] parametrs = args.Skip(1).ToArray(); + return (mode, parametrs); + } +} diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication/Matrix.cs b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/Matrix.cs new file mode 100644 index 0000000..bf31fa7 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/Matrix.cs @@ -0,0 +1,153 @@ +// +// Copyright (c) Kalinin Andrew. All rights reserved. +// + +namespace ParallelMatrixMultiplication; + +/// +/// A class representing a matrix and operations for working with it. +/// +public class Matrix +{ + /// + /// An array for storing matrix elements. + /// + private readonly int[,] numbers; + + /// + /// Initializes a new instance of the class. + /// + /// The number of specified rows. + /// The number of specified columns. + public Matrix(int rows, int columns) + { + this.numbers = new int[rows, columns]; + this.Rows = rows; + this.Columns = columns; + } + + /// + /// Initializes a new instance of the class from a 2D array. + /// + /// The 2D array containing matrix values. + public Matrix(int[,] data) + { + this.Rows = data.GetLength(0); + this.Columns = data.GetLength(1); + this.numbers = (int[,])data.Clone(); + } + + /// + /// Gets number of rows in the matrix. + /// + public int Rows { get; private set; } + + /// + /// Gets number of columns in the matrix. + /// + public int Columns { get; private set; } + + /// + /// Indexer for accessing matrix elements. + /// + /// Row index. + /// Column index. + /// The value of the element. + public int this[int rows, int columns] + { + get => this.numbers[rows, columns]; + } + + /// + /// A method for generating a matrix with random values. + /// + /// Number of lines. + /// Number of columns. + /// Matrix with random values. + public static Matrix GenerateRandomMatrix(int rows, int columns) + { + Random random = new Random(); + int[,] data = new int[rows, columns]; + for (int i = 0; i < rows; i++) + { + for (int j = 0; j < columns; ++j) + { + data[i, j] = random.Next(1, 74); + } + } + + return new Matrix(data); + } + + /// + /// A method for loading a matrix from a file. + /// + /// The path to the matrix file. + /// The matrix from the file. + /// It is thrown if the file is not found. + /// It is thrown if the file is empty or contains incorrect data. + /// It is thrown if the numbers in the file have an incorrect format. + public static Matrix LoadFromFile(string filePath) + { + if (!File.Exists(filePath)) + { + throw new FileNotFoundException($"Файл {filePath} не найден"); + } + + string[] lines = File.ReadAllLines(filePath); + + if (lines.Length == 0) + { + throw new InvalidDataException("Файл пуст"); + } + + int rows = lines.Length; + + string[] firstRowValues = lines[0].Split(' ', StringSplitOptions.RemoveEmptyEntries); + int columnsSize = firstRowValues.Length; + + int[,] data = new int[rows, columnsSize]; + for (int i = 0; i < rows; ++i) + { + string[] values = lines[i].Split(' ', StringSplitOptions.RemoveEmptyEntries); + + if (values.Length != columnsSize) + { + throw new InvalidDataException("Строка имеет некорректное значение стобцов"); + } + + for (int j = 0; j < columnsSize; ++j) + { + if (!int.TryParse(values[j], out int parsedValue)) + { + throw new FormatException("Неверный формат числа в строке"); + } + + data[i, j] = parsedValue; + } + } + + return new Matrix(data); + } + + /// + /// A method for saving a matrix to a file. + /// + /// The path to save the file. + public void SaveToFile(string filePath) + { + using StreamWriter writer = new StreamWriter(filePath); + for (int i = 0; i < this.Rows; i++) + { + for (int j = 0; j < this.Columns; j++) + { + writer.Write(this.numbers[i, j] + (j == this.Columns - 1 ? string.Empty : " ")); + } + + if (i < this.Rows - 1) + { + writer.WriteLine(); + } + } + } +} \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication/MatrixMultiplier.cs b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/MatrixMultiplier.cs new file mode 100644 index 0000000..297df56 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/MatrixMultiplier.cs @@ -0,0 +1,104 @@ +// +// Copyright (c) Kalinin Andrew. All rights reserved. +// + +namespace ParallelMatrixMultiplication; + +/// +/// A class for performing matrix multiplication in sequential and parallel ways. +/// +public static class MatrixMultiplier +{ + /// + /// Performs sequential multiplication of two matrices(AxB). + /// + /// The first matrix. + /// The second matrix. + /// The resulting matrix. + /// It is thrown if the number of columns of the first + /// matrix is not equal to the number of rows of the second. + /// + public static Matrix SequentialMultiplication(Matrix a, Matrix b) + { + if (a.Columns != b.Rows) + { + throw new InvalidDataException("Умножение невозможно(количество столбцов первой матрицы не равно количеству строк второй)"); + } + + int[,] resultData = new int[a.Rows, b.Columns]; + for (int i = 0; i < a.Rows; ++i) + { + for (int j = 0; j < b.Columns; j++) + { + int sum = 0; + for (int k = 0; k < a.Columns; k++) + { + sum += a[i, k] * b[k, j]; + } + + resultData[i, j] = sum; + } + } + + return new Matrix(resultData); + } + + /// + /// Performs parallel multiplication of two matrices(AxB). + /// + /// The first matrix. + /// The second matrix. + /// Number of threads. + /// The resulting matrix. + /// It is thrown if the number of columns of the first + /// matrix is not equal to the number of rows of the second. + /// + public static Matrix ParallelMultiplication(Matrix a, Matrix b, int numThreads) + { + if (a.Columns != b.Rows) + { + throw new InvalidDataException("Умножение невозможно(количество столбцов первой матрицы не равно количеству строк второй)"); + } + + int[,] resultData = new int[a.Rows, b.Columns]; + + int actualNumOfThread = Math.Min(a.Rows, numThreads); + Thread[] threads = new Thread[actualNumOfThread]; + int rowsForThread = a.Rows / actualNumOfThread; + + for (int i = 0; i < actualNumOfThread; ++i) + { + int startRow = i * rowsForThread; + int endRow = (i == actualNumOfThread - 1) ? a.Rows : (i + 1) * rowsForThread; + + threads[i] = new Thread(() => + { + for (int row = startRow; row < endRow; row++) + { + for (int columns = 0; columns < b.Columns; columns++) + { + int sum = 0; + for (int k = 0; k < a.Columns; ++k) + { + sum += a[row, k] * b[k, columns]; + } + + resultData[row, columns] = sum; + } + } + }); + } + + foreach (var thread in threads) + { + thread.Start(); + } + + foreach (var thread in threads) + { + thread.Join(); + } + + return new Matrix(resultData); + } +} \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication/MatrixUserInterface.cs b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/MatrixUserInterface.cs new file mode 100644 index 0000000..942eb6a --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/MatrixUserInterface.cs @@ -0,0 +1,117 @@ +// +// Copyright (c) Kalinin Andrew. All rights reserved. +// + +namespace ParallelMatrixMultiplication; + +using System.Diagnostics; + +/// +/// A user interface class for working with matrix multiplication. +/// +public static class MatrixUserInterface +{ + /// + /// Loads matrices from files, performs sequential and parallel multiplication, + /// and saves the results to files, as well as additionally measures execution time. + /// + /// The path to the first matrix. + /// The path to the second matrix. + /// The path to the sequential result matrix. + /// The path to the parallel result matrix. + public static void LoadFromFileAndMultiply(string pathA, string pathB, string sequentialSavePath, string parallelSavePath) + { + Matrix first = Matrix.LoadFromFile(pathA); + Matrix second = Matrix.LoadFromFile(pathB); + + Stopwatch stopwatch = Stopwatch.StartNew(); + Matrix sequentialResult = MatrixMultiplier.SequentialMultiplication(first, second); + stopwatch.Stop(); + Console.WriteLine($"\nПоследовательное умножение завершено. Время: {stopwatch.ElapsedMilliseconds} мс"); + + sequentialResult.SaveToFile(sequentialSavePath); + + int numOfThreads = Environment.ProcessorCount; + Console.WriteLine($"\nПараллельное умножение c {numOfThreads} потоками:"); + stopwatch.Restart(); + Matrix parallelResult = MatrixMultiplier.ParallelMultiplication(first, second, numOfThreads); + stopwatch.Stop(); + Console.WriteLine($"\nПараллельное уммножение завершено. Время: {stopwatch.ElapsedMilliseconds} мс"); + + parallelResult.SaveToFile(parallelSavePath); + } + + /// + /// Performs performance testing of sequential and parallel matrix multiplication + /// for various matrix sizes with a set number of runs. + /// + /// The number of runs for each test. + public static void UsersMatrixTests(int n) + { + var testCases = new List<(int RowsA, int ColumnsA, int RowsB, int ColumnsB)>() + { + (100, 100, 100, 100), + (200, 200, 200, 200), + (300, 300, 300, 300), + (400, 400, 400, 400), + (500, 500, 500, 500), + }; + + Console.WriteLine($"Проведение тестирования с {n} запусками"); + Console.WriteLine("\nРазмеры матриц | " + + "Матожидание(последовательное) | " + + "СКО(последовательное) | " + + "Матожидание(параллельное) | " + + "СКО(параллельное) \n"); + + foreach (var testCase in testCases) + { + int rowsA = testCase.RowsA; + int columnsA = testCase.ColumnsA; + int rowsB = testCase.RowsB; + int columnsB = testCase.ColumnsB; + + Matrix matrixA = Matrix.GenerateRandomMatrix(rowsA, columnsA); + Matrix matrixB = Matrix.GenerateRandomMatrix(rowsB, columnsB); + + var sequentialTimes = new List(); + var parallelTimes = new List(); + + int numOfThreads = Environment.ProcessorCount; + + for (int i = 0; i < n; ++i) + { + Stopwatch stopwatch = Stopwatch.StartNew(); + MatrixMultiplier.SequentialMultiplication(matrixA, matrixB); + stopwatch.Stop(); + sequentialTimes.Add(stopwatch.Elapsed.TotalMilliseconds); + + stopwatch.Restart(); + MatrixMultiplier.ParallelMultiplication(matrixA, matrixB, numOfThreads); + stopwatch.Stop(); + parallelTimes.Add(stopwatch.Elapsed.TotalMilliseconds); + } + + double sequentialExpectation = CalculateMathematicalExpectation(sequentialTimes); + double parallelExpectation = CalculateMathematicalExpectation(parallelTimes); + + double sequentialStandardDeviation = CalculateStandardDeviation(sequentialTimes, sequentialExpectation); + double parallelStandardDeviation = CalculateStandardDeviation(parallelTimes, parallelExpectation); + + Console.WriteLine($"{rowsA}x{columnsA} * {rowsB}x{columnsB} | {sequentialExpectation:F2} мс | {sequentialStandardDeviation:F2} | {parallelExpectation:F2} | {parallelStandardDeviation:F2}\n"); + } + } + + private static double CalculateMathematicalExpectation(List values) => values.Sum() / values.Count; + + private static double CalculateStandardDeviation(List values, double expectation) + { + double sumOfSquares = 0; + foreach (double value in values) + { + sumOfSquares += (value - expectation) * (value - expectation); + } + + return Math.Sqrt(sumOfSquares / values.Count); + } +} \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication/ParallelMatrixMultiplication.csproj b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/ParallelMatrixMultiplication.csproj new file mode 100644 index 0000000..81e1be1 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/ParallelMatrixMultiplication.csproj @@ -0,0 +1,25 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication/Program.cs b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/Program.cs new file mode 100644 index 0000000..7ff2eb9 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/Program.cs @@ -0,0 +1,63 @@ +// +// Copyright (c) Kalinin Andrew. All rights reserved. +// + +using ParallelMatrixMultiplication; + +args = Environment.GetCommandLineArgs().Skip(1).ToArray(); + +if (args.Length == 0) +{ + Console.WriteLine("\n Укажите режим работы ('load' или 'matrixTest')"); + return; +} +var (choice, parameters) = ArgumentParser.Parse(args); + +try +{ + switch (choice) + { + case "load": + if (parameters.Length < 4) + { + Console.WriteLine("Недостаточно аргументов. (load )"); + return; + } + + string pathA = parameters[0]; + string pathB = parameters[1]; + string sequentialSavePath = parameters[2]; + string parallelSavePath = parameters[3]; + + ArgumentNullException.ThrowIfNullOrEmpty(pathA); + ArgumentNullException.ThrowIfNullOrEmpty(pathB); + ArgumentNullException.ThrowIfNullOrEmpty(sequentialSavePath); + ArgumentNullException.ThrowIfNullOrEmpty(parallelSavePath); + MatrixUserInterface.LoadFromFileAndMultiply(pathA, pathB, sequentialSavePath, parallelSavePath); + break; + + case "matrixtest": + if (parameters.Length < 1) + { + Console.WriteLine("Недостаточно аргументов. (matrixtest )"); + return; + } + + if (!int.TryParse(parameters[0], out int n) || n <= 0) + { + Console.WriteLine("Неверное количество запусков. Ожидается целое положительное число"); + return; + } + + MatrixUserInterface.UsersMatrixTests(n); + break; + + default: + Console.WriteLine("\nНеизвестный ввод. Ожидается load или matrixtest\n"); + break; + } +} +catch (Exception ex) +{ + Console.WriteLine($"Произошла ошибка: {ex.Message}"); +} \ No newline at end of file diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication/resultOfTheExperiment.png b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/resultOfTheExperiment.png new file mode 100644 index 0000000..174583c Binary files /dev/null and b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/resultOfTheExperiment.png differ diff --git a/ParallelMatrixMultiplication/ParallelMatrixMultiplication/stylecop.json b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/stylecop.json new file mode 100644 index 0000000..ce12f73 --- /dev/null +++ b/ParallelMatrixMultiplication/ParallelMatrixMultiplication/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": "Kalinin Andrew", + "copyrightText": "Copyright (c) {companyName}. All rights reserved." + } + } +}