3
\$\begingroup\$

The program is supposed perform discrete mathematics operations on a number of conjunctive statements (see lines 34 - 50). Currently I just have it so they print out the tables in 0's and 1's, but I'll be adding a compare functionality shortly.

Even though I'm sure this work leaves much to be desired I'm currently worried that about the repetition on lines 78 - 79 as the only unique part is the expression itself while the if else part isn't or never will be unique.

What can I do to condense?

# Module is created to allow the user to easily select their expression,$      
# prints the output and test it to be confident it works.$                     
import itertools, sys$                                                         
$                                                                              
def setup_table(variables=2):$                                                 
    ''' setup_table prints out all possibilities of a truth_table based on-$  
    the amount of variables passed to it'''$                                   
    return (list(itertools.product(range(2), repeat = variables)))$            
$                                                                              
def printer(truth_table):$                                                     
    '''printer simply outputs the truth_table in a easier to read way'''$      
    selection = input('print to the command line? (yes/no): ')$                
    if selection == 'yes':-$                                                   
        for table in truth_table:$                                             
            print(table)$                                                      
    else: return truth_table$                                                  
--------$                                                                      
def expression_menu():$                                                        
    ''' expression menu offers the user a selection of expressions to evulate'''$
    expression = int(input('''$                                                
    choose your expression(s)$                                                 
    A single expression will print out the truth table$                        
    selecting two expressions will print both and compare:$                    
$                                                                              
    **************************************************$                        
    Whew look at that list! do you really want to type all that in?$           
    Type EVALALL in order to compare them all$                                 
$                                                                              
    1. ((p and q) or (p or q)) and not(r or not q)$                            
    2. (p or r) or (q and s)$                                                  
    3. (p or r) and ( q or (p and s))$                                         
    4. not (p and q)$                                                          
    5. not (p or q)$                                                           
    6. p -> q$                                                                 
    7. (not p) -> (not q)$                                                     
    8. p or ( q and r)-$                                                       
    9. (not p) and (not q)$                                                    
    10. (not p) or (not q)$                                                    
    11. (not p) or q$                                                          
    12. p and (not q)$                                                         
    13. (p or q) and (p or r)$                                                 
----$                                                                          
    BETA (type in your own!)$                                                  
----$                                                                          
    **************************************************$                        
    expression: '''))$                                                         
   #TODO: this is not a good way to do this.., watch your inputs!.$            
    if expression == 1: variables = 3$                                         
    elif expression == 2: variables = 4$                                       
    elif expression == 3: variables = 4$              
    elif expression == 4:$                                                     
    elif express$                                                              
        print '''Type in your own is still under contruction'''$               
        sys.exit()$                                                            
--------$                                                                      
$                                                                              
    return truth(expression,variables)$                                        
$                                                                              
def truth(expression, variables):$                                             
    ''' truth evulates the expression selected in expression_menu using$       
    the table built in setup_table and the boolean logic contained below'''$   
    truth_table = []$                                                          
$                                                                              
----$                                                                          
    for line in setup_table(variables):$                                       
        # all this mess is to get them so their the same type! TODO: type conv$
        str_line = ''$                                                         
        for number in line:$                                                   
            str_num = str(number)$                                             
            str_line += str_num + ' '$                                         
        # add your expressions here!$                                          
        # TODO: there has to be a way to streamline these expressions, if,else$
        if expression == 1:$                                                   
            if (((line[0] and line[1]) or (line[0] or line[1])) and not (line[2] or not line[1]))>
                str_line += '1'$                                               
            else:$                                                             
                str_line += '0'$                                               
$                                                                              
            truth_table.append(str_line)$                                      
        elif expression == 2:$                                                 
            if (line[0] or line[2]) or ( line[1] and line[3]):$                
                str_line += '1'$                                               
            else:$                                                             
                str_line += '0'$                                               
$
            truth_table.append(str_line)$                                      
        elif expression == 3:$                                                 
            if (line[0] or line[2]) and (line[1] or (line[0] and line[3])):$   
                str_line += '1'$                                               
            else:$                                                             
                str_line += '0'$                                               
        elif expressoin == 4:$                                                 
