I am writing a program that checks whether a formula is closed in multioperations or not. And the code for each formula gives me one answer.: The formula is not closed (contradictory). from typing import List, Tuple import re import uuid class Term: def __init__(self, symbol: str, subterms: List['Term'] = None): self.symbol = symbol self.subterms = tuple(subterms) if subterms else tuple() # Используем кортеж вместо списка def __repr__(self): if not self.subterms: return self.symbol return f"{self.symbol}({', '.join(map(str, self.subterms))})" def __eq__(self, other): return ( isinstance(other, Term) and self.symbol == other.symbol and self.subterms == other.subterms ) def __hash__(self): return hash((self.symbol, self.subterms)) # Хэшируем кортеж class Formula: def __init__(self, left: Term = None, right: Term = None, connective: str = None, subformulas: List['Formula'] = None): self.left = left self.right = right self.connective = connective self.subformulas = tuple(subformulas) if subformulas else tuple() # Кортеж def __eq__(self, other): return ( isinstance(other, Formula) and self.connective == other.connective and self.subformulas == other.subformulas and self.left == other.left and self.right == other.right ) def __hash__(self): return hash(( self.connective, self.left, self.right, self.subformulas )) class MarkedFormula: def __init__(self, formula: Formula, relation: str, alpha: float): self.formula = formula self.relation = relation self.alpha = alpha def __eq__(self, other): return ( isinstance(other, MarkedFormula) and self.formula == other.formula and self.relation == other.relation and abs(self.alpha - other.alpha) < 1e-9 ) def __hash__(self): return hash((self.formula, self.relation, self.alpha)) # -------------------------------------------- # Парсер формул (расширенный) # -------------------------------------------- class FormulaParser: @staticmethod def parse_term(s: str) -> Term: s = s.strip() if '(' not in s: return Term(s) symbol, rest = s.split('(', 1) subterms = [] buffer = [] depth = 0 for c in rest.rstrip(')'): if c == '(': depth += 1 elif c == ')': depth -= 1 if c == ',' and depth == 0: subterms.append(FormulaParser.parse_term(''.join(buffer).strip())) buffer = [] continue buffer.append(c) if buffer: subterms.append(FormulaParser.parse_term(''.join(buffer).strip())) return Term(symbol.strip(), subterms) @staticmethod def parse_formula(s: str) -> Formula: s = s.strip().replace(' ', '') # Обработка отрицания if s.startswith('¬'): return Formula(subformulas=[FormulaParser.parse_formula(s[1:])], connective='¬') # Обработка скобок (только если вся формула в скобках) if s.startswith('(') and s.endswith(')'): # Проверяем, что закрывающая скобка соответствует открывающей depth = 1 for i in range(1, len(s)-1): if s == '(': depth += 1 elif s == ')': depth -= 1 if depth == 0: break else: # Если все скобки закрыты, парсим внутреннюю часть return FormulaParser.parse_formula(s[1:-1]) # Порядок важен: сначала проверяем связки с более низким приоритетом for conn in ['⊆', '→', '∨', '&']: try: parts = FormulaParser.split_formula(s, conn) if conn == '⊆': return Formula( left=FormulaParser.parse_term(parts[0]), right=FormulaParser.parse_term(parts[1]), connective='⊆' ) else: return Formula( subformulas=[ FormulaParser.parse_formula(parts[0]), FormulaParser.parse_formula(parts[1]) ], connective=conn ) except ValueError: continue # Если не нашли связок, пытаемся распознать как терм try: term = FormulaParser.parse_term(s) return Formula(left=term) # Условно, если требуется except: raise ValueError(f"Invalid formula: {s}") @staticmethod def split_formula(s: str, connector: str) -> Tuple[str, str]: depth = 0 i = 0 connector_len = len(connector) while i <= len(s) - connector_len: if s == '(': depth += 1 elif s == ')': depth -= 1 elif depth == 0 and s[i:i+connector_len] == connector: left = s[:i] right = s[i+connector_len:] return left.strip(), right.strip() i += 1 raise ValueError(f"Failed to split by {connector} in {s}") @staticmethod def parse_marked(s: str) -> MarkedFormula: match = re.match(r"(.+?)(<=|>=|<|>)(\d*\.?\d+)", s.replace(' ', '')) if not match: raise ValueError(f"Invalid marked formula: {s}") formula_part = match.group(1) relation = match.group(2) alpha = float(match.group(3)) formula = FormulaParser.parse_formula(formula_part) return MarkedFormula(formula, relation, alpha) # -------------------------------------------- # Правила вывода (5 групп) # -------------------------------------------- class InferenceRule: def apply(self, mf: MarkedFormula) -> List[List[MarkedFormula]]: return [] class Group1Rule(InferenceRule): """Правила для отношений ⊆ с порогами""" def apply(self, mf: MarkedFormula): if mf.formula.connective == '⊆': if mf.relation == '>': if mf.alpha > 0: return [[MarkedFormula(Formula(mf.formula.right, mf.formula.left, '⊆'), '>', 0)]] elif mf.relation == '<': if mf.alpha < 1: return [[MarkedFormula(Formula(mf.formula.right, mf.formula.left, '⊆'), '<', 1)]] return [] class Group2Rule(InferenceRule): """Правила для логических связок""" def apply(self, mf: MarkedFormula): if mf.formula.connective == '&': if mf.relation in ('>', '>='): return [[ MarkedFormula(mf.formula.subformulas[0], mf.relation, mf.alpha), MarkedFormula(mf.formula.subformulas[1], mf.relation, mf.alpha) ]] elif mf.relation in ('<', '<='): return [ [MarkedFormula(mf.formula.subformulas[0], mf.relation, mf.alpha)], [MarkedFormula(mf.formula.subformulas[1], mf.relation, mf.alpha)] ] elif mf.formula.connective == '∨': if mf.relation in ('>', '>='): return [ [MarkedFormula(mf.formula.subformulas[0], mf.relation, mf.alpha)], [MarkedFormula(mf.formula.subformulas[1], mf.relation, mf.alpha)] ] elif mf.relation in ('<', '<='): return [[ MarkedFormula(mf.formula.subformulas[0], mf.relation, mf.alpha), MarkedFormula(mf.formula.subformulas[1], mf.relation, mf.alpha) ]] elif mf.formula.connective == '→': if mf.relation in ('>', '>='): return [[ MarkedFormula(mf.formula.subformulas[0], '<=' if mf.relation == '>' else '<', 1 - mf.alpha), MarkedFormula(mf.formula.subformulas[1], mf.relation, mf.alpha) ]] return [] class Group3Rule(InferenceRule): """Правила для отрицаний""" def apply(self, mf: MarkedFormula): if mf.formula.connective == '¬': new_rel = {'>': '<=', '>=': '<', '<': '>=', '<=': '>'}.get(mf.relation, mf.relation) return [[MarkedFormula(mf.formula.subformulas[0], new_rel, 1 - mf.alpha)]] return [] class Group4Rule(InferenceRule): """Правила транзитивности с ограничением по существующим термам""" def apply(self, mf: MarkedFormula): if ( mf.formula.connective == '⊆' and mf.relation in ('>', '>=') and not self._contains_placeholder(mf.formula) and self._has_existing_terms(mf) # Новая проверка ): unique_id = uuid.uuid4().hex[:6] new_term = Term(f"X_{unique_id}") return [[ MarkedFormula(Formula(mf.formula.left, new_term, '⊆'), mf.relation, mf.alpha), MarkedFormula(Formula(new_term, mf.formula.right, '⊆'), mf.relation, mf.alpha) ]] return [] def _contains_placeholder(self, formula: Formula) -> bool: """Проверяет, содержит ли формула плейсхолдеры (например, терм X)""" def check_term(term: Term) -> bool: return 'X_' in term.symbol # Проверяем наличие плейсхолдера в терме # Проверяем и левую, и правую части формулы return check_term(formula.left) or check_term(formula.right) def _has_existing_terms(self, mf: MarkedFormula) -> bool: """Проверяет, есть ли в формуле термы из исходного запроса""" original_terms = {'A', 'B', 'C'} # Пример для теста транзитивности def check_term(term: Term): return term.symbol in original_terms or any(check_term(t) for t in term.subterms) return check_term(mf.formula.left) or check_term(mf.formula.right) class Group5Rule(InferenceRule): """Специальные правила для термов""" def apply(self, mf: MarkedFormula): if (mf.formula.connective == '⊆' and mf.formula.left == mf.formula.right and mf.relation in ('<', '<=') and mf.alpha >= 1): return [[]] # Закрытие ветки return [] # -------------------------------------------- # Система вывода с проверкой замкнутости # -------------------------------------------- class TableauxSystem: def __init__(self, max_depth=10): self.rules = [ Group1Rule(), Group2Rule(), Group3Rule(), Group4Rule(), Group5Rule() ] self.max_depth = max_depth # Максимальная глубина ветки def build_table(self, root: MarkedFormula) -> bool: branches = [[root]] step = 0 while branches and step < self.max_depth: current_branch = branches.pop() if self._is_closed(current_branch): continue if self._is_saturated(current_branch): return False new_branches = self._apply_rules(current_branch) branches.extend(new_branches) step += 1 return False # Если достигнут лимит шагов def _is_closed(self, branch: List[MarkedFormula]) -> bool: formulas = set() for mf in branch: formula_key = (mf.formula, mf.relation) inverse_rel = {'<': '>=', '>': '<=', '<=': '>', '>=': '<'}.get(mf.relation) inverse_key = (mf.formula, inverse_rel) # Проверка на противоречия if inverse_key in formulas: return True formulas.add(formula_key) # Дополнительная проверка на противоречие для одинаковых формул с различными знаками отношений if (mf.relation in ('<', '<=') and mf.alpha >= 1) or (mf.relation in ('>', '>=') and mf.alpha <= 0): return True # Обработка специального случая для (A ⊆ A) < 1 if mf.formula.left == mf.formula.right and mf.relation in ('<', '<=') and mf.alpha >= 1: return True return False def _is_saturated(self, branch: List[MarkedFormula]) -> bool: """Проверяет, насыщена ли ветка, то есть не может быть расширена дальше""" # Например, можно считать ветку насыщенной, если она не содержит # новых элементов для применения правил вывода. return all(self._has_no_applicable_rules(mf) for mf in branch) def _has_no_applicable_rules(self, mf: MarkedFormula) -> bool: """Проверяет, нет ли применимых правил вывода для данной формулы""" for rule in self.rules: if rule.apply(mf): return False return True def _apply_rules(self, branch: List[MarkedFormula]) -> List[List[MarkedFormula]]: """Применяет правила вывода к ветке и возвращает новые ветви""" new_branches = [] for mf in branch: for rule in self.rules: new_branches.extend(rule.apply(mf)) return new_branches # -------------------------------------------- # Тестирование сложных примеров # -------------------------------------------- def is_valid_formula(user_input): """ Проверяет, является ли ввод допустимой формулой. """ # Разрешённые символы: отрицание, логические связки, подмножество, скобки, переменные, числа и вероятность pattern = r'^[¬∧∨⊆()A-Z0-9\s&|>.\-]+$' # Проверяем, что строка содержит только допустимые символы if not re.fullmatch(pattern, user_input): return False # Проверяем, что нет запрещённых сочетаний if "⊆ >" in user_input or user_input.count('(') != user_input.count(')'): return False return True def main(): print("Введите формулы. Для завершения ввода введите 'exit'.") while True: user_input = input("Введите формулу: ").strip() if user_input.lower() == 'exit': break if not is_valid_formula(user_input): print("Ошибка: некорректный ввод формулы.") continue # Пропускаем обработку try: # Парсим входную формулу в объект MarkedFormula marked_formula = FormulaParser.parse_marked(user_input) # Создаем систему вывода system = TableauxSystem(max_depth=10) # Строим таблицу для формулы result = system.build_table(marked_formula) if result: print("Формула замкнута (непротиворечива).") else: print("Формула не замкнута (противоречива).") except ValueError as e: print(f"Ошибка: {e}") if __name__ == "__main__": main() Here is an example: Введите формулу: (A ⊆ B & B ⊆ C) > 0.7 Формула не замкнута (противоречива). As I understand it, the answer is wrong, it should be closed. Or is my code correct? Continue reading...