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";
}
////////////////////////////////////////////////////////////////////////////////