$                                                                              
            truth_table.append(str_line)$                                      
# un comment printer to have print to comman line.$                            
    #printer(truth_table)-$                                                    
    return truth_table$                                                                           
$                                                                              
def selection():$                                                              
    selection = raw_input('choose another expression? (yes/no)')$
    if selection == 'yes':$                                                    
        return expression_menu()$                                              
    else: sys.exit()$                                                          
---$                                                                           
if __name__ == '__main__':$                                                    
    expression_menu()$
\$\endgroup\$
1
  • 2
    \$\begingroup\$ If there's repetition, you need to show more of it so we can get an idea of how it repeats. And while you're at it, explain to us what this code is used for. It looks like you're doing some boolean logic here and some K-maps could help. \$\endgroup\$ May 16, 2012 at 0:31

2 Answers 2

5
\$\begingroup\$
# Module is created to allow the user to easily select their expression,      
# prints the output and test it to be confident it works.                     
import itertools, sys                                                         

def setup_table(variables=2):                                   

setup isn't really helpful in understanding this function. Normally, we'd use create. It might be a good idea to give a longer description as well.

    ''' setup_table prints out all possibilities of a truth_table based on-  
    the amount of variables passed to it'''                                   
    return (list(itertools.product(range(2), repeat = variables))) 

You don't need the parens around this expression

def printer(truth_table):                                                     
    '''printer simply outputs the truth_table in a easier to read way'''      
    selection = input('print to the command line? (yes/no): ')           

The command line is where you enter commands, here you are printing to standard output or the terminal

    if selection == 'yes':                                                   
        for table in truth_table:                                             

A truth table doesn't contain multiple tables, so this variable shouldn't be called table

            print(table)                                                      
    else: return truth_table

Why in the world you want to return the truth_table here? A calling function can't really make use of it because it doesn't get returned consistently, and the calling function already has the table anyways

def expression_menu():                                                        
    ''' expression menu offers the user a selection of expressions to evulate'''
    expression = int(input('''                                                
    choose your expression(s)                                                 
    A single expression will print out the truth table                        
    selecting two expressions will print both and compare:                    

    **************************************************                        
    Whew look at that list! do you really want to type all that in?           
    Type EVALALL in order to compare them all                                 

    1. ((p and q) or (p or q)) and not(r or not q)                            
    2. (p or r) or (q and s)                                                  
    3. (p or r) and ( q or (p and s))                                         
    4. not (p and q)                                                          
    5. not (p or q)                                                           
    6. p -> q                                                                 
    7. (not p) -> (not q)                                                     
    8. p or ( q and r)-                                                       
    9. (not p) and (not q)                                                    
    10. (not p) or (not q)                                                    
    11. (not p) or q                                                          
    12. p and (not q)                                                         
    13. (p or q) and (p or r)                                                 
    BETA (type in your own!)                                                  
    **************************************************                        
    expression: '''))       

For crazy long strings, I recommend putting them global constants so as not the interrupt your flow

   #TODO: this is not a good way to do this.., watch your inputs!.            
    if expression == 1: variables = 3                                         
    elif expression == 2: variables = 4                                       
    elif expression == 3: variables = 4              
    elif expression == 4:                                                     
    elif express    

This syntax is invalid, I assume it got messed up in the same way your got $ thrown all over it

        print '''Type in your own is still under contruction'''               
        sys.exit()                                                            

    return truth(expression,variables)                                        

def truth(expression, variables):                                             
    ''' truth evulates the expression selected in expression_menu using       
    the table built in setup_table and the boolean logic contained below'''   
    truth_table = []                                                          

    for line in setup_table(variables):                                       
        # all this mess is to get them so their the same type! TODO: type conv
        str_line = ''                                                         
        for number in line:                                                   
            str_num = str(number)                                             
            str_line += str_num + ' ' 

This loop can be written as str_line = ' '.join(map(str, line)) + ' '

        # add your expressions here!                                          
        # TODO: there has to be a way to streamline these expressions, if,else
        if expression == 1:                                                   
            if (((line[0] and line[1]) or (line[0] or line[1])) and not (line[2] or not line[1])):

