├── .github └── workflows │ └── python.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── getting_started.md ├── installing.md └── structure.md ├── images └── menu.png ├── requirements.txt └── src ├── cli ├── main.py └── truth_table.py ├── data ├── __init__.py ├── decode.py └── encode.py ├── entity ├── __init__.py ├── base.py ├── node.py ├── operators.py └── quantifiers.py ├── tablos └── tablo.py ├── tests ├── __init__.py └── data │ ├── __init__.py │ ├── test_decode.py │ └── test_encode.py └── truth_table └── table.py /.github/workflows/python.yml: -------------------------------------------------------------------------------- 1 | name: Python 2 | 3 | on: [ push, pull_request ] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | build: 10 | runs-on: ${{ matrix.os }} 11 | strategy: 12 | matrix: 13 | os: [windows-latest, ubuntu-latest, macos-latest] 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Set up Python 18 | uses: actions/setup-python@v3 19 | with: 20 | python-version: "3.12" 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install -r requirements.txt 25 | - name: Test with unittest 26 | run: | 27 | python -m unittest discover -s src/tests 28 | - name: Generate Artifacts 29 | run: pyinstaller --onefile src/cli/main.py -p . 30 | - name: Archive Artifacts 31 | uses: actions/upload-artifact@v4 32 | with: 33 | name: predimate-${{ matrix.os }} 34 | path: ./dist -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | **/__pycache__ 3 | **/.pytest_cache 4 | dist 5 | build 6 | *.spec -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |
Welcome to the contributing section! We are thrilled that you want to contribute to the platform. Here are some ways you can get started:
3 | 4 |This guide provides step-by-step instructions to set up and run the Predimate platform on your local machine. It covers the prerequisites, compiling the project, and running it. By following this guide, you can have Predimate up and running in no time!
6 | 7 |To maintain a clean and organized version history, we follow conventional commit messages. When contributing to Predimate, please ensure that your commit messages adhere to the conventions. This will help us understand the purpose of each change and ensure smooth collaboration within the community.
9 | 10 |If you encounter any bugs while using our platform, please report them on our GitHub repository. Feel free to create an issue describing the problem you encountered. If you have the expertise and want to fix the bug yourself, we gladly accept pull requests.
12 | 13 |Do you have an idea for a new feature that would enhance Predimate? We would love to hear it! Create a new issue on GitHub to propose your idea, and let's discuss it together. If you're up for the challenge, feel free to implement the new feature and submit a pull request.
15 | 16 |Clear and comprehensive documentation is vital for any project. If you find areas in the existing documentation that can be improved or have ideas for new documentation, please let us know. You can contribute to the project by creating or updating documentation and submitting a pull request.
18 | 19 |Robust testing ensures the reliability and stability. If you have experience with testing or want to learn more about it, you can contribute by writing and improving test cases.
21 | 22 |As Predimate evolves, there may be opportunities to improve the existing codebase. Whether it's refactoring for better readability, optimizing performance, or enhancing code organization, your contributions can help make Predimate better.
24 | 25 |26 | Remember that contributing to an open-source project is a collaborative effort. We appreciate all contributions, regardless of size or scope. 27 |-------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc.
4 |
5 |
6 |
9 | The "Predimate" algorithm, created during the second semester at Ulbra by me, is a specialized tool designed to guide students through propositional logic problems step by step, enhancing their learning experience. It simplifies complex logic challenges into manageable steps, promoting a deeper understanding of the subject and improving logical reasoning skills. Predimate is a valuable educational resource for both students and educators, facilitating the acquisition of essential logical skills. 10 |
11 | 12 |If you simply want to run Predimate without building it from source, follow the steps listed in installing docs.
14 | 15 |For detailed information on how to contribute, please refer to our Contribution Guide. It covers everything you need to know about making contributions to Predimate. Happy contributing! 🚀
17 | 18 || Operator | 22 |Name | 23 |
|---|---|
| ^ | 26 |Conjunction | 27 |
| ∧ | 30 |Conjunction | 31 |
| v | 34 |Disjunction | 35 |
| ∨ | 38 |Disjunction | 39 |
| -> | 42 |Conditional | 43 |
| → | 46 |Conditional | 47 |
| <-> | 50 |Biconditional | 51 |
| ↔ | 54 |Biconditional | 55 |
| ¬ | 58 |Negation | 59 |
| ~ | 62 |Negation | 63 |
--------------------------------------------------------------------------------
/docs/getting_started.md:
--------------------------------------------------------------------------------
1 | Welcome to the "Getting Started" guide for our project! This section will walk you through the necessary steps to set up the project on both Linux and Windows operating systems.
3 |Before we start, let's make sure you have the necessary prerequisites installed for setting up the project on your system. Please ensure you have the following tools and dependencies ready:
5 |14 | If you are on linux, most of these dependencies are available in your distro's package manager, just install them via command line. 15 |
16 |Cloning the repository with git and navigate to the project:
18 |git clone https://github.com/baskerbyte/predimate.git
19 | cd predimate
20 |
21 | Now that you have compiled the project, you can run it using the following step:
23 |python src/main.py
24 | To get Predimate up and running on your system, follow these simple steps:
4 | 5 |That's it! You've successfully installed Predimate. -------------------------------------------------------------------------------- /docs/structure.md: -------------------------------------------------------------------------------- 1 |
Welcome to the Predimate project workspace! This workspace is organized into several key directories, each serving a specific purpose to facilitate the development of the platform. Here's a brief description of each directory:
3 |data - Responsible for transforming input strings into manipulatable data structures, interpreting logical formulas provided by the user.
6 | derived - Solves logical formulas using the derived method, inferring conclusions based on given premises.
9 | entity - Represents entities and objects relevant to the Predimate algorithm, handling the definition and management of logical entities.
12 | inferences - Resolves logical formulas using various inference methods, applying inference rules to deduce conclusions from premises.
15 | tablos - Validates logical formulas using the tree of refutation (tabular method) approach, assessing the validity of logical expressions.
18 | tests - Contains unit tests and test cases for the Predimate algorithm, ensuring the correctness and reliability of its functionalities through comprehensive testing.
21 | truth_table - Validates logical formulas using truth tables, constructing tables to determine the validity and truth values of expressions under different conditions.
24 | This organized structure enables efficient development, easy collaboration, and seamless integration of different parts of the platform. By breaking down the project into logical components, it becomes more maintainable, scalable, and easier to understand for contributors and developers.
27 |As you work on different aspects of the Predimate project, remember to use the appropriate directory to keep your code organized and ensure a smooth development process. Happy coding! 🚀
-------------------------------------------------------------------------------- /images/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisfbl/predimate/94adcb8761aa30f42549d84342ed6566074cca04/images/menu.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyinstaller 2 | texttable -------------------------------------------------------------------------------- /src/cli/main.py: -------------------------------------------------------------------------------- 1 | from src.data.encode import encode_expression 2 | from src.cli.truth_table import generate_truth_table 3 | 4 | 5 | def print_main_header(): 6 | header = r""" 7 | _____ _ _ _ 8 | | __ \ | (_) | | 9 | | |__) | __ ___ __| |_ _ __ ___ __ _| |_ ___ 10 | | ___/ '__/ _ \/ _` | | '_ ` _ \ / _` | __/ _ \ 11 | | | | | | __/ (_| | | | | | | | (_| | || __/ 12 | |_| |_| \___|\__,_|_|_| |_| |_|\__,_|\__\___| 13 | """ 14 | 15 | print(header) 16 | 17 | 18 | def get_menu_choice(): 19 | print("\nMenu Principal:") 20 | print("1 - Tabela Verdade") 21 | print("0 - Sair\n") 22 | 23 | return int(input("Escolha uma opção: ")) 24 | 25 | 26 | def parse_input(item, prepositions, expressions): 27 | wrapped = encode_expression(item) 28 | 29 | if wrapped is None: 30 | quit(f"Argumento \"{item}\" inválido") 31 | 32 | if wrapped not in expressions: 33 | expressions.append(wrapped) 34 | 35 | for prep in list(filter(lambda char: char.isalpha() and char != 'v', item)): 36 | if prep.upper() not in prepositions: 37 | prepositions.append(prep.upper()) 38 | 39 | 40 | def get_input_list(prompt, repeat=True): 41 | prepositions, expressions = [], [] 42 | 43 | while True: 44 | item = input(prompt).replace(" ", "") 45 | 46 | if item == "0": 47 | break 48 | 49 | parse_input(item, prepositions, expressions) 50 | 51 | if not repeat: 52 | break 53 | 54 | prepositions.sort() 55 | 56 | return prepositions, expressions 57 | 58 | 59 | def main(): 60 | print_main_header() 61 | 62 | while True: 63 | menu = get_menu_choice() 64 | 65 | if menu == 0: 66 | return 67 | 68 | (prepositions, premises) = get_input_list("Digite uma premissa (ou 0 para pular): ") 69 | (_, conclusion) = get_input_list("Digite a conclusão (ou 0 para pular): ", False) 70 | 71 | if menu == 1: 72 | generate_truth_table(prepositions, premises, conclusion) 73 | else: 74 | break 75 | 76 | 77 | if __name__ == "__main__": 78 | main() 79 | -------------------------------------------------------------------------------- /src/cli/truth_table.py: -------------------------------------------------------------------------------- 1 | from texttable import Texttable 2 | 3 | from src.truth_table.table import table_type, generate_combinations, evaluate_expressions, is_valid 4 | 5 | 6 | def create_text_table(header, rows): 7 | table = Texttable() 8 | table.set_cols_align("c" * len(header)) 9 | table.set_max_width(0) 10 | table.add_rows([header] + rows) 11 | 12 | return table 13 | 14 | 15 | def generate_truth_table(prepositions, premises, conclusion): 16 | expressions = premises + conclusion 17 | combinations = generate_combinations(prepositions) 18 | values = evaluate_expressions(prepositions, expressions, combinations) 19 | 20 | expanded_expressions = values.keys() 21 | 22 | # Orients values in rows 23 | rows = list(zip(*values.values())) 24 | header = list(map(lambda x: str(x), expanded_expressions)) 25 | results = [['V' if value else 'F' for value in row] for row in rows] 26 | 27 | print(create_text_table(header, results).draw()) 28 | print(f'Tipo de tabela: {table_type(rows)}') 29 | 30 | if conclusion: 31 | print(f'{"O argumento é válido" if is_valid(values, premises, conclusion[0]) else "O argumento é inválido"}') 32 | -------------------------------------------------------------------------------- /src/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisfbl/predimate/94adcb8761aa30f42549d84342ed6566074cca04/src/data/__init__.py -------------------------------------------------------------------------------- /src/data/decode.py: -------------------------------------------------------------------------------- 1 | from src.entity.operators import * 2 | 3 | 4 | def decode_expression(expr): 5 | if isinstance(expr, Base): 6 | return str(expr) 7 | else: 8 | return expr 9 | -------------------------------------------------------------------------------- /src/data/encode.py: -------------------------------------------------------------------------------- 1 | from src.entity.operators import * 2 | from src.entity.quantifiers import * 3 | 4 | 5 | def encode_expression(expr: str) -> Base: 6 | i = 0 7 | result = [] 8 | 9 | while i < len(expr): 10 | if expr[i] == '(': 11 | # Ignore '(' 12 | i += 1 13 | # Sum `i` to find the real position of parenthesis in current expr 14 | # Add 1 to the result to move to the character immediately after the closing parenthesis. 15 | j = find_parentheses_end(expr[i:]) + i + 1 16 | 17 | result.append(encode_expression(expr[i:j])) 18 | # Ignore everything inside the parentheses, because it will be solved in the recursion above 19 | i = j 20 | elif expr[i] == ')': 21 | # Ignore ')' 22 | i += 1 23 | # The operator with the most characters is <-> (3), so the substring 24 | elif operator := find_operator(expr[i:i + 3]): 25 | i += len(operator) 26 | 27 | # The behavior of negation is different from the other operators 28 | # While operators have a left and right side to the expression, negation has only one parameter 29 | if operator not in get_operators(Negation): 30 | right = encode_expression(expr[i:]) 31 | left = result.pop() 32 | 33 | return operators[operator](left, right) 34 | else: 35 | # After the negation there can be a parenthesis or a literal, as in ~(P^Q) or ~P 36 | if expr[i] == '(': 37 | i += 1 38 | j = find_parentheses_end(expr[i:]) + i 39 | sub_result = encode_expression(expr[i:j]) 40 | i = j 41 | elif not expr[i].isalpha(): 42 | i += 1 43 | j = find_end(expr[i:]) + i + 1 44 | sub_result = encode_expression(expr[i - 1:j]) 45 | i = j 46 | else: 47 | j = find_end(expr[i:]) + i + 1 48 | sub_result = encode_expression(expr[i:j]) 49 | i = j 50 | 51 | result.append(Negation(sub_result)) 52 | elif quantifier := find_quantifier(expr[i]): 53 | i += 2 54 | var = expr[i - 1] 55 | 56 | if expr[i] == '(': 57 | i += 1 58 | j = find_parentheses_end(expr[i:]) + i 59 | sub_result = encode_expression(expr[i:j]) 60 | i = j 61 | elif expr[i] in get_operators(Negation): 62 | i += 1 63 | j = find_end(expr[i:]) + i + 1 64 | sub_result = Negation(Predicate(expr[i], [*expr[i + 1:j]])) 65 | i = j 66 | elif not expr[i].isalpha(): 67 | sub_result = encode_expression(expr[i:]) 68 | i = len(expr) 69 | else: 70 | i += 1 71 | j = find_end(expr[i:]) + i + 1 72 | sub_result = encode_expression(expr[i - 1:j]) 73 | i = j 74 | 75 | result.append(quantifiers[quantifier](var, sub_result)) 76 | else: 77 | j = find_end(expr[i:]) + i + 1 78 | 79 | if j >= 2: 80 | sub_result = Predicate(expr[i], [*expr[i + 1:j]]) 81 | else: 82 | sub_result = Preposition(expr[i].upper()) 83 | 84 | result.append(sub_result) 85 | i += j 86 | 87 | if len(result) == 1: 88 | return result[0] 89 | 90 | 91 | def find_parentheses_end(expr: str) -> int: 92 | # In the expr the first parenthesis is ignored, so we start the count with 1 93 | count = 1 94 | 95 | for i, char in enumerate(expr): 96 | if char == '(': 97 | count += 1 98 | elif char == ')': 99 | count -= 1 100 | if count == 0: 101 | return i 102 | 103 | raise ValueError("Parênteses desequilibrados") 104 | 105 | 106 | def find_operator(expr: str) -> str | None: 107 | for operator in operators: 108 | # Use startswith to avoid false truths like in PvQ, making sure that the start is an operator 109 | if expr.startswith(operator): 110 | return operator 111 | 112 | return None 113 | 114 | 115 | def find_quantifier(expr: str) -> str | None: 116 | for quantifier in quantifiers: 117 | if expr.startswith(quantifier): 118 | return quantifier 119 | 120 | return None 121 | 122 | 123 | def find_end(expr): 124 | for i in range(len(expr)): 125 | if not expr[i].isalpha() or expr[i] == 'v' or expr[i] == '∨': 126 | return i - 1 127 | elif i == len(expr) - 1: 128 | return i 129 | 130 | return None 131 | 132 | 133 | def get_operators(op): 134 | result = [] 135 | 136 | for key, value in operators.items(): 137 | if value == op: 138 | result.append(key) 139 | 140 | return result 141 | -------------------------------------------------------------------------------- /src/entity/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisfbl/predimate/94adcb8761aa30f42549d84342ed6566074cca04/src/entity/__init__.py -------------------------------------------------------------------------------- /src/entity/base.py: -------------------------------------------------------------------------------- 1 | class Base: 2 | def __repr__(self): 3 | class_name = self.__class__.__name__ 4 | attributes = ", ".join(f"{attr}={getattr(self, attr)!r}" for attr in vars(self) if not attr.startswith('_')) 5 | 6 | return f"{class_name}({attributes})" 7 | 8 | def __eq__(self, other): 9 | if isinstance(other, self.__class__): 10 | return all(getattr(self, attr) == getattr(other, attr) for attr in vars(self) if not attr.startswith('_')) 11 | 12 | return False 13 | 14 | def __hash__(self): 15 | # Implement a custom hash method for instances of this class 16 | return hash(tuple(sorted(self.__dict__.items()))) 17 | -------------------------------------------------------------------------------- /src/entity/node.py: -------------------------------------------------------------------------------- 1 | from src.entity.base import Base 2 | 3 | 4 | class Node(Base): 5 | def __init__(self, data): 6 | self.data = data 7 | self.childrens = [] 8 | 9 | def add_child(self, children): 10 | self.childrens.append(children) 11 | 12 | return children 13 | -------------------------------------------------------------------------------- /src/entity/operators.py: -------------------------------------------------------------------------------- 1 | from src.entity.base import Base 2 | 3 | 4 | class Operator(Base): 5 | symbol = '' 6 | 7 | def __init__(self, left, right): 8 | self.left = left 9 | self.right = right 10 | 11 | # String representations of left and right operands 12 | self._left_str = f'({self.left})' if isinstance(self.left, Operator) else str(self.left) 13 | self._right_str = f'({self.right})' if isinstance(self.right, Operator) else str(self.right) 14 | 15 | def __str__(self): 16 | return f'{self._left_str}{self.symbol}{self._right_str}' 17 | 18 | 19 | class Conjunction(Operator): 20 | symbol = '^' 21 | 22 | 23 | class Disjunction(Operator): 24 | symbol = 'v' 25 | 26 | 27 | class Conditional(Operator): 28 | symbol = '->' 29 | 30 | 31 | class BiConditional(Operator): 32 | symbol = '<->' 33 | 34 | 35 | class Negation(Base): 36 | def __init__(self, expr): 37 | self.expr = expr 38 | 39 | def __str__(self): 40 | expr_str = f'({self.expr})' if isinstance(self.expr, Operator) or isinstance(self.expr, Negation) \ 41 | else str(self.expr) 42 | 43 | return f'~{expr_str}' 44 | 45 | 46 | class Preposition(Base): 47 | def __init__(self, prep): 48 | self.prep = prep 49 | 50 | def __str__(self): 51 | return f'{self.prep}' 52 | 53 | 54 | operators = { 55 | '^': Conjunction, 56 | '∧': Conjunction, 57 | 'v': Disjunction, 58 | '∨': Disjunction, 59 | '->': Conditional, 60 | '→': Conditional, 61 | '<->': BiConditional, 62 | '↔': BiConditional, 63 | '¬': Negation, 64 | '~': Negation 65 | } 66 | -------------------------------------------------------------------------------- /src/entity/quantifiers.py: -------------------------------------------------------------------------------- 1 | from src.entity.base import Base 2 | from src.entity.operators import Operator 3 | 4 | 5 | class Quantifier(Base): 6 | symbol = '' 7 | 8 | def __init__(self, var, expr): 9 | self.var = var 10 | self.expr = expr 11 | 12 | self._expr = f'({self.expr})' if isinstance(self.expr, Operator) else str(self.expr) 13 | 14 | def __str__(self): 15 | return f'{self.symbol}{self.var}{self._expr}' 16 | 17 | 18 | class Universal(Quantifier): 19 | symbol = '∀' 20 | 21 | 22 | class Existential(Quantifier): 23 | symbol = '∃' 24 | 25 | 26 | class Predicate(Base): 27 | def __init__(self, predicate, letters=['x']): 28 | self.predicate = predicate.upper() 29 | self.letters = [letter.lower() for letter in letters] 30 | 31 | def __str__(self): 32 | return f'{self.predicate}{",".join(self.letters)}' 33 | 34 | 35 | quantifiers = { 36 | "∀": Universal, 37 | "∃": Existential 38 | } 39 | -------------------------------------------------------------------------------- /src/tablos/tablo.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisfbl/predimate/94adcb8761aa30f42549d84342ed6566074cca04/src/tablos/tablo.py -------------------------------------------------------------------------------- /src/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisfbl/predimate/94adcb8761aa30f42549d84342ed6566074cca04/src/tests/__init__.py -------------------------------------------------------------------------------- /src/tests/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luisfbl/predimate/94adcb8761aa30f42549d84342ed6566074cca04/src/tests/data/__init__.py -------------------------------------------------------------------------------- /src/tests/data/test_decode.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from src.data.decode import decode_expression 4 | from src.entity.operators import * 5 | 6 | 7 | class TestDecode(unittest.TestCase): 8 | def test_decode_conjunction(self): 9 | self.assertEqual( 10 | "P^Q", 11 | decode_expression(Conjunction(left=Preposition(prep='P'), right=Preposition('Q'))) 12 | ) 13 | 14 | self.assertEqual( 15 | "(A^B)^C", 16 | decode_expression(Conjunction(left=Conjunction(left=Preposition(prep='A'), right=Preposition(prep='B')), right=Preposition(prep='C'))) 17 | ) 18 | 19 | self.assertEqual( 20 | "((D^E)^F)^G", 21 | decode_expression(Conjunction(left=Conjunction(left=Conjunction(left=Preposition(prep='D'), right=Preposition(prep='E')), right=Preposition(prep='F')), right=Preposition(prep='G'))) 22 | ) 23 | 24 | self.assertEqual( 25 | "(((H^I)^J)^K)^L", 26 | decode_expression(Conjunction(left=Conjunction(left=Conjunction(left=Conjunction(left=Preposition(prep='H'), right=Preposition(prep='I')), right=Preposition(prep='J')), right=Preposition(prep='K')), right=Preposition(prep='L'))) 27 | ) 28 | 29 | self.assertEqual( 30 | "((((M^N)^O)^P)^Q)^R", 31 | decode_expression(Conjunction(left=Conjunction(left=Conjunction(left=Conjunction(left=Conjunction(left='M', right='N'), right='O'), right='P'), right='Q'), right='R')) 32 | ) 33 | 34 | def test_decode_disjunction(self): 35 | self.assertEqual( 36 | "PvQ", 37 | decode_expression(Disjunction(left='P', right='Q')) 38 | ) 39 | 40 | self.assertEqual( 41 | "(AvB)vC", 42 | decode_expression(Disjunction(left=Disjunction(left='A', right='B'), right='C')) 43 | ) 44 | 45 | self.assertEqual( 46 | "Dv(EvF)", 47 | decode_expression(Disjunction(left='D', right=Disjunction(left='E', right='F'))) 48 | ) 49 | 50 | self.assertEqual( 51 | "(((PvQ)v(Rv(SvT)))v(Uv(Vv(Wv(XvY)))))vZ", 52 | decode_expression(Disjunction(left=Disjunction(left=Disjunction(left=Disjunction(left='P', right='Q'), right=Disjunction(left='R', right=Disjunction(left='S', right='T'))), right=Disjunction(left='U', right=Disjunction(left='V', right=Disjunction(left='W', right=Disjunction(left='X', right='Y'))))), right='Z')) 53 | ) 54 | 55 | self.assertEqual( 56 | "((JvK)vL)vM", 57 | decode_expression(Disjunction(left=Disjunction(left=Disjunction(left='J', right='K'), right='L'), right='M')) 58 | ) 59 | 60 | def test_decode_conditional(self): 61 | self.assertEqual( 62 | "P->Q", 63 | decode_expression(Conditional(left='P', right='Q')) 64 | ) 65 | 66 | self.assertEqual( 67 | "((P->(R->(T->V)))->(R->G))->R", 68 | decode_expression(Conditional(left=Conditional(left=Conditional(left='P', right=Conditional(left='R', right=Conditional(left='T', right='V'))), right=Conditional(left='R', right='G')), right='R')) 69 | ) 70 | 71 | self.assertEqual( 72 | "((A->(B->C))->(D->(E->F)))->G", 73 | decode_expression(Conditional(left=Conditional(left=Conditional(left='A', right=Conditional(left='B', right='C')), right=Conditional(left='D', right=Conditional(left='E', right='F'))), right='G')) 74 | ) 75 | 76 | self.assertEqual( 77 | "(((P->Q)->(R->S))->((T->U)->(V->W)))->X", 78 | decode_expression(Conditional(left=Conditional(left=Conditional(left=Conditional(left='P', right='Q'), right=Conditional(left='R', right='S')), right=Conditional(left=Conditional(left='T', right='U'), right=Conditional(left='V', right='W'))), right='X')) 79 | ) 80 | 81 | self.assertEqual( 82 | "((P->Q)->(R->(S->(T->(U->(V->(W->(X->(Y->Z)))))))))->(((A->B)->(C->(D->(E->(F->(G->(H->I)))))))->J)", 83 | decode_expression(Conditional(left=Conditional(left=Conditional(left='P', right='Q'), right=Conditional(left='R', right=Conditional(left='S', right=Conditional(left='T', right=Conditional(left='U', right=Conditional(left='V', right=Conditional(left='W', right=Conditional(left='X', right=Conditional(left='Y', right='Z'))))))))), right=Conditional(left=Conditional(left=Conditional(left='A', right='B'), right=Conditional(left='C', right=Conditional(left='D', right=Conditional(left='E', right=Conditional(left='F', right=Conditional(left='G', right=Conditional(left='H', right='I'))))))), right='J'))) 84 | ) 85 | 86 | def test_decode_biconditional(self): 87 | self.assertEqual( 88 | "P<->Q", 89 | decode_expression(BiConditional(left='P', right='Q')) 90 | ) 91 | 92 | self.assertEqual( 93 | "(P<->Q)<->(R<->(S<->(T<->(U<->(V<->(W<->(X<->(Y<->Z))))))))", 94 | decode_expression(BiConditional(left=BiConditional(left='P', right='Q'), right=BiConditional(left='R', right=BiConditional(left='S', right=BiConditional(left='T', right=BiConditional(left='U', right=BiConditional(left='V', right=BiConditional(left='W', right=BiConditional(left='X', right=BiConditional(left='Y', right='Z')))))))))) 95 | ) 96 | 97 | self.assertEqual( 98 | "(P<->(Q<->(R<->(S<->(T<->U)))))<->V", 99 | decode_expression(BiConditional(left=BiConditional(left='P', right=BiConditional(left='Q', right=BiConditional(left='R', right=BiConditional(left='S', right=BiConditional(left='T', right='U'))))), right='V')) 100 | ) 101 | 102 | self.assertEqual( 103 | "(((((A<->B)<->C)<->D)<->E)<->F)<->G", 104 | decode_expression(BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left='A', right='B'), right='C'), right='D'), right='E'), right='F'), right='G')) 105 | ) 106 | 107 | self.assertEqual( 108 | "((((((((P<->Q)<->R)<->S)<->T)<->U)<->V)<->W)<->X)<->Y", 109 | decode_expression(BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left='P', right='Q'), right='R'), right='S'), right='T'), right='U'), right='V'), right='W'), right='X'), right='Y')) 110 | ) 111 | 112 | def test_decode_negation(self): 113 | self.assertEqual( 114 | "~P", 115 | decode_expression(Negation(expr='P')) 116 | ) 117 | 118 | def test_decode(self): 119 | self.assertEqual( 120 | "~((PvQ)v(P->(Q^R)))^((P<->R)v(T->U))", 121 | decode_expression(Conjunction(left=Negation(expr=Disjunction(left=Disjunction(left='P', right='Q'), right=Conditional(left='P', right=Conjunction(left='Q', right='R')))), right=Disjunction(left=BiConditional(left='P', right='R'), right=Conditional(left='T', right='U')))) 122 | ) 123 | 124 | self.assertEqual( 125 | "(PvQ)^~P", 126 | decode_expression(Conjunction(left=Disjunction(left='P', right='Q'), right=Negation('P'))) 127 | ) 128 | 129 | self.assertEqual( 130 | "P->Q", 131 | decode_expression(Conditional(left='P', right='Q')) 132 | ) 133 | 134 | self.assertEqual( 135 | "~(P^Q)v((RvS)->((TvU)<->~W))", 136 | decode_expression(Disjunction(left=Negation(expr=Conjunction(left='P', right='Q')), right=Conditional(left=Disjunction(left='R', right='S'), right=BiConditional(left=Disjunction(left='T', right='U'), right=Negation(expr='W'))))) 137 | ) 138 | 139 | self.assertEqual( 140 | "(A^(BvC))^((Dv(EvF))->((G<->(H<->I))^(J^(KvL))))", 141 | decode_expression(Conjunction(left=Conjunction(left='A', right=Disjunction(left='B', right='C')), right=Conditional(left=Disjunction(left='D', right=Disjunction(left='E', right='F')), right=Conjunction(left=BiConditional(left='G', right=BiConditional(left='H', right='I')), right=Conjunction(left='J', right=Disjunction(left='K', right='L')))))) 142 | ) 143 | 144 | self.assertEqual( 145 | "~(~(~(PvQ))v(~(RvS)->~((TvU)<->W)))", 146 | decode_expression(Negation(expr=Disjunction(left=Negation(expr=Negation(expr=Disjunction(left='P', right='Q'))), right=Conditional(left=Negation(expr=Disjunction(left='R', right='S')), right=Negation(expr=BiConditional(left=Disjunction(left='T', right='U'), right='W')))))) 147 | ) 148 | 149 | 150 | if __name__ == '__main__': 151 | unittest.main() 152 | -------------------------------------------------------------------------------- /src/tests/data/test_encode.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from src.data.encode import encode_expression 4 | from src.entity.operators import * 5 | from src.entity.quantifiers import * 6 | 7 | 8 | class TestEncode(unittest.TestCase): 9 | def test_encode_conjunction(self): 10 | self.assertEqual( 11 | Conjunction(left=Preposition(prep='P'), right=Preposition('Q')), 12 | encode_expression("(P^Q)") 13 | ) 14 | 15 | self.assertEqual( 16 | Conjunction(left=Conjunction(left=Preposition(prep='A'), right=Preposition(prep='B')), right=Preposition(prep='C')), 17 | encode_expression("((A^B)^C)") 18 | ) 19 | 20 | self.assertEqual( 21 | Conjunction(left=Conjunction(left=Conjunction(left=Preposition(prep='D'), right=Preposition(prep='E')), right=Preposition(prep='F')), right=Preposition(prep='G')), 22 | encode_expression("(((D^E)^F)^G)") 23 | ) 24 | 25 | self.assertEqual( 26 | Conjunction(left=Conjunction(left=Conjunction(left=Conjunction(left=Preposition(prep='H'), right=Preposition(prep='I')), right=Preposition(prep='J')), right=Preposition(prep='K')), right=Preposition(prep='L')), 27 | encode_expression("((((H^I)^J)^K)^L)") 28 | ) 29 | 30 | self.assertEqual( 31 | Conjunction(left=Conjunction(left=Conjunction(left=Conjunction(left=Conjunction(left=Preposition(prep='M'), right=Preposition(prep='N')), right=Preposition(prep='O')), right=Preposition(prep='P')), right=Preposition(prep='Q')), right=Preposition(prep='R')), 32 | encode_expression("(((((M^N)^O)^P)^Q)^R)") 33 | ) 34 | 35 | def test_encode_disjunction(self): 36 | self.assertEqual( 37 | Disjunction(left=Preposition(prep='P'), right=Preposition(prep='Q')), 38 | encode_expression("PvQ") 39 | ) 40 | 41 | self.assertEqual( 42 | Disjunction(left=Disjunction(left=Preposition(prep='A'), right=Preposition(prep='B')), right=Preposition(prep='C')), 43 | encode_expression("((AvB)vC)") 44 | ) 45 | 46 | self.assertEqual( 47 | Disjunction(left=Preposition(prep='D'), right=Disjunction(left=Preposition(prep='E'), right=Preposition(prep='F'))), 48 | encode_expression("Dv(EvF)") 49 | ) 50 | 51 | self.assertEqual( 52 | Disjunction(left=Disjunction(left=Disjunction(left=Disjunction(left=Preposition(prep='P'), right=Preposition(prep='Q')), right=Disjunction(left=Preposition(prep='R'), right=Disjunction(left=Preposition(prep='S'), right=Preposition(prep='T')))), right=Disjunction(left=Preposition(prep='U'), right=Disjunction(left=Preposition(prep='V'), right=Disjunction(left=Preposition(prep='W'), right=Disjunction(left=Preposition(prep='X'), right=Preposition(prep='Y')))))), right=Preposition(prep='Z')), 53 | encode_expression("(((PvQ)v(Rv(SvT)))v(Uv(Vv(Wv(XvY)))))vZ") 54 | ) 55 | 56 | self.assertEqual( 57 | Disjunction(left=Disjunction(left=Disjunction(left=Preposition(prep='J'), right=Preposition(prep='K')), right=Preposition(prep='L')), right=Preposition(prep='M')), 58 | encode_expression("((JvK)vL)vM") 59 | ) 60 | 61 | def test_encode_conditional(self): 62 | self.assertEqual( 63 | Conditional(left=Preposition(prep='P'), right=Preposition(prep='Q')), 64 | encode_expression("P->Q") 65 | ) 66 | 67 | self.assertEqual( 68 | Conditional(left=Conditional(left=Conditional(left=Preposition(prep='P'), right=Conditional(left=Preposition(prep='R'), right=Conditional(left=Preposition(prep='T'), right=Preposition(prep='V')))), right=Conditional(left=Preposition(prep='R'), right=Preposition(prep='G'))), right=Preposition(prep='R')), 69 | encode_expression("((P->(R->(T->V)))->(R->G))->R") 70 | ) 71 | 72 | self.assertEqual( 73 | Conditional(left=Conditional(left=Conditional(left=Preposition(prep='A'), right=Conditional(left=Preposition(prep='B'), right=Preposition(prep='C'))), right=Conditional(left=Preposition(prep='D'), right=Conditional(left=Preposition(prep='E'), right=Preposition(prep='F')))), right=Preposition(prep='G')), 74 | encode_expression("((A->(B->C))->(D->(E->F)))->G") 75 | ) 76 | 77 | self.assertEqual( 78 | Conditional(left=Conditional(left=Conditional(left=Conditional(left=Preposition(prep='P'), right=Preposition(prep='Q')), right=Conditional(left=Preposition(prep='R'), right=Preposition(prep='S'))), right=Conditional(left=Conditional(left=Preposition(prep='T'), right=Preposition(prep='U')), right=Conditional(left=Preposition(prep='V'), right=Preposition(prep='W')))), right=Preposition(prep='X')), 79 | encode_expression("(((P->Q)->(R->S))->((T->U)->(V->W)))->X") 80 | ) 81 | 82 | self.assertEqual( 83 | Conditional(left=Conditional(left=Conditional(left=Preposition(prep='P'), right=Preposition(prep='Q')), right=Conditional(left=Preposition(prep='R'), right=Conditional(left=Preposition(prep='S'), right=Conditional(left=Preposition(prep='T'), right=Conditional(left=Preposition(prep='U'), right=Conditional(left=Preposition(prep='V'), right=Conditional(left=Preposition(prep='W'), right=Conditional(left=Preposition(prep='X'), right=Conditional(left=Preposition(prep='Y'), right=Preposition(prep='Z')))))))))), right=Conditional(left=Conditional(left=Conditional(left=Preposition(prep='A'), right=Preposition(prep='B')), right=Conditional(left=Preposition(prep='C'), right=Conditional(left=Preposition(prep='D'), right=Conditional(left=Preposition(prep='E'), right=Conditional(left=Preposition(prep='F'), right=Conditional(left=Preposition(prep='G'), right=Conditional(left=Preposition(prep='H'), right=Preposition(prep='I')))))))), right=Preposition(prep='J'))), encode_expression("((P->Q)->(R->(S->(T->(U->(V->(W->(X->(Y->Z)))))))))->(((A->B)->(C->(D->(E->(F->(G->(H->I)))))))->J)") 84 | ) 85 | 86 | def test_encode_biconditional(self): 87 | self.assertEqual( 88 | BiConditional(left=Preposition(prep='P'), right=Preposition(prep='Q')), 89 | encode_expression("P<->Q") 90 | ) 91 | 92 | self.assertEqual( 93 | BiConditional(left=BiConditional(left=Preposition(prep='P'), right=Preposition(prep='Q')), right=BiConditional(left=Preposition(prep='R'), right=BiConditional(left=Preposition(prep='S'), right=BiConditional(left=Preposition(prep='T'), right=BiConditional(left=Preposition(prep='U'), right=BiConditional(left=Preposition(prep='V'), right=BiConditional(left=Preposition(prep='W'), right=BiConditional(left=Preposition(prep='X'), right=BiConditional(left=Preposition(prep='Y'), right=Preposition(prep='Z')))))))))), 94 | encode_expression("(P<->Q)<->(R<->(S<->(T<->(U<->(V<->(W<->(X<->(Y<->Z))))))))"), 95 | ) 96 | 97 | self.assertEqual( 98 | BiConditional(left=BiConditional(left=Preposition(prep='P'), right=BiConditional(left=Preposition(prep='Q'), right=BiConditional(left=Preposition(prep='R'), right=BiConditional(left=Preposition(prep='S'), right=BiConditional(left=Preposition(prep='T'), right=Preposition(prep='U')))))), right=Preposition(prep='V')), 99 | encode_expression("(P<->(Q<->(R<->(S<->(T<->U)))))<->V"), 100 | ) 101 | 102 | self.assertEqual( 103 | BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=Preposition(prep='A'), right=Preposition(prep='B')), right=Preposition(prep='C')), right=Preposition(prep='D')), right=Preposition(prep='E')), right=Preposition(prep='F')), right=Preposition(prep='G')), 104 | encode_expression("(((((A<->B)<->C)<->D)<->E)<->F)<->G"), 105 | ) 106 | 107 | self.assertEqual( 108 | BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=BiConditional(left=Preposition(prep='P'), right=Preposition(prep='Q')), right=Preposition(prep='R')), right=Preposition(prep='S')), right=Preposition(prep='T')), right=Preposition(prep='U')), right=Preposition(prep='V')), right=Preposition(prep='W')), right=Preposition(prep='X')), right=Preposition(prep='Y')), 109 | encode_expression("((((((((P<->Q)<->R)<->S)<->T)<->U)<->V)<->W)<->X)<->Y") 110 | ) 111 | 112 | def test_encode_negation(self): 113 | self.assertEqual( 114 | Negation(expr=Preposition(prep='P')), 115 | encode_expression("~P") 116 | ) 117 | 118 | def test_encode_predicate(self): 119 | self.assertEqual( 120 | Conditional(left=Predicate(predicate='M', letters=['c']), right=Negation(expr=Predicate(predicate='E', letters=['c']))), 121 | encode_expression("Mc->~Ec") 122 | ) 123 | 124 | self.assertEqual( 125 | Conjunction(left=Predicate(predicate='M', letters=['c']), right=Predicate(predicate='M', letters=['b'])), 126 | encode_expression("Mc^Mb") 127 | ) 128 | 129 | def test_encode_universal(self): 130 | self.assertEqual( 131 | Universal(var='x', expr=Conditional(left=Predicate(predicate='R', letters=['x']), right=Predicate(predicate='V', letters=['x']))), 132 | encode_expression("∀x(Rx->Vx)") 133 | ) 134 | 135 | self.assertEqual( 136 | Universal(var='x', expr=Predicate(predicate='R', letters=['x'])), 137 | encode_expression("∀xRx") 138 | ) 139 | 140 | self.assertEqual( 141 | Universal(var='x', expr=Negation(expr=Predicate(predicate='R', letters=['x']))), 142 | encode_expression("∀x~Rx") 143 | ) 144 | 145 | self.assertEqual( 146 | Negation(expr=Universal(var='x', expr=Predicate(predicate='R', letters=['x']))), 147 | encode_expression("~∀xRx") 148 | ) 149 | 150 | self.assertEqual( 151 | Conditional(left=Negation(expr=Predicate(predicate='L', letters=['b', 'b'])), right=Universal(var='x', expr=Negation(expr=Predicate(predicate='L', letters=['b', 'x'])))), 152 | encode_expression("~Lbb->∀x~Lbx") 153 | ) 154 | 155 | self.assertEqual( 156 | Universal(var='x', expr=Universal(var='y', expr=Predicate(predicate='L', letters=['x', 'y']))), 157 | encode_expression("∀x∀yLxy") 158 | ) 159 | 160 | self.assertEqual( 161 | Universal(var='x', expr=Conditional(left=Conjunction(left=Predicate(predicate='R', letters=['x']), right=Predicate(predicate='V', letters=['x'])), right=Predicate(predicate='S', letters=['x']))), 162 | encode_expression("∀x((Rx^Vx)->Sx)") 163 | ) 164 | 165 | self.assertEqual( 166 | Universal(var='x', expr=Universal(var='y', expr=Universal(var='z', expr=Conditional(left=Conjunction(left=Predicate(predicate='T', letters=['x', 'y']), right=Predicate(predicate='T', letters=['y', 'z'])), right=Predicate(predicate='T', letters=['x', 'z']))))), 167 | encode_expression("∀x∀y∀z((Txy^Tyz)->Txz)") 168 | ) 169 | 170 | def test_encode_existential(self): 171 | self.assertEqual( 172 | Existential(var='x', expr=Predicate(predicate='L', letters=['x', 'x'])), 173 | encode_expression("∃xLxx") 174 | ) 175 | 176 | self.assertEqual( 177 | Existential(var='x', expr=Conjunction(left=Predicate(predicate='L', letters=['b', 'x']), right=Predicate(predicate='L', letters=['c', 'x']))), 178 | encode_expression("∃x(Lbx^Lcx)") 179 | ) 180 | 181 | self.assertEqual( 182 | Existential(var='x', expr=Predicate(predicate='D', letters=['c', 'x', 'b'])), 183 | encode_expression("∃xDcxb") 184 | ) 185 | 186 | self.assertEqual( 187 | Existential(var='x', expr=Conjunction(left=Predicate(predicate='A', letters=['x']), right=Predicate(predicate='D', letters=['b', 'x', 'c']))), 188 | encode_expression("∃x(Ax^Dbxc)") 189 | ) 190 | 191 | self.assertEqual( 192 | Existential(var='x', expr=Existential(var='y', expr=Predicate(predicate='L', letters=['x', 'y']))), 193 | encode_expression("∃x∃yLxy") 194 | ) 195 | 196 | self.assertEqual( 197 | Existential(var='x', expr=Existential(var='y', expr=Existential(var='z', expr=Conditional(left=Conjunction(left=Predicate(predicate='T', letters=['x', 'y']), right=Predicate(predicate='T', letters=['y', 'z'])), right=Predicate(predicate='T', letters=['x', 'z']))))), 198 | encode_expression("∃x∃y∃z((Txy^Tyz)->Txz)") 199 | ) 200 | 201 | def test_encode(self): 202 | self.assertEqual( 203 | Conjunction(left=Negation(expr=Disjunction(left=Disjunction(left=Preposition(prep='P'), right=Preposition(prep='Q')), right=Conditional(left=Preposition(prep='P'), right=Conjunction(left=Preposition(prep='Q'), right=Preposition(prep='R'))))), right=Disjunction(left=BiConditional(left=Preposition(prep='P'), right=Preposition(prep='R')), right=Conditional(left=Preposition(prep='T'), right=Preposition(prep='U')))), 204 | encode_expression("~((PvQ)v(P->(Q^R)))^((P<->R)v(T->U))") 205 | ) 206 | 207 | self.assertEqual( 208 | Conjunction(left=Disjunction(left=Preposition(prep='P'), right=Preposition(prep='Q')), right=Negation(expr=Preposition(prep='P'))), 209 | encode_expression("(PvQ)^~P"), 210 | ) 211 | 212 | self.assertEqual( 213 | Disjunction(left=Negation(expr=Conjunction(left=Preposition(prep='P'), right=Preposition(prep='Q'))), right=Conditional(left=Disjunction(left=Preposition(prep='R'), right=Preposition(prep='S')), right=BiConditional(left=Disjunction(left=Preposition(prep='T'), right=Preposition(prep='U')), right=Negation(expr=Preposition(prep='W'))))), 214 | encode_expression("~(P^Q)v((RvS)->((TvU)<->~W))") 215 | ) 216 | 217 | self.assertEqual( 218 | Conjunction(left=Conjunction(left=Preposition(prep='A'), right=Disjunction(left=Preposition(prep='B'), right=Preposition(prep='C'))), right=Conditional(left=Disjunction(left=Preposition(prep='D'), right=Disjunction(left=Preposition(prep='E'), right=Preposition(prep='F'))), right=Conjunction(left=BiConditional(left=Preposition(prep='G'), right=BiConditional(left=Preposition(prep='H'), right=Preposition(prep='I'))), right=Conjunction(left=Preposition(prep='J'), right=Disjunction(left=Preposition(prep='K'), right=Preposition(prep='L')))))), 219 | encode_expression("(A^(BvC))^((Dv(EvF))->((G<->(H<->I))^(J^(KvL))))") 220 | ) 221 | 222 | self.assertEqual( 223 | Negation(expr=Disjunction(left=Negation(expr=Negation(expr=Disjunction(left=Preposition(prep='P'), right=Preposition(prep='Q')))), right=Conditional(left=Negation(expr=Disjunction(left=Preposition(prep='R'), right=Preposition(prep='S'))), right=Negation(expr=BiConditional(left=Disjunction(left=Preposition(prep='T'), right=Preposition(prep='U')), right=Preposition(prep='W')))))), 224 | encode_expression("~(~(~(PvQ))v(~(RvS)->~((TvU)<->W)))") 225 | ) 226 | 227 | 228 | if __name__ == '__main__': 229 | unittest.main() 230 | -------------------------------------------------------------------------------- /src/truth_table/table.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | from itertools import product 3 | 4 | from src.entity.operators import * 5 | 6 | 7 | def generate_combinations(prepositions): 8 | return list(product([True, False], repeat=len(prepositions))) 9 | 10 | 11 | def evaluate_expression(expr, result, row): 12 | value = None 13 | 14 | if expr in result and len(result[expr]) > row: 15 | return result[expr][row] 16 | 17 | if isinstance(expr, Operator): 18 | left_value = evaluate_expression(expr.left, result, row) 19 | right_value = evaluate_expression(expr.right, result, row) 20 | 21 | if isinstance(expr, Conjunction): 22 | value = left_value and right_value 23 | elif isinstance(expr, Disjunction): 24 | value = left_value or right_value 25 | elif isinstance(expr, Conditional): 26 | value = (not left_value) or right_value 27 | elif isinstance(expr, BiConditional): 28 | value = left_value == right_value 29 | elif isinstance(expr, Negation): 30 | value = not evaluate_expression(expr.expr, result, row) 31 | else: 32 | return result[expr][row] 33 | 34 | result.setdefault(expr, []).append(value) 35 | 36 | return value 37 | 38 | 39 | def evaluate_expressions(prepositions, expressions, combinations): 40 | prep_combinations = list(zip(*combinations)) 41 | result = {Preposition(preposition): prep_combinations[i] for i, preposition in enumerate(prepositions)} 42 | 43 | for i in range(len(combinations)): 44 | for expr in expressions: 45 | evaluate_expression(expr, result, i) 46 | 47 | keys = list(result.keys()) 48 | 49 | return OrderedDict( 50 | sorted( 51 | result.items(), 52 | key=lambda item: ( 53 | not isinstance(item[0], Preposition), 54 | not (isinstance(item[0], Negation) and isinstance(item[0].expr, Preposition)), 55 | str(item[0].expr) if isinstance(item[0], Negation) and isinstance(item[0].expr, Preposition) else None, 56 | keys.index(item[0]) 57 | ) 58 | ) 59 | ) 60 | 61 | 62 | def table_type(results): 63 | if all(result[-1] for result in results): 64 | return "Tautologia" 65 | elif all(not result[-1] for result in results): 66 | return "Contradição" 67 | else: 68 | return "Contingência" 69 | 70 | 71 | def is_valid(results, premises, conclusion): 72 | final_premises = [results[premise] for premise in premises] 73 | final_conclusion = results[conclusion] 74 | 75 | for row_premises, row_conclusion in zip(zip(*final_premises), final_conclusion): 76 | if (all(row_premises) and not row_conclusion) or not any(row_premises): 77 | return False 78 | 79 | return True 80 | --------------------------------------------------------------------------------