## DBsubject() ## DBchapter() ## DBsection() ## Date(2024-07-15) ## Institution(University of Lethbridge) ## Author(Olivia Henders & Nicole Wilson) ## MO(1) ## KEYWORDS('boolean expressions', 'minterms', 'maxterms', 'SOP', 'POS', 'logic operators', 'digital logic') ########################### # Initialization # The first line in the .pg file after any opening comments. # Defines the bounds of the document. DOCUMENT(); # Contains a comma-separated list of macro filename strings. # functions being used in the problem. loadMacros( # REQUIRED: Used for basic question and answer operations. "PGstandard.pl", # Required for proper text formatting. "PGML.pl", "PGcourse.pl", # REQUIRED: to implement checkboxes "scaffold.pl", "parserCheckboxList.pl", "parserPopUp.pl", "answerHints.pl", ); # INSTRUCTIONS INSTRUCTIONS INSTRUCTIONS INSTRUCTIONS INSTRUCTIONS # ================================================================ # Only edit between the #-ULETH-# and #-END-ULETH-# tags, pay # attention the the instructions. # ================================================================ # INSTRUCTIONS INSTRUCTIONS INSTRUCTIONS INSTRUCTIONS INSTRUCTIONS ############################# # Initialize Question Details # In truth tables and kmaps entries may be 0, 1, or X (don't care) # In state tables entries may be 0, 1, X (don't care), or I (indeterminant). Context()->strings->add(0 => {}, 1 => {}, X => {}, I => {}); # Recognized operators and how they will be displayed %operator = ( not => "'", or => " + ", nor => "\text{ nor }", xor => " \oplus ", and => " \cdot ", nand => "\text{ nand }" ); #-ULETH-# # ================================================================ # ONE:---> input operands # Enter the input operands in display order. @inputs = ("A", "B", "C"); # ====================== # TWO:---> output operands # Enter the output operands in display order. @outputs = ("O_1", "O_2"); # ====================== # THREE:---> definitions of the output operands # Enter the postfix versions of the boolean expressions for the output # operands. # All input operands and operators must be comma delimited, each # boolean expression must have "end" after it. # only the operators listed above have been defined @boolExprPostFix = ( "A", "C", "or", "B", "C", "not", "or", "and", "end", "A", "not", "C", "not", "and", "B", "not", "C", "and", "or", "end" ); # ====================== # FOUR:----> Don't cares # For each output operand indicate the row that contains a don't care. # List the output operand in quotes, the comma delimited list of rows, # then "end". # The default is that this list is blank. @dontCareList = ("O_1", 0, "end", "O_2", 7, "end"); #@dontCareList = (); # ====================== # FIVE:----> Indeterminant # for each output operand indicate the row that contains an indeterminant result. # List the output operand in quotes, the comma delimited list of rows, # then "end". # The default is that this list is blank. #@indeterminantList = ("O_1", 7, "end", "O_2", 0, "end"); @indeterminantList = (); # ======================= # For each desired K-map enter the output operand and the 3 or 4 # input operands that should appear in the k-map. # List the output operand, the input operands, then "end" in a # comma delimited list. #@kmapList = ("O_1", "A", "B", "C", "O_2", "A", "B", "C"); # ================================================================ #-END-ULETH-# # Determine the number of inputs and outputs $numInputs = $#inputs + 1; $numOutputs = $#outputs + 1; ##################################################################### # Create bool expressions in infix format to display ##################################################################### @boolExpr = (); @postfix = @boolExprPostFix; for (my $i = 0; $i < $numOutputs; $i++) { @infix = (); $next = {}; push(@infix, (shift(@postfix))); while ($next ne "end") { $next = shift(@postfix); if ($next eq "not") { $next = "(" . pop(@infix) . $operator{$next} . ")"; push(@infix, $next); } elsif ($next eq "or" || $next eq "and" || $next eq "xor" || $next eq "nand" || $next eq "nor") { $next = $operator{$next} . pop(@infix) . ")"; $next = "(" . pop(@infix) . $next; push(@infix, $next); } elsif ($next eq "end") { last; } else { push(@infix, $next); } } $boolExpr[$i] = $infix[0]; $boolExpr[$i] = substr($boolExpr[$i], 1, length($boolExpr[$i]) - 2); } # Array containing latex with definitions of the outputs @displayExprArray = (); for (my $i = 0; $i < $numOutputs; $i++) { $displayExprArray[$i][0] = "\(" . $outputs[$i] . "\)"; $displayExprArray[$i][1] = " = "; $displayExprArray[$i][2] = "\(" . $boolExpr[$i] . "\)"; } ##################################################################### # Create a array with all data ##################################################################### # These values do not include the header row with the operands nor the # column with row numbers. $numRows = 2**$numInputs; $numCols = $numInputs + $numOutputs; # hash to find the column number for each operand. %columnRef = (); for (my $i = 0; $i < $numInputs; $i++) { $columnRef{ $inputs[$i] } = $i + 1; } for (my $i = $numInputs; $i < $numInputs + $numOutputs; $i++) { $columnRef{ $outputs[ $i - $numInputs ] } = $i + 1; } # Fill the complete bool array @boolArray = (); # Store row numbers $boolArray[0][0] = "\text{Row}"; for (my $i = 0; $i < $numRows; $i++) { $boolArray[ $i + 1 ][0] = $i; } # Store input headings for (my $i = 0; $i < $numInputs; $i++) { $boolArray[0][ $i + 1 ] = $inputs[$i]; } # Store output headings for (my $i = $numInputs; $i < $numInputs + $numOutputs; $i++) { $boolArray[0][ $i + 1 ] = $outputs[ $i - $numInputs ]; } # Store input values $change = $numRows / 2; for (my $c = 0; $c < $numInputs; $c++) { for (my $r = 0; $r < $numRows; $r++) { $boolArray[ $r + 1 ][ $c + 1 ] = int($r / $change) % 2; } $change = $change / 2; } # Calculate and store output values. @rightStack = (); @leftStack = (); for (my $r = 0; $r < $numRows; $r++) { @rightStack = @boolExprPostFix; @leftStack = (); for (my $c = 0; $c < $numOutputs; $c++) { $curr = shift(@rightStack); while ($curr ne "end") { if ($curr eq "not") { # unary operator $curr = pop(@leftStack); if ($curr eq "0") { push(@leftStack, "1"); } elsif ($curr eq "1") { push(@leftStack, "0"); } else # don't care, indeterminant, or error { push(@leftStack, $curr); } } elsif ($curr eq "or" || $curr eq "nor" || $curr eq "xor" || $curr eq "and" || $curr eq "nand") { # binary operator $op = $curr; $curr = pop(@leftStack); $prev = pop(@leftStack); if ($curr eq "I" || $prev eq "I") { push(@leftStack, "I"); } elsif ($curr eq "X" || $prev eq "X") { push(@leftStack, "X"); } elsif (($curr ne "0" && $curr ne "1") || ($prev ne "0" && $prev ne "1")) { push(@leftStack, "error"); } elsif ($op eq "or") { if ($curr eq "1" || $prev eq "1") { push(@leftStack, "1"); } else { push(@leftStack, "0"); } } elsif ($op eq "nor") { push(@leftStack, $prev); push(@leftStack, $curr); unshift(@rightStack, "not"); unshift(@rightStack, "or"); } elsif ($op eq "xor") { if ($prev ne $curr) { push(@leftStack, "1"); } else { push(@leftStack, "0"); } } elsif ($op eq "and") { if ($curr eq "0" || $prev eq "0") { push(@leftStack, "0"); } else { push(@leftStack, "1"); } } elsif ($op eq "nand") { push(@leftStack, $prev); push(@leftStack, $curr); unshift(@rightStack, "not"); unshift(@rightStack, "and"); } } elsif (exists($columnRef{$curr})) { # operand push(@leftStack, $boolArray[ $r + 1 ][ $columnRef{$curr} ]); } elsif ($curr ne "end") { # error handling push(@leftStack, "error"); } $curr = shift(@rightStack); } # while ($curr ne "end") $boolArray[ $r + 1 ][ $numInputs + $c + 1 ] = pop(@leftStack); } # for (my $c = 0; $c < $numOutputs; $c++) } # for (my $r = 0; $r < $numRows; $r++) while ($#dontCareList > -1) { $curr = shift(@dontCareList); $col = $columnRef{$curr}; $curr = shift(@dontCareList); while ($curr ne "end") { $boolArray[ $curr + 1 ][$col] = "X"; $curr = shift(@dontCareList); } } while ($#indeterminantList > -1) { $curr = shift(@indeterminantList); $col = $columnRef{$curr}; $curr = shift(@indeterminantList); while ($curr ne "end") { $boolArray[ $curr + 1 ][$col] = "I"; $curr = shift(@indeterminantList); } } ######################################################### # Make array with all data in bool array inside \(..\) @displayBoolArray = (); for (my $c = 0; $c <= $numCols; $c++) { for (my $r = 0; $r <= $numRows; $r++) { $displayBoolArray[$r][$c] = "\(" . $boolArray[$r][$c] . "\)"; } } ######################################################## # Make array with ans_rule in output columns @displayBoolWithAnsRuleArray = (); for (my $c = 0; $c <= $numCols; $c++) { for (my $r = 0; $r <= $numRows; $r++) { $displayBoolWithAnsRuleArray[$r][$c] = "\(" . $boolArray[$r][$c] . "\)"; } } for (my $c = $numInputs + 1; $c <= $numInputs + $numOutputs; $c++) { $displayBoolWithAnsRuleArray[0][$c] = "\(" . $boolArray[0][$c] . "\)"; for (my $r = 0; $r < $numRows; $r++) { $displayBoolWithAnsRuleArray[ $r + 1 ][$c] = ans_rule(1); } } ############################# # Problem Text #-ULETH-# Scaffold::Begin(); $showPartialCorrectAnswers = 0; Section::Begin('Instructions', is_open => "always"); BEGIN_PGML Answer the questions in each section then select the Preview Answers button at the bottom of the page. * If your answers are correct then the next section will open. * If your answers are incorrect then the next section will not open. END_PGML Section::End(); Section::Begin( 'Complete the truth table', can_open => "when_previous_correct", is_open => "correct_or_first_incorrect" ); $displayExprTable = DataTable(~~@displayExprArray); $displayBoolWithAnsRuleTable = DataTable(~~@displayBoolWithAnsRuleArray); $displayCompleteTable = DataTable(~~@displayBoolArray); ################################################# # Hint table for boolean operators $boolOperatorsHintTable = $BCENTER . begintable(8) . row( "\(I_0\)", "\(I_1\)", "\(I_0' \)", "\(I_0 \cdot I_1\)", "\(I_0 + I_1\)", "\(I_0 \text{ nand } I_1\)", "\(I_0 \text{ nor } I_1\)", "\(I_0 \oplus I_1\)", ) . row( "\(0\)", "\(0\)", "\(1\)", "\(0\)", "\(0\)", "\(1\)", "\(1\)", "\(0\)", ) . row( "\(0\)", "\(1\)", "\(1\)", "\(0\)", "\(1\)", "\(1\)", "\(0\)", "\(1\)", ) . row( "\(1\)", "\(0\)", "\(0\)", "\(0\)", "\(1\)", "\(1\)", "\(0\)", "\(1\)", ) . row( "\(1\)", "\(1\)", "\(0\)", "\(1\)", "\(1\)", "\(0\)", "\(0\)", "\(0\)", ) . endtable() . $ECENTER; BEGIN_PGML Given that [@ $displayExprString @]*** or for better display [@ $displayExprTable @]*** Complete the following truth table [@ $displayBoolWithAnsRuleTable @]*** END_PGML BEGIN_PGML_HINT Recall: [@ $boolOperatorsHintTable @]*** * The and operation only produces a [`1`] when both operands are [`1`]. So, in every row that has an operand set to [`0`] the output is [`0`] and all the rest are [`1`]. * The or operation only produces a [`0`] when both operands are [`0`]. So, in every row that has an operand set to [`1`] the output is [`1`] and all the rest are [`0`]. * The nand operation only produces a [`0`] when both operands are [`1`]. So, in every row that has an operand set to [`1`] the output is [`0`] and all the rest are [`1`]. * The nor operation only produces a [`1`] when both operands are [`0`]. So, in every row that has an operand set to [`0`] the output is [`1`] and all the rest are [`0`]. * The xor, exculsive or, operation only produces a [`0`] when both operands have the same value. So, in every row that has matching operands the output is [`0`] and all the rest are [`1`]. END_PGML_HINT ############################################## # Answer Evaluation for (my $r = $numInputs; $r < $numInputs + $numOutputs; $r++) { for (my $c = 0; $c < $numRows; $c++) { ANS(Compute($boolArray[$r][$c])->cmp()); } } Section::End(); # Sections temporarily removed and/or under development # The code above problem text only needed for these sections # has been temporarily removed. # - Find Sum of Products (temporarily removed) # - Find Product of Sums (temporarily removed) # - Find minterms and don't care terms (temporarily removed) # - Find maxterms and don't care terms (temporarily removed) # - complete kmaps (needed by 2025-02) # - complete wiring diagram (future development) # - enter test values (temporarily removed) # - complete state diagram (future development) # - complete timing diagram (future development) #Section::Begin('template', # can_open => "when_previous_correct", # is_open => "correct_or_first_incorrect" #); #BEGIN_PGML #END_PGML #BEGIN_PGML_HINT #END_PGML_HINT #Section::End(); Scaffold::End(); BEGIN_PGML_SOLUTION Completed truth table: [@ $displayCompleteTable @]*** END_PGML_SOLUTION # Marks the end of the problem document. ENDDOCUMENT();