You don't need the outer parens

                str_line += '1'                                               
            else:                                                             
                str_line += '0'                                               

Adding strings is expensive. Instead, putting everything in a list and then convert that into a string using ' '.join

            truth_table.append(str_line)                                      
        elif expression == 2:                                                 
            if (line[0] or line[2]) or ( line[1] and line[3]):                
                str_line += '1'                                               
            else:                                                             
                str_line += '0'                                               

            truth_table.append(str_line)                                      
        elif expression == 3:                                                 
            if (line[0] or line[2]) and (line[1] or (line[0] and line[3])):   
                str_line += '1'                                               
            else:                                                             
                str_line += '0'                                               
        elif expressoin == 4:                                                 

            truth_table.append(str_line)                                      

Yes, that's some annoying duplication. I'll talk about what to do about it at the end

    # un comment printer to have print to comman line.                            
    #printer(truth_table)-                                                    
    return truth_table                                                                           

def selection():                                                              
    selection = raw_input('choose another expression? (yes/no)')
    if selection == 'yes':                                                    
        return expression_menu()

Don't return things unless your caller need them

    else: sys.exit()                   

You should only really use sys.exit() if the program has an error or something. Otherwise, just let your code return.

if __name__ == '__main__':                                                    
    expression_menu()    

In order to solve your repetition, you need to store the expression as data not code. Basically you need some classes like:

class Variable(object):
    def __init__(self, number):
        self.number = number

class And(object):
    def __init__(self, left, right):
         self.left = left
         self.right = right

class Or(object):
    def __init__(self, left, right):
         self.left = left
         self.right = right

class Not(object):
    def __init__(self, expression):
         self.expression = expression

Then you should have a list of your expressions

P = Variable(0)
Q = Variable(1)
R = Variable(2)
EXPRESSIONS = [
    And(Or(And(P,Q),Or(P,Q)),Not(Or(R,Not(q)))),
    ...
]

Then you should be able to write methods to do things like:

  • Convert the expression to a string
  • Evaluate the truth values of the expression
  • Count the number of variables in the expression

If you do that, you should only have to define your expression in exactly one place. So your printing out function should end up looking something like

def truth(expression):
    variable_table = setup_table( expression.count_variables() )
    truth_table = []
    for line in variable_table:
        value = expression.evaluate(line)
        truth_table.append( ' '.join(line + [value]) )
    return truth_table
\$\endgroup\$
2
  • \$\begingroup\$ If you need an idea of how to dynamically parse expressions and create executable trees, you might want to check out the following: code.activestate.com/recipes/577469 \$\endgroup\$ May 18, 2012 at 18:47
  • 2
    \$\begingroup\$ What a wonderfully detailed review! i wish i could somehow reward you beyond a simple checkmark \$\endgroup\$ May 19, 2012 at 7:30
1
\$\begingroup\$

I don't know if you are generating the conditions or if they will just be in your code. If you have to write them all out, you can at least factor the logic out in a function. If you can generate the conditions, use a loop within my_function, then you only have to call it once.

I haven't tested this, but something like this should work.

elif expression == 3 :

    ( line, str_line ) += my_function( (line[0] or line[2])  and  (  line[1] or (line[0] and line[3]) ) )
    ( line, str_line ) += my_function( (line[1] or line[2])  and  (  line[1] or (line[0] and line[3]) ) )
    ( line, str_line ) += my_function( (line[2] or line[2])  and  (  line[1] or (line[0] and line[3]) ) )

end

....

def my_function( condition ) :
    line = str_line = ''

    if( condition )

       line += '1'                                               

    else:                                                             

       str_line += '0'

    return ( line, str_line )
end
\$\endgroup\$
2
  • \$\begingroup\$ isn't line[0] line[2], etc... going to be undefined? \$\endgroup\$ May 16, 2012 at 3:04
  • \$\begingroup\$ line is not being sent into the function, only the result of the boolean expression which gets evaluated in the outer scope. What I didn't look up is how python evaluates such expressions outside an if statement, but I assume that the 'and' and 'or' operators cause it to be a boolean. \$\endgroup\$
    – user13328
    May 16, 2012 at 3:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.