Logical Argument Truth Table Generator

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

Leave a Reply

Your email address will not be published. Required fields are marked *