For a discrete mathematics lab, I was required to submit a program that would generate a truth table given two statements and determine it’s validity; if not valid, it will indicate which columns are incorrect.
Part of the prerequisite (for simplicity) was hardcoding in the premise and conclusion; this is done by changing the boolean statements in the corresponding methods.
The proper overloadeded method is determined by the use of the macro variableCount.
//////////////////////////////////////////////////////////////////////////////// #include <iostream> #include <vector> //////////////////////////////////////////////////////////////////////////////// // Replace with your conclusion, and your premise #define yourConclusion "((P v Q) ^ (Q -> R) XOR (P ^ R)) (R ^ Q)" #define yourPremise "(P v R)" /* Replace with the number of variables used in premise or conclusion, * whichever is greater. */ #define variableCount 3 //////////////////////////////////////////////////////////////////////////////// class Table { // Used for modeling individual columns of the truth table struct Column { std::string statement; // A vector of boolean values representing the column downwards std::vector truthList; Column(std::string passedStatement) { this->statement = passedStatement; } }; private: std::vector<Column*> Columns; public: /* The constructor initializes the table, given hardcoded premise * and conclusion, and the macro definitions above */ Table(); ~Table(); // Overloaded for different variable counts bool premiseCalc(bool P); bool premiseCalc(bool P, bool Q); bool premiseCalc(bool P, bool Q, bool R); bool conclusionCalc(bool P); bool conclusionCalc(bool P, bool Q); bool conclusionCalc(bool P, bool Q, bool R); // Prints the table, formatted void printTable(void); // Wrapped biconditional and conditional operators bool biconditional(bool leftValue, bool rightValue); bool conditional(bool leftValue, bool rightValue); std::string convertToText(bool passedBool); }; //////////////////////////////////////////////////////////////////////////////// int main(void) { std::cout << "Premise: " << yourPremise; std::cout << "\nConclusion: " << yourConclusion << "\n"; Table *theTable = new Table(); theTable->printTable(); delete theTable; return 0; } //////////////////////////////////////////////////////////////////////////////// /* * Replace with whatever premise you would like to "hardcode" in, in the * overloaded function with the number of arguments matching variableCount. * Adjust variableCount to match number of variables used if greater than the * number used in the conclusion. */ //////////////////////////////////////////////////////////////////////////////// bool Table::premiseCalc(bool P) { return P; } bool Table::premiseCalc(bool P, bool Q) { return (P ^ Q); } bool Table::premiseCalc(bool P, bool Q, bool R) { return biconditional(((P || Q) && (conditional(Q, R)) ^ (P && R)), (R & Q)); } //////////////////////////////////////////////////////////////////////////////// /* * Replace with whatever conclusion you would like to "hardcode" * in, in the overloaded function with the number of arguments matching * variableCount. Adjust variableCount to match number of variables used * if greater than the number used in the premise. */ //////////////////////////////////////////////////////////////////////////////// bool Table::conclusionCalc(bool P) { return P; } bool Table::conclusionCalc(bool P, bool Q) { return (P || Q) && (!(P && Q)); } bool Table::conclusionCalc(bool P, bool Q, bool R) { return (P || R); } //////////////////////////////////////////////////////////////////////////////// // The biconditional is easily represented in C++ as the == equality operator //////////////////////////////////////////////////////////////////////////////// bool Table::biconditional(bool leftValue, bool rightValue) { return (leftValue == rightValue); } //////////////////////////////////////////////////////////////////////////////// /* The conditional is repreesented as a ternary conditional operator, wherein * if the left value is 0, or the right value is 1, the value returned is 1. * Else, it returns 0. */ //////////////////////////////////////////////////////////////////////////////// bool Table::conditional(bool leftValue, bool rightValue) { return ((!leftValue || rightValue) ? 1 : 0); } //////////////////////////////////////////////////////////////////////////////// Table::Table() { std::string premise = yourPremise; std::string conclusion = yourConclusion; // If there is at least one variable used if(variableCount >= 1) { // Prepare the first column this->Columns.push_back(new Column("P")); this->Columns[0]->truthList.push_back(true); this->Columns[0]->truthList.push_back (false); // If only one variable is used, finish fleshing out table if(variableCount == 1) { this->Columns.push_back(new Column(premise)); this->Columns.push_back(new Column(conclusion)); for(int i = 1; i <= 2; i++) { if(i == 1) { // Push back premise results using P for(int j = 0; j <= 1; j++) { this->Columns[i]->truthList.push_back( premiseCalc(this->Columns[0]->truthList[j])); } } else { // Push back conclusion results using P for(int j = 0; j <= 1; j++) { this->Columns[i]->truthList.push_back( conclusionCalc(this->Columns[0]->truthList[j])); } } } } } // If there are at least two variables if(variableCount >= 2) { // Prepare the second column, push two more values onto [1] to make 4 this->Columns.push_back(new Column("Q")); this->Columns[0]->truthList.push_back(true); this->Columns[0]->truthList.push_back(false); this->Columns[1]->truthList.push_back(true); this->Columns[1]->truthList.push_back(false); this->Columns[1]->truthList.push_back(false); this->Columns[1]->truthList.push_back(true); // If only two variables are used, finish fleshing out the table if(variableCount == 2) { this->Columns.push_back(new Column(premise)); this->Columns.push_back(new Column(conclusion)); for(int i = 2; i <= 3; i++) { if(i == 2) { for(int j = 0; j <= 3; j++) { this->Columns[i]->truthList.push_back( premiseCalc(this->Columns[0]->truthList[j], this->Columns[1]->truthList[j])); } } else { for(int j = 0; j <= 3; j++) { this->Columns[i]->truthList.push_back( conclusionCalc(this->Columns[0]->truthList[j], this->Columns[1]->truthList[j])); } } } } } // If there are three variables used if(variableCount == 3) { // Set up R, and Premise/Conc since we know one has at least 3 this->Columns.push_back(new Column("R")); this->Columns.push_back(new Column(premise)); this->Columns.push_back(new Column(conclusion)); // Fill columns with values this->Columns[2]->truthList.push_back(true); this->Columns[2]->truthList.push_back(true); this->Columns[2]->truthList.push_back(true); this->Columns[2]->truthList.push_back(true); this->Columns[2]->truthList.push_back(false); this->Columns[2]->truthList.push_back(false); this->Columns[2]->truthList.push_back(false); this->Columns[2]->truthList.push_back(false); this->Columns[0]->truthList.push_back(true); this->Columns[0]->truthList.push_back(false); this->Columns[0]->truthList.push_back(true); this->Columns[0]->truthList.push_back(false); this->Columns[1]->truthList.push_back(true); this->Columns[1]->truthList.push_back(false); this->Columns[1]->truthList.push_back(false); this->Columns[1]->truthList.push_back(true); // Solve premise and conclusion for(int i = 3; i <= 4; i++) { if(i == 3) { for(int j = 0; j < 8; j++) { this->Columns[i]->truthList.push_back( premiseCalc(this->Columns[0]->truthList[j], this->Columns[1]->truthList[j], this->Columns[2]->truthList[j])); } } else { for(int j = 0; j < 8; j++) { this->Columns[i]->truthList.push_back( conclusionCalc(this->Columns[0]->truthList[j], this->Columns[1]->truthList[j], this->Columns[2]->truthList[j])); } } } } return; } //////////////////////////////////////////////////////////////////////////////// Table::~Table() { // Iterate through the columns, deleting for(auto it : this->Columns) { delete it; } return; } //////////////////////////////////////////////////////////////////////////////// void Table::printTable(void) { auto it = Columns.begin(); // Used to mark row advancement int index = 0; // Holds the statements validity bool validity = true; // Output the statements at the top of the table while(it != Columns.end()) { std::cout << "| " << (*(it))->statement << " |"; ++it; } // Linefeed std::cout << "\n"; it = Columns.begin(); // While it is less than 2^(n-1), or the number of rows while(index < (2 << (variableCount - 1))) { if( (*(it))->statement.length() == 1) { std::cout << "| " << convertToText((*(it))->truthList[index]) << " |"; ++it; } else { // Attempt at formatting to fit statement lengths std::cout << "| "; for(int i = 0; i < ((*(it))->statement.length()/2); i++) { std::cout << " "; } // ConvertToText turns bool into T or F std::cout << convertToText((*(it))->truthList[index]); for(int i = 0; i < ((*(it))->statement.length()/2); i++) { std::cout << " "; } std::cout << " |"; ++it; } // If at end of column, advance line if(it == Columns.end()) { index++; std::cout << std::endl; it = Columns.begin(); } } // Set concIt to the start of the conclusions bool list auto concIt = Columns[variableCount + 1]->truthList.begin(); // Iterate through the premises bool list for(auto premIt : Columns[variableCount]->truthList) { // If the current conclusion and premise values don't match if(premIt && !(*(concIt))) { // Output distance from current iterator to start of the bool vec std::cout << "\nStatement is invalid, as per line " << (std::distance(Columns[variableCount + 1]-> truthList.begin(), concIt)+1); // Mark statement false validity = false; } // increment conclusion iterator to be cohesive with premIt ++concIt; } // If the flag was not thrown, we know it is valid if(validity) { std::cout << std::endl << "Statement is valid"; } return; } //////////////////////////////////////////////////////////////////////////////// std::string Table::convertToText(bool passedBool) { return passedBool ? "T" : "F"; } ////////////////////////////////////////////////////////////////////////////////