Created
November 13, 2017 04:17
-
-
Save SibTiger/1c3829b2dea43e59b277384422e092c2 to your computer and use it in GitHub Desktop.
Operating Systems: Multiply two matrices [Dynamic]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ===================================================== | |
// Programmer: Nicholas Gautier | |
// Class: CS3513; Operating System | |
// Assignment #: 3 | |
// Due Date: 31. Oktober. 2017 | |
// Instructor: Dr. Zhao | |
// Description: This program is designed to take two | |
// matrix's and multiply them to capture | |
// the answer. | |
// NOTES: | |
// Credits: Dr. Agyros; teaching Matrix Algebra | |
// Return Codes: | |
// 0 = Successful Operation | |
// !0 = See Operating System documentation | |
// ===================================================== | |
#pragma region Inclusions | |
#include <stdio.h> // Basic input and output | |
#include <stdbool.h> // Because I was spoiled in C[++ | #]; give me bool datatypes! | |
#include <ctype.h> // Used for tolower() function | |
#include <stddef.h> // NULLPTR | |
#include <stdlib.h> // Malloc | |
#include <pthread.h> // Used for threads; because I want to join threads (kill them) | |
#pragma endregion | |
#pragma region Function Prototypes | |
void DrawInstructions(); // Displays instructions to the end user | |
void DrawHeader(); // Displays the program header on the terminal buffer | |
char RunAgainQuestion(); // Provides the option for the user to solve another | |
// matrix or close the program. | |
int FetchMatrixSize(bool); // Allow the end-user to specify the matrix size (length or height) | |
int FetchNumber(); // This function will allow the end-user to provide numerical data. | |
// Preferably | |
void AllocateMemory(int***, int, int); // Allocate the memory space (pointers) | |
void DeallocateMemory(int***, int); // Thrash the memory space (pointers) | |
void DefineMatrixDimensions(int, int); // Allows the user to define the matrix size | |
void DrawMatrix(int**, int, int); // This function will display the matrix on the screen. | |
void FillMatrix(int**, int, int, bool); // Allow the user to populate the matrix | |
bool CheckMultiplicationTheorem(int, int); // This function will check if the two matrices follows the multiplication theorem | |
void MultiplyMatricesThreadingSetup(); // Setup the multiplication process. | |
void MultiplyMatricesThreadingProcess(void *); // Multiply the two matrices | |
#pragma endregion | |
#pragma region Global Definitions | |
#define _NAME_ "Matrix Product Solver" // Name of this program | |
#define _VERSION_ "1.0" // Version of this program | |
#define _THREAD_COUNT_MAX_ 10 // Maximum number of threads possible | |
#define _MATRIX_MAX_SIZE_ 100 // [DEPRECATED] This is the max size possible of the matrices within this program. | |
#pragma endregion | |
#pragma region Global Data | |
// Matrices | |
int **matrixA; // User Defined Matrix | |
int **matrixB; // User Defined Matrix | |
int **matrixC; // Answer Matrix | |
// Matrices Dimensions | |
int sizeColumnsMatrixA; // Used to determine the size of the 'A' matrix's height | |
int sizeRowsMatrixA; // Used to determine the size of the 'A' matrix's length | |
int sizeColumnsMatrixB; // Used to determine the size of the 'B' matrix's height | |
int sizeRowsMatrixB; // Used to determine the size of the 'B' matrix's length | |
#pragma endregion | |
#pragma region Structs | |
struct MatrixIndexes | |
{ | |
// Indexing | |
int indexColumn; | |
int indexRow; | |
}; // Struct : Matrix | |
#pragma endregion | |
// Main program entry point | |
int main() | |
{ | |
// Declaration and Initializations | |
// ------------------------ | |
char userChoice = 'n'; // This will be used to determine if the user wants to | |
// calculate another matrix product. | |
// ------------------------ | |
do | |
{ | |
printf("\n\n\n\n"); // Provide some padding before displaying any information. | |
// Program Initial Run | |
DrawHeader(); // Display the program header | |
DrawInstructions(); // Display the instructions to the end-user | |
// Setup the two matrices | |
printf("Please provide the following information:\n"); | |
printf("First Matrix\n-----------\n"); | |
sizeColumnsMatrixA = FetchMatrixSize(false); | |
sizeRowsMatrixA = FetchMatrixSize(true); | |
printf("\n"); | |
printf("Second Matrix\n-----------\n"); | |
sizeColumnsMatrixB = FetchMatrixSize(false); | |
sizeRowsMatrixB = FetchMatrixSize(true); | |
printf("\n"); | |
// Make sure that the matrices are valid; if not - do not proceed any further. | |
printf("Checking if Multiplication Theorem. . .\n"); | |
if (!CheckMultiplicationTheorem(sizeColumnsMatrixA, sizeRowsMatrixB)) | |
{ // Multiplication Theorem validation failed | |
printf ("\a"); // Sound bell for error | |
printf ("\n\nMULTIPLICATION THEOREM CHECK FAILED!\n"); | |
printf ("The two matrices fails the 'Multiplication Theorem' rules\n"); | |
printf ("Please make sure that Matrix A's column space matches with Matrix B's row space.\n"); | |
printf ("----\n"); | |
printf ("First Matrix Dimensions: %d x %d\n", sizeRowsMatrixA, sizeColumnsMatrixA); | |
printf ("Second Matrix Dimensions: %d x %d\n\n", sizeRowsMatrixB, sizeColumnsMatrixB); | |
} // IF: Bad Matrices - Multiplication Theorem | |
else | |
{ // Multiplication Theorem validation succeeded | |
printf("Allocating the required memory space. . .\n"); | |
AllocateMemory(&matrixA, sizeRowsMatrixA, sizeColumnsMatrixA); | |
AllocateMemory(&matrixB, sizeRowsMatrixB, sizeColumnsMatrixB); | |
AllocateMemory(&matrixC, sizeColumnsMatrixA, sizeRowsMatrixB); // Answer Matrix | |
printf("Populating matrices. . .\n"); | |
FillMatrix(matrixA, sizeRowsMatrixA, sizeColumnsMatrixA, true); | |
FillMatrix(matrixB, sizeRowsMatrixB, sizeColumnsMatrixB, true); | |
printf("Displaying matrices. . .\n"); | |
printf("Matrix A:\n"); | |
DrawMatrix(matrixA, sizeRowsMatrixA, sizeColumnsMatrixA); | |
printf("Matrix B:\n"); | |
DrawMatrix(matrixB, sizeRowsMatrixB, sizeColumnsMatrixB); | |
// ---- | |
// Initialize the Matrix C (the answer) | |
MultiplyMatricesThreadingSetup(); | |
printf("Matrix C:\n"); | |
DrawMatrix(matrixC, sizeRowsMatrixA, sizeColumnsMatrixB); | |
// ---- | |
// Thrash the matrices | |
printf("Thrashing the matrices. . . .\n"); | |
DeallocateMemory(&matrixA, sizeRowsMatrixA); | |
DeallocateMemory(&matrixB, sizeRowsMatrixB); | |
DeallocateMemory(&matrixC, sizeRowsMatrixB); // Answer Matrix | |
} // ELSE: Matrices follows Multiplication Theorem | |
// Does the user wants to solve another matrix? | |
userChoice = RunAgainQuestion(); | |
// ---- | |
} while(tolower(userChoice) == 'y'); // Solve another matrix product? | |
printf("Closing %s...\n", _NAME_); | |
return 0; // Close the program | |
} // main() | |
// Multiply Matrices [Threading] | |
// ==================================== | |
// This function will prepare the multiplication process between the two matrices. | |
void MultiplyMatricesThreadingSetup() | |
{ | |
// Initialization and Declarations | |
// ------------------------ | |
struct MatrixIndexes *objMatrixData = (struct MatrixIndexes*) malloc(sizeof(struct MatrixIndexes)); // Create a new object of the matrix | |
// This will merely be held for preparation | |
int i; // Utilized for the 'for' loop; as we can not declare | |
// within the for-loop. | |
int j; // Utilized for the 'for' loop; as we can not declare | |
// within the for-loop. | |
// ------------------------ | |
for(i = 0; i < sizeRowsMatrixA; i++) | |
for(j = 0; j < sizeColumnsMatrixB; j++) | |
{ | |
// Assign the required data | |
objMatrixData->indexColumn = i; | |
objMatrixData->indexRow = j; | |
// Prepare thread data | |
pthread_t tid; // Thread ID | |
pthread_attr_t threadAttributes; // Declaration for thread attributes | |
pthread_attr_init(&threadAttributes); // Generate default attributes | |
// Generate thread | |
pthread_create(&tid, &threadAttributes, MultiplyMatricesThreadingProcess, objMatrixData); | |
// Wait for the thread to finish - then kill it | |
pthread_join(tid, NULL); | |
} // Inner-loop | |
} // MultiplyMatricesThreadingSetup() | |
// Multiply Matrices [[Threading _Process_]] | |
// ==================================== | |
// This function will perform the actual multiplication process between the two matrices. | |
void MultiplyMatricesThreadingProcess(void* objMatrix) | |
{ | |
// Initialization and Declarations | |
// ------------------------ | |
struct MatrixIndexes *matrixData = objMatrix; // Utilizes another matrix object for processing | |
int i; // Used for the for-loop | |
int sum = 0; // Holds the answer | |
// ------------------------ | |
// Multiplication Process | |
for (i = 0; i < sizeColumnsMatrixA; i++) | |
sum += matrixA[matrixData->indexColumn][i] * matrixB[i][matrixData->indexRow]; | |
// Store the result in the actual matrix | |
matrixC[matrixData->indexColumn][matrixData->indexRow] = sum; | |
// Close the thread | |
pthread_exit(0); | |
} // MultiplyMatricesThreadingProcess() | |
// Check Multiplication Theorem | |
// ==================================== | |
// This function will make sure that the two matrices are following the | |
// multiplication theorem. To do this, we assure that the first matrix | |
// columns matches with the number of rows with the second matrix. | |
// ---- | |
// Parameters: | |
// matrixAColumns [int] | |
// Number of columns within the first matrix | |
// matrixBRows [int] | |
// Number of rows within the second matrix | |
// ---- | |
// Output: | |
// [Bool] | |
// false | |
// When the two matrices fail the multiplication theorem, false will be returned. | |
// true | |
// When the two matrices pass the multiplication theorem, true will be returned. | |
bool CheckMultiplicationTheorem(int matrixAColumns, int matrixBRows) | |
{ | |
if (matrixAColumns != matrixBRows) | |
return false; | |
else | |
return true; | |
} // CheckMultiplicationTheorem() | |
// Fill Matrix | |
// ==================================== | |
// This function will allow the end-user to input data into | |
// the matrix's indexes (2-Dimensional array) | |
// ---- | |
// Parameters: | |
// matrixArray [int***] | |
// The matrix in which we are going to populate data into. | |
// matrixRow [int] | |
// How many rows for the matrix. | |
// matrixColumn [int] | |
// How many columns for the matrix. | |
void FillMatrix(int** matrixArray, int matrixRow, int matrixColumn, bool enforceRandomValues) | |
{ | |
// Initialization and Declarations | |
// ------------------------ | |
int i; // Utilized for the 'for' loop; as we can not declare within the for-loop. | |
int j; // Utilized for the 'for' loop; as we can not declare within the for-loop. | |
// ------------------------ | |
// Scan through the matrix's indexes to add data | |
for (i = 0; i < matrixRow; i++) | |
for (j = 0; j < matrixColumn; j++) | |
{ | |
if (enforceRandomValues) | |
// Automatically generate data | |
matrixArray[i][j] = rand() % _MATRIX_MAX_SIZE_; | |
else | |
{ | |
// User inputs data into the matrix | |
// ***************************************** | |
// * I don't always test my code. * | |
// * But when I do, I do it in production. * | |
// ***************************************** | |
printf("Enter data for the Matrix Index: row [ %d ] - column [ %d ]\n", i, j); | |
matrixArray[i][j] = FetchNumber(); | |
} // Else: Manual Input | |
} // FOR: Matrix Column | |
} // FillMatrix() | |
// Draw Matrix | |
// ==================================== | |
// This function will merely display the matrix provided. | |
// ---- | |
// Parameters: | |
// matrixArray [int***] | |
// The matrix we are going to draw | |
// matrixRow [int] | |
// How many rows for the matrix. | |
// matrixColumn [int] | |
// How many columns for the matrix. | |
void DrawMatrix(int** matrixArray, int matrixRow, int matrixColumn) | |
{ | |
// Initialization and Declarations | |
// ------------------------ | |
int i; // Utilized for the 'for' loop; as we can not declare within the for-loop. | |
int j; // Utilized for the 'for' loop; as we can not declare within the for-loop. | |
// ------------------------ | |
// Provide some information about the matrix | |
printf("Matrix contains [ %d ] rows and [ %d ] columns.\n", matrixRow, matrixColumn); | |
// Scan through the matrix's indexes | |
for (i = 0; i < matrixRow; i++) | |
{ | |
for (j = 0; j < matrixColumn; j++) | |
printf("%d\t", matrixArray[i][j]); | |
printf("\n"); // We will use this to make our output nicer; just like an ordinary Matrix\cube | |
} // FOR: Outer-loop | |
printf("\n\n"); | |
} // DrawMatrix() | |
// Allocate Memory (Pointers) | |
// ==================================== | |
// This function will allocate the memory locations necessary for the requested matrix. | |
// ---- | |
// Parameters: | |
// matrixArray [int***] | |
// The matrix in which is going to be allocated | |
// matrixRow [int] | |
// How many rows requested for the matrix. | |
// matrixColumn [int] | |
// How many columns requested for the matrix. | |
void AllocateMemory(int*** matrixArray, int matrixRow, int matrixColumn) | |
{ | |
// Initialization and Declarations | |
// ------------------------ | |
int i = 0; // Utilized for the 'for' loop; as we can not declare within the for-loop. | |
// ------------------------ | |
// Setup the initial memory space | |
*matrixArray = (int**)malloc(matrixRow * sizeof(int*)); | |
// Allocate the memory spaces within the matrix rows and columns. | |
for (i = 0; i < matrixRow; i++) | |
(*matrixArray)[i] = (int*)malloc(matrixColumn * sizeof(int)); | |
} // AllocateMemory() | |
// Deallocate Memory (Pointers) | |
// ==================================== | |
// This function is designed to thrash the memory locations | |
// previously initialized within the pointer array (Matrix). | |
// ---- | |
// Parameters: | |
// matrixArray [int***] | |
// The matrix in which is going to be deallocated | |
// matrixRow [int] | |
// How many rows this matrix contains. | |
void DeallocateMemory(int*** matrixArray, int matrixRow) | |
{ | |
// Initialization and Declarations | |
// ------------------------ | |
int i = 0; // Utilized for the 'for' loop; as we can not declare within the for-loop. | |
// ------------------------ | |
// Deallocate the memory spaces within the matrix's rows | |
for (i = 0; i < matrixRow; i++) | |
free((*matrixArray)[i]); | |
// Deallocate the initial memory space of the matrix. | |
free(*matrixArray); | |
matrixArray = NULL; | |
} // DeallocateMemory() | |
// Fetch Matrix Size | |
// ==================================== | |
// This function will allow the end-user to provide input in regards | |
// to the matrix size - either length or height. | |
// ---- | |
// Parameters: | |
// sizeType [Bool] | |
// true = Length [rows] | |
// false = Height [columns] | |
// ---- | |
// Output: | |
// int: | |
// returns a number that specifies the matrix size | |
// NOTE: This value is CHECKED against the max | |
// size possible for the matrix. | |
int FetchMatrixSize(bool sizeType) | |
{ | |
// Declaration and Initializations | |
// ------------------------ | |
char sizeChoiceRaw[_MATRIX_MAX_SIZE_]; // This will be used to capture user input - unfiltered. | |
int sizeChoice = 0; // This variable will hold the user's size choice - filtered | |
bool badInput = true; // This will be used to determine if the input was valid. | |
// ------------------------ | |
do | |
{ | |
// Provide instructions to the end-user | |
// Output Formatting; this may seem weird | |
printf("Please specify the matrix "); | |
// Length [Row] | |
if (sizeType) | |
printf("length "); | |
// Height [column] | |
else | |
printf("height "); | |
printf("size:\n"); | |
// ---- | |
// Capture the input from the end-user | |
printf(">>>>>> "); | |
fgets (sizeChoiceRaw, sizeof(sizeChoiceRaw), stdin); // Fetch the input | |
sscanf(sizeChoiceRaw, "%d", &sizeChoice); // Filter the input | |
// If non-int values exists | |
// then this will return '0' or 'EOL'. | |
// If a number is given before non-int's | |
// then the number will be captured - anything | |
// after will be dropped. | |
// Example: 32d2 | |
// Saved: 32 | |
// Dropped: d2 | |
// Check the input to make sure that it is valid | |
if ((sizeChoice > 1) && (sizeChoice < (_MATRIX_MAX_SIZE_ + 1))) | |
// Valid input | |
badInput = false; | |
else | |
// Invalid input | |
printf("The size of [ %d ] is not valid! Try again\n\n", sizeChoice); | |
} while (badInput); | |
return (int)sizeChoice; // Return the choice; casting for assurance sakes | |
} // int FetchMatrixSize() | |
// Fetch Number | |
// ==================================== | |
// This function will retrieve a number from the end-user | |
// and send it back to the calling function. | |
// NOTE: This function uses scanf; if '0' is returned - then | |
// '0' will be used, even if it was accidental by user. For instance, | |
// instead of a number the user inputs a char, from there scanf() | |
// will use '0'. | |
// ---- | |
// Output: | |
// int | |
// Provides any number to the calling function. | |
int FetchNumber() | |
{ | |
// Declaration and Initializations | |
// ------------------------ | |
char sizeChoiceRaw[_MATRIX_MAX_SIZE_]; // This will be used to capture user input - unfiltered. | |
int numData; // This variable will hold the user's size choice - filtered | |
// ------------------------ | |
// Capture the input from the end-user | |
printf(">>>>>> "); | |
fgets (sizeChoiceRaw, sizeof(sizeChoiceRaw), stdin); // Fetch the input | |
sscanf(sizeChoiceRaw, "%d", &numData); // Filter the input | |
// If non-int values exists | |
// then this will return '0' or 'EOL'. | |
// If a number is given before non-int's | |
// then the number will be captured - anything | |
// after will be dropped. | |
// Example: 32d2 | |
// Saved: 32 | |
// Dropped: d2 | |
return (int)numData; // Casting for assurance sakes | |
} // FetchNumber() | |
// Run Again Question | |
// ==================================== | |
// This function is dedicated into asking the end-user if they want | |
// to terminate the program or run again. | |
// ---- | |
// Output: | |
// char | |
// Returns only 'one' character of any value directly from the user. | |
char RunAgainQuestion() | |
{ | |
// Declaration and Initializations | |
// ------------------------ | |
char choice; // Used for capturing STDIN from the end-user [keyboard] | |
bool badInput = true; // Make sure that the input is valid | |
// ------------------------ | |
do | |
{ | |
printf("Solve another matrix?\n"); | |
printf("\t[Y]es OR [N]o\n"); | |
printf(">>>>>> "); | |
choice = getchar(); | |
getchar(); // Get rid of the 'enter key ghosting'. | |
// Because the enter key is STILL in STDIN. | |
if ((tolower(choice) != 'y') && (tolower(choice) != 'n')) | |
// Bad input | |
printf("Input of [ %c ] was invalid!\n\n", choice); | |
else | |
// Valid input | |
badInput = false; | |
} while (badInput); | |
return choice; | |
} // RunAgainQuestion() | |
// Draw Header | |
// ==================================== | |
// This function is designed to provide a header. | |
void DrawHeader() | |
{ | |
printf("%s - Version: %s\n", _NAME_, _VERSION_); | |
printf("--------------------------------------------\n\n"); | |
} // DrawHeader() | |
// Draw Instructions() | |
// ==================================== | |
// This function will provide instructions to the end-user, along with how | |
// this program works. | |
void DrawInstructions() | |
{ | |
printf("Instructions\n"); | |
printf("----------------\n"); | |
printf("This program will take two matrices and multiply them for you.\nHowever, this program will work with threads to accomplish this specific task.\n"); | |
printf("You will be asked to provide the following information: Matrix size by length and height, and lastly - the values within the vertices's.\n"); | |
printf("======================================\n"); | |
printf("\n\n"); | |
} // DrawInstructions() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment