diff --git a/.github/workflows/full-ci.yml b/.github/workflows/full-ci.yml index 111b1a24..018987fb 100644 --- a/.github/workflows/full-ci.yml +++ b/.github/workflows/full-ci.yml @@ -86,9 +86,19 @@ jobs: - uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha }} + - uses: cachix/install-nix-action@v31 + with: + nix_path: nixpkgs=channel:nixos-unstable - uses: actions/setup-go@v3 with: go-version: ${{ env.goVersion }} - run: go install golang.org/x/tools/cmd/goyacc@latest - run: cd src && make - - run: cd devtools && make test-suite + - uses: rrbutani/use-nix-shell-action@v1 + with: + file: shell.nix + script: | + cd devtools + make test-suite + + diff --git a/.gitignore b/.gitignore index c1a48f56..9671578e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +*.lpo + .direnv [Pp]roblems [Oo]utput diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a3632354..db6ba779 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,11 +8,12 @@ wish to contribute to Goéland, you should start by [forking](https://github.com/GoelandProver/Goeland/fork) the repository. Then, you can work on on your feature/bug fix/enhancement in your local repository. -Once you deem your work satisfactory, you should [open a pull -request](https://github.com/GoelandProver/Goeland/compare) **targeting -master**. Then, one of the maintainer will review your code as soon as -possible. If you have no feedback for a few days, do not hesitate to ping one of -them. The current maintainers are: @jcailler, @jrosain. +Once you deem your work satisfactory and have properly updated the test suite +(c.f. [Managing the test suite](#managing-the-test-suite)), you should [open a pull +request](https://github.com/GoelandProver/Goeland/compare) **targeting master**. Then, one +of the maintainer will review your code as soon as possible. If you have no feedback for a +few days, do not hesitate to ping one of them. The current maintainers are: @jcailler, +@jrosain. Your code is expected to (i) build, (ii) satisfy the unit tests and (iii) not prove countertheorems. This check *does not* run automatically. One of the @@ -39,6 +40,25 @@ have a very descriptive error as it will make things easier to debug. Note that, by default, neither of these options `panic`. You have to activate the `-debug` flag in order for them to panic and you to have a backtrace. +### Managing the test suite + +In order to have a systematic testing of Goéland, we have a [test +suite](devtools/test-suite) that contains: +- basic test files to check functionalities, +- bug files that correspond to a reported bug that has been resolved, and +- output files that test the output of Goéland. + +When you add a new functionality to Goéland, you must add some files to the +[basic](devtools/test-suite/basic) folder that tests your newly implemented +functionalities. If your pull request fixes a bug, you must add the bug file to the +[bugs](devtools/test-suite/bugs) folder. Beware that we run the Rocq and Lambdapi output +on the test suite, so you should think about whether a problem is checkable or not. If +it's not, add them in the corresponding `no_chk` instead. The current not-checkable +problems are problems involving a typed context. Moreover, if your problem includes +equalities, the Lambdapi check may fail. If so, add your problem to the +`lp_tolerate_fails` variable in the `run-test-suite` file. + + ## For Maintainers By default, a pull request that modifies the go source code has the `needs:ci` label. You diff --git a/devtools/run-test-suite.py b/devtools/run-test-suite.py index 2b377173..a3383f16 100644 --- a/devtools/run-test-suite.py +++ b/devtools/run-test-suite.py @@ -5,6 +5,7 @@ import sys import re import difflib +import shutil from subprocess import PIPE, run class Parser: @@ -12,6 +13,7 @@ class Parser: RES = "% result: " ENV = "% env: " EXIT_CODE = "% exit: " + no_check = False def __init__(self, filename): self.filename = filename @@ -20,6 +22,10 @@ def __init__(self, filename): self.parseEnv() self.parseExitCode() + args_avoid_chk = ["-proof", "-otptp", "-osctptp"] + if "no_chk" in filename or self.expectedExitCode != "" or any(arg in self.arguments for arg in args_avoid_chk) or self.expectedResult == "NOT VALID": + self.no_check = True + def parseGen(self, pat): with open(self.filename) as f: for line in f.readlines(): @@ -42,24 +48,118 @@ def parseEnv(self): def parseExitCode(self): self.expectedExitCode = self.parseGen(self.EXIT_CODE).strip() - def getCommandLine(self): - return self.env + " ../src/_build/goeland " + self.arguments + " " + self.filename + def getCommandLine(self, checker_args): + arguments = self.arguments + checker_args + return self.env + " ../src/_build/goeland " + arguments + " " + self.filename + + def getArgsForPrinting(self): + chk_str = "" + if self.no_check: + chk_str = " (no check)" + return self.arguments + chk_str def sanitize(s): return s.encode('utf-8', errors='ignore').decode(errors='ignore') -def runProver(command): - print(f"Launching: {command}") +def runProver(f, command): result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True, encoding='utf-8') return (sanitize(result.stdout), sanitize(result.stderr), result.returncode) -def runWithExpected(f, parser): - output, err, exit_code = runProver(parser.getCommandLine()) +def getRelevantOutput(output): + relevantLines = [] + ok = -1 + for line in output.split("\n"): + if re.search("% SZS output start", line): + ok = 1 + elif re.search("% SZS output end", line): + ok = -1 + elif ok == 0: + if len(line.strip()) > 0: + relevantLines.append(line.strip()) + else: + ok -= 1 + + return relevantLines + +def isExecutable(prog) : + return shutil.which(prog) is not None + +def makeGenericCheck(command, extension, cleanup_always, cleanup_compile_success, f, output): + check_lines = getRelevantOutput(output) + check_success = False + filename = os.getcwd() + "/" + os.path.basename(f)[:-2].replace("-", "_") + + with open(f"{filename}.{extension}", "w") as chk_file: + chk_file.write("\n".join(check_lines)) + + result = run(f"{command} {filename}.{extension}", stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True, encoding='utf-8') + check_success = result.returncode == 0 + + for ext in cleanup_always: + os.remove(f"{filename}.{ext}") + + if not check_success: + return False, result.stderr + else: + for ext in cleanup_compile_success: + os.remove(f"{filename}.{ext}") + + return True, None + +def getRocqCompiler() : + if isExecutable("rocq"): + return "rocq compile" + elif isExecutable("coqc"): + return "coqc" + else: + raise Exception("No Rocq executable found on the system") + +def makeRocqCheck(f, output): + check_status, err = makeGenericCheck(getRocqCompiler(), "v", ["glob"], ["v", "vo", "vok", "vos"], f, output) + + if not check_status: + print(f"ROCQ check has failed.") + print(f"Reason: {err}") + exit(1) + +def makeLambdapiCheck(f, output): + lp_command = "lambdapi check --lib-root .. --map-dir Logic.Goeland:../proof-certification/LambdaPi" + check_status, err = makeGenericCheck(lp_command, "lp", [], ["lp"], f, output) + + # As the lambdapi output does not manage equality, we tolerate fails for the problems + # of the test suite that have equality. + lp_tolerated_fails = ["TEST_EQ.p", "TEST_EQ2.p", "sankalp.p"] + + if not check_status: + if os.path.basename(f) in lp_tolerated_fails: + print(f"LAMBDAPI check has failed, but it was expected.") + else: + print(f"LAMBDAPI check has failed") + exit(1) + +def runWithExpected(f, parser, checker_args, check_fun): + """ + Runs Goéland on [f] using the parsed command line, then checks if the output corresponds to the expected one. + This function manages: + - error codes (e.g., it can detect whether Goéland exits with error code i + - results (e.g., VALID, NOT VALID). + + If Goéland runs into an unexpected error, we report it. Moreover, if the kind of expected return is a VALID + result, we run a checker (specified by checker_args and check_fun) to check that the proof is indeed valid + (except for files in the no-chk folder). + """ + output, err, exit_code = runProver(f, parser.getCommandLine("")) if err != "": print(f"Runtime error: {err}") exit(1) + if parser.expectedExitCode != '': + if int(parser.expectedExitCode) != exit_code: + print(f"Error: expected exit code '{parser.expectedExitCode}', got: '{exit_code}'") + exit(1) + else: return + search = re.compile(".*% RES : (.*)$") for line in output.split("\n"): res = search.match(line) @@ -69,37 +169,28 @@ def runWithExpected(f, parser): print(f"Error: expected '{parser.expectedResult}', got: '{actual}'") exit(1) else: + if parser.no_check: return + output, _, _ = runProver(f, parser.getCommandLine(checker_args)) + check_fun(f, output) return - if parser.expectedExitCode != '': - if int(parser.expectedExitCode) != exit_code: - print(f"Error: expected exit code '{parser.expectedExitCode}', got: '{exit_code}'") - exit(1) - else: return - print(f"Unknown error: got\n{output}") exit(1) +def runWithRocqChk(f, parser): + runWithExpected(f, parser, " -context -orocq", makeRocqCheck) + +def runWithLpChk(f, parser): + runWithExpected(f, parser, " -olp", makeLambdapiCheck) + def compareOutputs(f, parser): - output, err, _ = runProver(parser.getCommandLine()) + output, err, exit_code = runProver(f, parser.getCommandLine("")) - if err != "": + if err != "" or exit_code != 0: print(f"Runtime error: {err}") exit(1) - relevantLines = [] - ok = -1 - for line in output.split("\n"): - if re.search("% SZS output start", line): - ok = 1 - elif re.search("% SZS output end", line): - ok = -1 - elif ok == 0: - if len(line.strip()) > 0: - relevantLines.append(line.strip()) - else: - ok -= 1 - + relevantLines = getRelevantOutput(output) relevantExpectedLines = [] with open(os.path.splitext(f)[0] + ".out") as f: @@ -119,10 +210,12 @@ def compareOutputs(f, parser): if __name__ == "__main__": outputTest = ["-proof", "-otptp", "-osctptp"] - for f in glob.glob("test-suite/**/*.p"): + for f in sorted(glob.glob("test-suite/**/*.p")): parser = Parser(f) if any(out in parser.arguments for out in outputTest) : compareOutputs(f, parser) else : - runWithExpected(f, parser) + print(f"{f}\t{parser.getArgsForPrinting()}") + runWithRocqChk(f, parser) + runWithLpChk(f, parser) diff --git a/devtools/test-suite/basic/test-typing-elab-1.p b/devtools/test-suite/basic/test-typing-elab-1.p new file mode 100644 index 00000000..1a650628 --- /dev/null +++ b/devtools/test-suite/basic/test-typing-elab-1.p @@ -0,0 +1,7 @@ +% should fail because $lesseq is a defined function for $int, $rat and $real but is not polymorphic +% for any type +% exit: 1 + +tff(ty_type, type, ty : $tType). + +tff(conj, conjecture, ! [A : ty] : $lesseq(A, A)). diff --git a/devtools/test-suite/basic/test-typing-elab-2.p b/devtools/test-suite/basic/test-typing-elab-2.p new file mode 100644 index 00000000..ad8ea066 --- /dev/null +++ b/devtools/test-suite/basic/test-typing-elab-2.p @@ -0,0 +1,7 @@ +% should fail because $quotient is a defined function for $int, $rat and $real but is not polymorphic +% for any type +% exit: 1 + +tff(ty_type, type, ty : $tType). + +tff(conj, conjecture, ! [A : ty] : $lesseq($quotient(A, A), 1)). diff --git a/devtools/test-suite/basic/test-typing-elab-3.p b/devtools/test-suite/basic/test-typing-elab-3.p new file mode 100644 index 00000000..fed2fe93 --- /dev/null +++ b/devtools/test-suite/basic/test-typing-elab-3.p @@ -0,0 +1,4 @@ +% quotient is defined specifically for integers +% result: NOT VALID + +tff(conj, conjecture, $lesseq($quotient(2, 2), 1)). diff --git a/devtools/test-suite/basic/tf1_syntax_chk.p b/devtools/test-suite/basic/tf1_syntax_chk.p index ddbabeb5..fbddcf04 100644 --- a/devtools/test-suite/basic/tf1_syntax_chk.p +++ b/devtools/test-suite/basic/tf1_syntax_chk.p @@ -1,5 +1,5 @@ -% TODO: args -one_step and result NOT_VALID once typing is working again (this is satisfiable) -% exit: 3 +% args: -one_step +% result: NOT VALID tff(beverage_type,type, beverage: $tType ). diff --git a/devtools/test-suite/basic/tfa_syntax_chk.p b/devtools/test-suite/basic/tfa_syntax_chk.p index bcf3c0bb..aa731dfc 100644 --- a/devtools/test-suite/basic/tfa_syntax_chk.p +++ b/devtools/test-suite/basic/tfa_syntax_chk.p @@ -1,5 +1,5 @@ % As arithmetic is not handled by Goeland, we simply check that parsing is OK -% args: -ari -one_step -l 1 +% args: -one_step -l 1 % result: NOT VALID tff(p_int_type,type, diff --git a/devtools/test-suite/bugs/bug_52-1.p b/devtools/test-suite/bugs/bug_52-1.p new file mode 100644 index 00000000..0c3cd848 --- /dev/null +++ b/devtools/test-suite/bugs/bug_52-1.p @@ -0,0 +1,3 @@ +% result: VALID + +fof(rocq_output_test,conjecture,! [X]: (p(X) | ~p(X))). diff --git a/devtools/test-suite/bugs/bug_52-3.p b/devtools/test-suite/bugs/bug_52-3.p new file mode 100644 index 00000000..4026b2be --- /dev/null +++ b/devtools/test-suite/bugs/bug_52-3.p @@ -0,0 +1,4 @@ +% tests for the presence of metavariables +% result: VALID + +fof(rocq_output_test,conjecture,? [X]: (p(X) | ~p(X))). diff --git a/devtools/test-suite/bugs/bug_53-1.p b/devtools/test-suite/bugs/bug_53-1.p new file mode 100644 index 00000000..942299af --- /dev/null +++ b/devtools/test-suite/bugs/bug_53-1.p @@ -0,0 +1,33 @@ +% args: -one_step +% exit: 1 + +tff(list_type,type, + list: $tType > $tType ). + +tff(maybe_type,type, + maybe: $tType > $tType ). + +%----Polymorphic symbols +tff(nil_type,type, + nil: + !>[A: $tType] : list(A) ). + +tff(cons_type,type, + cons: + !>[A: $tType] : ( ( A * list(A) ) > list(A) ) ). + +tff(none_type,type, + none: + !>[A: $tType] : maybe(A) ). + +tff(some_type,type, + some: + !>[A: $tType] : ( A > maybe(A) ) ). + +tff(head_type,type, + head: + !>[A: $tType] : ( list(A) > maybe(A) ) ). + +%----This cannot be well typed, the last cons is not well formed +tff(solve_this,conjecture, + head($int,cons($int,1,cons($int,2,cons($int,3)))) = some($int,1) ). diff --git a/devtools/test-suite/bugs_no_chk/bug_52-2.p b/devtools/test-suite/bugs_no_chk/bug_52-2.p new file mode 100644 index 00000000..f054cf22 --- /dev/null +++ b/devtools/test-suite/bugs_no_chk/bug_52-2.p @@ -0,0 +1,13 @@ +% TODO: move this file to bugs once we enable typed GS3 proofs +% result: VALID + +tff(nat_type,type,nat : $tType). +tff(zero_nat,type,zero : nat). +tff(succ_nat,type,succ : nat > nat). +tff(list_type,type,list : $tType > $tType). +tff(nil_list,type,nil : !> [A]: list(A)). +tff(cons_list,type,cons : !> [A]: ((A * list(A)) > list(A))). +tff(p_type,type,p : !> [A : $tType]: (list(A) > $o)). + +tff(rocq_output_test,conjecture,! [A: $tType, X : A]: + ((succ(zero) = succ(zero)) | (p(A,cons(A,X,nil(A))) | ~p(A,cons(A,X,nil(A)))))). diff --git a/devtools/test-suite/basic/Axioms/SYN000+0.ax b/devtools/test-suite/no_chk/Axioms/SYN000+0.ax similarity index 100% rename from devtools/test-suite/basic/Axioms/SYN000+0.ax rename to devtools/test-suite/no_chk/Axioms/SYN000+0.ax diff --git a/devtools/test-suite/basic/Axioms/SYN000_0.ax b/devtools/test-suite/no_chk/Axioms/SYN000_0.ax similarity index 100% rename from devtools/test-suite/basic/Axioms/SYN000_0.ax rename to devtools/test-suite/no_chk/Axioms/SYN000_0.ax diff --git a/devtools/test-suite/basic/fol_syntax_chk.p b/devtools/test-suite/no_chk/fol_syntax_chk.p similarity index 100% rename from devtools/test-suite/basic/fol_syntax_chk.p rename to devtools/test-suite/no_chk/fol_syntax_chk.p diff --git a/devtools/test-suite/basic/tf0_syntax_chk.p b/devtools/test-suite/no_chk/tf0_syntax_chk.p similarity index 100% rename from devtools/test-suite/basic/tf0_syntax_chk.p rename to devtools/test-suite/no_chk/tf0_syntax_chk.p diff --git a/devtools/test-suite/proofs/example_sctptp.out b/devtools/test-suite/proofs/example_sctptp.out index 18621ff5..b99a1dfc 100644 --- a/devtools/test-suite/proofs/example_sctptp.out +++ b/devtools/test-suite/proofs/example_sctptp.out @@ -1,29 +1,29 @@ -fof(c_example_sctptp_p, conjecture, ((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))). +fof(c_example_sctptp_p, conjecture, (! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))). -fof(f8, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~((! [X4] : (p(X4)))), ~((? [Y6] : (~(p(Y6))))), ~((~((? [Y6] : (~(p(Y6))))) => (! [X4] : (p(X4))))), ~(p(Sko_0)), ~(~(p(Sko_0))), p(Sko_0)] --> [], inference(leftHyp, [status(thm), 6], [])). +fof(f8, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~(! [X4]: p(X4)), ~(? [Y6]: ~p(Y6)), ~(~(? [Y6]: ~p(Y6)) => (! [X4]: p(X4))), ~p(Sko_0), ~~p(Sko_0), p(Sko_0)] --> [], inference(leftHyp, [status(thm), 6], [])). -fof(f7, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~((! [X4] : (p(X4)))), ~((? [Y6] : (~(p(Y6))))), ~((~((? [Y6] : (~(p(Y6))))) => (! [X4] : (p(X4))))), ~(p(Sko_0)), ~(~(p(Sko_0)))] --> [], inference(leftNotNot, [status(thm), 5], [f8])). +fof(f7, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~(! [X4]: p(X4)), ~(? [Y6]: ~p(Y6)), ~(~(? [Y6]: ~p(Y6)) => (! [X4]: p(X4))), ~p(Sko_0), ~~p(Sko_0)] --> [], inference(leftNotNot, [status(thm), 5], [f8])). -fof(f6, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~((! [X4] : (p(X4)))), ~((? [Y6] : (~(p(Y6))))), ~((~((? [Y6] : (~(p(Y6))))) => (! [X4] : (p(X4))))), ~(p(Sko_0))] --> [], inference(leftNotEx, [status(thm), 2, $fot(Sko_0)], [f7])). +fof(f6, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~(! [X4]: p(X4)), ~(? [Y6]: ~p(Y6)), ~(~(? [Y6]: ~p(Y6)) => (! [X4]: p(X4))), ~p(Sko_0)] --> [], inference(leftNotEx, [status(thm), 2, $fot(Sko_0)], [f7])). -fof(f4, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~((! [X4] : (p(X4)))), ~((? [Y6] : (~(p(Y6))))), ~((~((? [Y6] : (~(p(Y6))))) => (! [X4] : (p(X4)))))] --> [], inference(leftNotAll, [status(thm), 1, 'Sko_0'], [f6])). +fof(f4, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~(! [X4]: p(X4)), ~(? [Y6]: ~p(Y6)), ~(~(? [Y6]: ~p(Y6)) => (! [X4]: p(X4)))] --> [], inference(leftNotAll, [status(thm), 1, 'Sko_0'], [f6])). -fof(f11, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), (! [X4] : (p(X4))), ~(~((? [Y6] : (~(p(Y6)))))), ~(((! [X4] : (p(X4))) => ~((? [Y6] : (~(p(Y6))))))), (? [Y6] : (~(p(Y6)))), ~(p(Sko_1)), p(Sko_1)] --> [], inference(leftHyp, [status(thm), 6], [])). +fof(f11, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ! [X4]: p(X4), ~~(? [Y6]: ~p(Y6)), ~((! [X4]: p(X4)) => ~(? [Y6]: ~p(Y6))), ? [Y6]: ~p(Y6), ~p(Sko_1), p(Sko_1)] --> [], inference(leftHyp, [status(thm), 6], [])). -fof(f10, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), (! [X4] : (p(X4))), ~(~((? [Y6] : (~(p(Y6)))))), ~(((! [X4] : (p(X4))) => ~((? [Y6] : (~(p(Y6))))))), (? [Y6] : (~(p(Y6)))), ~(p(Sko_1))] --> [], inference(leftForall, [status(thm), 1, $fot(Sko_1)], [f11])). +fof(f10, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ! [X4]: p(X4), ~~(? [Y6]: ~p(Y6)), ~((! [X4]: p(X4)) => ~(? [Y6]: ~p(Y6))), ? [Y6]: ~p(Y6), ~p(Sko_1)] --> [], inference(leftForall, [status(thm), 1, $fot(Sko_1)], [f11])). -fof(f9, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), (! [X4] : (p(X4))), ~(~((? [Y6] : (~(p(Y6)))))), ~(((! [X4] : (p(X4))) => ~((? [Y6] : (~(p(Y6))))))), (? [Y6] : (~(p(Y6))))] --> [], inference(leftExists, [status(thm), 4, 'Sko_1'], [f10])). +fof(f9, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ! [X4]: p(X4), ~~(? [Y6]: ~p(Y6)), ~((! [X4]: p(X4)) => ~(? [Y6]: ~p(Y6))), ? [Y6]: ~p(Y6)] --> [], inference(leftExists, [status(thm), 4, 'Sko_1'], [f10])). -fof(f5, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), (! [X4] : (p(X4))), ~(~((? [Y6] : (~(p(Y6)))))), ~(((! [X4] : (p(X4))) => ~((? [Y6] : (~(p(Y6)))))))] --> [], inference(leftNotNot, [status(thm), 2], [f9])). +fof(f5, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ! [X4]: p(X4), ~~(? [Y6]: ~p(Y6)), ~((! [X4]: p(X4)) => ~(? [Y6]: ~p(Y6)))] --> [], inference(leftNotNot, [status(thm), 2], [f9])). -fof(f3ext2, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~((~((? [Y6] : (~(p(Y6))))) => (! [X4] : (p(X4)))))] --> [], inference(leftNotImplies, [status(thm), 1], [f4])). +fof(f3ext2, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~(~(? [Y6]: ~p(Y6)) => (! [X4]: p(X4)))] --> [], inference(leftNotImplies, [status(thm), 1], [f4])). -fof(f3ext1, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~(((! [X4] : (p(X4))) => ~((? [Y6] : (~(p(Y6)))))))] --> [], inference(leftNotImplies, [status(thm), 1], [f5])). +fof(f3ext1, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~((! [X4]: p(X4)) => ~(? [Y6]: ~p(Y6)))] --> [], inference(leftNotImplies, [status(thm), 1], [f5])). -fof(f3, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6)))))))] --> [], inference(leftNotIff, [status(thm), 0], [f3ext1, f3ext2])). +fof(f3, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6)))] --> [], inference(leftNotIff, [status(thm), 0], [f3ext1, f3ext2])). -fof(f2, plain, [((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))] --> [((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))], inference(hyp, [status(thm), 0], [])). +fof(f2, plain, [(! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))] --> [(! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))], inference(hyp, [status(thm), 0], [])). -fof(f1, plain, [] --> [((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6)))))), ~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6)))))))], inference(rightNot, [status(thm), 1], [f2])). +fof(f1, plain, [] --> [(! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6)), ~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6)))], inference(rightNot, [status(thm), 1], [f2])). -fof(f0, plain, [] --> [((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))], inference(cut, [status(thm), 1], [f1, f3])). \ No newline at end of file +fof(f0, plain, [] --> [(! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))], inference(cut, [status(thm), 1], [f1, f3])). diff --git a/devtools/test-suite/proofs/example_sctptp.p b/devtools/test-suite/proofs/example_sctptp.p index 25b76bce..d877b98f 100644 --- a/devtools/test-suite/proofs/example_sctptp.p +++ b/devtools/test-suite/proofs/example_sctptp.p @@ -1,7 +1,5 @@ -% args: -no_id -osctptp +% args: -osctptp % result: VALID fof(test_sctptp, conjecture, (! [X] : p(X)) <=> (~(? [Y] : ~p(Y)))). - - \ No newline at end of file diff --git a/devtools/test-suite/proofs/example_tptp.out b/devtools/test-suite/proofs/example_tptp.out index f574adc7..3ae286e7 100644 --- a/devtools/test-suite/proofs/example_tptp.out +++ b/devtools/test-suite/proofs/example_tptp.out @@ -1,29 +1,29 @@ -fof(c_example_tptp_p, conjecture, ((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))). +fof(c_example_tptp_p, conjecture, (! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))). -fof(f8, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~((! [X4] : (p(X4)))), ~((? [Y6] : (~(p(Y6))))), ~((~((? [Y6] : (~(p(Y6))))) => (! [X4] : (p(X4))))), ~(p(sko_0)), ~(~(p(sko_0))), p(sko_0)] --> [], inference(leftHyp, [status(thm), 6], [])). +fof(f8, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~(! [X4]: p(X4)), ~(? [Y6]: ~p(Y6)), ~(~(? [Y6]: ~p(Y6)) => (! [X4]: p(X4))), ~p(sko_0), ~~p(sko_0), p(sko_0)] --> [], inference(leftHyp, [status(thm), 6], [])). -fof(f7, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~((! [X4] : (p(X4)))), ~((? [Y6] : (~(p(Y6))))), ~((~((? [Y6] : (~(p(Y6))))) => (! [X4] : (p(X4))))), ~(p(sko_0)), ~(~(p(sko_0)))] --> [], inference(leftNotNot, [status(thm), 5], [f8])). +fof(f7, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~(! [X4]: p(X4)), ~(? [Y6]: ~p(Y6)), ~(~(? [Y6]: ~p(Y6)) => (! [X4]: p(X4))), ~p(sko_0), ~~p(sko_0)] --> [], inference(leftNotNot, [status(thm), 5], [f8])). -fof(f6, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~((! [X4] : (p(X4)))), ~((? [Y6] : (~(p(Y6))))), ~((~((? [Y6] : (~(p(Y6))))) => (! [X4] : (p(X4))))), ~(p(sko_0))] --> [], inference(leftNotEx, [status(thm), 2, $fot(sko_0)], [f7])). +fof(f6, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~(! [X4]: p(X4)), ~(? [Y6]: ~p(Y6)), ~(~(? [Y6]: ~p(Y6)) => (! [X4]: p(X4))), ~p(sko_0)] --> [], inference(leftNotEx, [status(thm), 2, $fot(sko_0)], [f7])). -fof(f4, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~((! [X4] : (p(X4)))), ~((? [Y6] : (~(p(Y6))))), ~((~((? [Y6] : (~(p(Y6))))) => (! [X4] : (p(X4)))))] --> [], inference(leftNotAll, [status(thm), 1, 'sko_0'], [f6])). +fof(f4, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~(! [X4]: p(X4)), ~(? [Y6]: ~p(Y6)), ~(~(? [Y6]: ~p(Y6)) => (! [X4]: p(X4)))] --> [], inference(leftNotAll, [status(thm), 1, 'sko_0'], [f6])). -fof(f11, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), (! [X4] : (p(X4))), ~(~((? [Y6] : (~(p(Y6)))))), ~(((! [X4] : (p(X4))) => ~((? [Y6] : (~(p(Y6))))))), (? [Y6] : (~(p(Y6)))), ~(p(sko_1)), p(sko_1)] --> [], inference(leftHyp, [status(thm), 6], [])). +fof(f11, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ! [X4]: p(X4), ~~(? [Y6]: ~p(Y6)), ~((! [X4]: p(X4)) => ~(? [Y6]: ~p(Y6))), ? [Y6]: ~p(Y6), ~p(sko_1), p(sko_1)] --> [], inference(leftHyp, [status(thm), 6], [])). -fof(f10, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), (! [X4] : (p(X4))), ~(~((? [Y6] : (~(p(Y6)))))), ~(((! [X4] : (p(X4))) => ~((? [Y6] : (~(p(Y6))))))), (? [Y6] : (~(p(Y6)))), ~(p(sko_1))] --> [], inference(leftForall, [status(thm), 1, $fot(sko_1)], [f11])). +fof(f10, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ! [X4]: p(X4), ~~(? [Y6]: ~p(Y6)), ~((! [X4]: p(X4)) => ~(? [Y6]: ~p(Y6))), ? [Y6]: ~p(Y6), ~p(sko_1)] --> [], inference(leftForall, [status(thm), 1, $fot(sko_1)], [f11])). -fof(f9, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), (! [X4] : (p(X4))), ~(~((? [Y6] : (~(p(Y6)))))), ~(((! [X4] : (p(X4))) => ~((? [Y6] : (~(p(Y6))))))), (? [Y6] : (~(p(Y6))))] --> [], inference(leftExists, [status(thm), 4, 'sko_1'], [f10])). +fof(f9, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ! [X4]: p(X4), ~~(? [Y6]: ~p(Y6)), ~((! [X4]: p(X4)) => ~(? [Y6]: ~p(Y6))), ? [Y6]: ~p(Y6)] --> [], inference(leftExists, [status(thm), 4, 'sko_1'], [f10])). -fof(f5, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), (! [X4] : (p(X4))), ~(~((? [Y6] : (~(p(Y6)))))), ~(((! [X4] : (p(X4))) => ~((? [Y6] : (~(p(Y6)))))))] --> [], inference(leftNotNot, [status(thm), 2], [f9])). +fof(f5, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ! [X4]: p(X4), ~~(? [Y6]: ~p(Y6)), ~((! [X4]: p(X4)) => ~(? [Y6]: ~p(Y6)))] --> [], inference(leftNotNot, [status(thm), 2], [f9])). -fof(f3ext2, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~((~((? [Y6] : (~(p(Y6))))) => (! [X4] : (p(X4)))))] --> [], inference(leftNotImplies, [status(thm), 1], [f4])). +fof(f3ext2, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~(~(? [Y6]: ~p(Y6)) => (! [X4]: p(X4)))] --> [], inference(leftNotImplies, [status(thm), 1], [f4])). -fof(f3ext1, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))), ~(((! [X4] : (p(X4))) => ~((? [Y6] : (~(p(Y6)))))))] --> [], inference(leftNotImplies, [status(thm), 1], [f5])). +fof(f3ext1, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))), ~((! [X4]: p(X4)) => ~(? [Y6]: ~p(Y6)))] --> [], inference(leftNotImplies, [status(thm), 1], [f5])). -fof(f3, plain, [~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6)))))))] --> [], inference(leftNotIff, [status(thm), 0], [f3ext1, f3ext2])). +fof(f3, plain, [~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6)))] --> [], inference(leftNotIff, [status(thm), 0], [f3ext1, f3ext2])). -fof(f2, plain, [((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))] --> [((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))], inference(hyp, [status(thm), 0], [])). +fof(f2, plain, [(! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))] --> [(! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))], inference(hyp, [status(thm), 0], [])). -fof(f1, plain, [] --> [((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6)))))), ~(((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6)))))))], inference(rightNot, [status(thm), 1], [f2])). +fof(f1, plain, [] --> [(! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6)), ~((! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6)))], inference(rightNot, [status(thm), 1], [f2])). -fof(f0, plain, [] --> [((! [X4] : (p(X4))) <=> ~((? [Y6] : (~(p(Y6))))))], inference(cut, [status(thm), 1], [f1, f3])). \ No newline at end of file +fof(f0, plain, [] --> [(! [X4]: p(X4)) <=> ~(? [Y6]: ~p(Y6))], inference(cut, [status(thm), 1], [f1, f3])). diff --git a/devtools/test-suite/proofs/example_tptp.p b/devtools/test-suite/proofs/example_tptp.p index a7835d7c..7c6928d5 100644 --- a/devtools/test-suite/proofs/example_tptp.p +++ b/devtools/test-suite/proofs/example_tptp.p @@ -1,4 +1,4 @@ -% args: -no_id -otptp +% args: -otptp % result: VALID fof(test_tptp, conjecture, diff --git a/devtools/test-suite/proofs/flatten-1.out b/devtools/test-suite/proofs/flatten-1.out index 8f7c127f..def47b3c 100644 --- a/devtools/test-suite/proofs/flatten-1.out +++ b/devtools/test-suite/proofs/flatten-1.out @@ -1,7 +1,7 @@ -[0] ALPHA_NOT_NOT : ~(~((p_1 & q_2 & ~(p_1)))) - -> [1] (p_1 & q_2 & ~(p_1)) +[0] ALPHA_NOT_NOT : ~~(p & q & ~p) + -> [1] p & q & ~p -[1] ALPHA_AND : (p_1 & q_2 & ~(p_1)) - -> [2] p_1, q_2, ~(p_1) +[1] ALPHA_AND : p & q & ~p + -> [2] p, q, ~p -[2] CLOSURE : p_1 +[2] CLOSURE : p diff --git a/devtools/test-suite/proofs/flatten-2.out b/devtools/test-suite/proofs/flatten-2.out index 09a62e72..4de193ea 100644 --- a/devtools/test-suite/proofs/flatten-2.out +++ b/devtools/test-suite/proofs/flatten-2.out @@ -1,7 +1,7 @@ -[0] ALPHA_NOT_OR : ~((p_1 | q_2 | ~(p_1))) - -> [1] ~(p_1), ~(q_2), ~(~(p_1)) +[0] ALPHA_NOT_OR : ~(p | q | ~p) + -> [1] ~p, ~q, ~~p -[1] ALPHA_NOT_NOT : ~(~(p_1)) - -> [2] p_1 +[1] ALPHA_NOT_NOT : ~~p + -> [2] p -[2] CLOSURE : p_1 +[2] CLOSURE : p diff --git a/devtools/test-suite/proofs/tf1_basic_thm-2.out b/devtools/test-suite/proofs/tf1_basic_thm-2.out new file mode 100644 index 00000000..9f8a3e0e --- /dev/null +++ b/devtools/test-suite/proofs/tf1_basic_thm-2.out @@ -0,0 +1,28 @@ +[0] ALPHA_AND : (! [A13]: head(A13 ; nil(A13 ; )) = none(A13 ; )) & (! [A15, X17, XS19]: head(A15 ; cons(A15 ; X17, XS19)) = some(A15 ; X17)) & ~(! [A21, X23, Y25, Z27]: head(A21 ; cons(A21 ; X23, cons(A21 ; Y25, cons(A21 ; Z27, nil(A21 ; ))))) = some(A21 ; X23)) + -> [1] ! [A13]: head(A13 ; nil(A13 ; )) = none(A13 ; ), ! [A15, X17, XS19]: head(A15 ; cons(A15 ; X17, XS19)) = some(A15 ; X17), ~(! [A21, X23, Y25, Z27]: head(A21 ; cons(A21 ; X23, cons(A21 ; Y25, cons(A21 ; Z27, nil(A21 ; ))))) = some(A21 ; X23)) + +[1] DELTA_NOT_FORALL : ~(! [A21, X23, Y25, Z27]: head(A21 ; cons(A21 ; X23, cons(A21 ; Y25, cons(A21 ; Z27, nil(A21 ; ))))) = some(A21 ; X23)) + -> [2] ~(! [X23, Y25, Z27]: head(skoTy@29 ; cons(skoTy@29 ; X23, cons(skoTy@29 ; Y25, cons(skoTy@29 ; Z27, nil(skoTy@29 ; ))))) = some(skoTy@29 ; X23)) + +[2] DELTA_NOT_FORALL : ~(! [X23, Y25, Z27]: head(skoTy@29 ; cons(skoTy@29 ; X23, cons(skoTy@29 ; Y25, cons(skoTy@29 ; Z27, nil(skoTy@29 ; ))))) = some(skoTy@29 ; X23)) + -> [3] ~(! [Y25, Z27]: head(skoTy@29 ; cons(skoTy@29 ; skolem@X23@0, cons(skoTy@29 ; Y25, cons(skoTy@29 ; Z27, nil(skoTy@29 ; ))))) = some(skoTy@29 ; skolem@X23@0)) + +[3] DELTA_NOT_FORALL : ~(! [Y25, Z27]: head(skoTy@29 ; cons(skoTy@29 ; skolem@X23@0, cons(skoTy@29 ; Y25, cons(skoTy@29 ; Z27, nil(skoTy@29 ; ))))) = some(skoTy@29 ; skolem@X23@0)) + -> [4] ~(! [Z27]: head(skoTy@29 ; cons(skoTy@29 ; skolem@X23@0, cons(skoTy@29 ; skolem@Y25@1, cons(skoTy@29 ; Z27, nil(skoTy@29 ; ))))) = some(skoTy@29 ; skolem@X23@0)) + +[4] DELTA_NOT_FORALL : ~(! [Z27]: head(skoTy@29 ; cons(skoTy@29 ; skolem@X23@0, cons(skoTy@29 ; skolem@Y25@1, cons(skoTy@29 ; Z27, nil(skoTy@29 ; ))))) = some(skoTy@29 ; skolem@X23@0)) + -> [5] ~(head(skoTy@29 ; cons(skoTy@29 ; skolem@X23@0, cons(skoTy@29 ; skolem@Y25@1, cons(skoTy@29 ; skolem@Z27@2, nil(skoTy@29 ; ))))) = some(skoTy@29 ; skolem@X23@0)) + +[5] GAMMA_FORALL : ! [A13]: head(A13 ; nil(A13 ; )) = none(A13 ; ) + -> [6] head(A13 ; nil(A13 ; )) = none(A13 ; ) + +[6] GAMMA_FORALL : ! [A15, X17, XS19]: head(A15 ; cons(A15 ; X17, XS19)) = some(A15 ; X17) + -> [7] ! [X17, XS19]: head(skoTy@29 ; cons(skoTy@29 ; X17, XS19)) = some(skoTy@29 ; X17) + +[7] GAMMA_FORALL : ! [X17, XS19]: head(skoTy@29 ; cons(skoTy@29 ; X17, XS19)) = some(skoTy@29 ; X17) + -> [8] ! [XS19]: head(skoTy@29 ; cons(skoTy@29 ; skolem@X23@0, XS19)) = some(skoTy@29 ; skolem@X23@0) + +[8] GAMMA_FORALL : ! [XS19]: head(skoTy@29 ; cons(skoTy@29 ; skolem@X23@0, XS19)) = some(skoTy@29 ; skolem@X23@0) + -> [9] head(skoTy@29 ; cons(skoTy@29 ; skolem@X23@0, cons(skoTy@29 ; skolem@Y25@1, cons(skoTy@29 ; skolem@Z27@2, nil(skoTy@29 ; ))))) = some(skoTy@29 ; skolem@X23@0) + +[9] CLOSURE : head(skoTy@29 ; cons(skoTy@29 ; skolem@X23@0, cons(skoTy@29 ; skolem@Y25@1, cons(skoTy@29 ; skolem@Z27@2, nil(skoTy@29 ; ))))) = some(skoTy@29 ; skolem@X23@0) diff --git a/devtools/test-suite/proofs/tf1_basic_thm-2.p b/devtools/test-suite/proofs/tf1_basic_thm-2.p new file mode 100644 index 00000000..a814c1b8 --- /dev/null +++ b/devtools/test-suite/proofs/tf1_basic_thm-2.p @@ -0,0 +1,40 @@ +% args: -proof +% result: VALID + +tff(list_type,type, + list: $tType > $tType ). + +tff(maybe_type,type, + maybe: $tType > $tType ). + +%----Polymorphic symbols +tff(nil_type,type, + nil: + !>[A: $tType] : list(A) ). + +tff(cons_type,type, + cons: + !>[A: $tType] : ( ( A * list(A) ) > list(A) ) ). + +tff(none_type,type, + none: + !>[A: $tType] : maybe(A) ). + +tff(some_type,type, + some: + !>[A: $tType] : ( A > maybe(A) ) ). + +tff(head_type,type, + head: + !>[A: $tType] : ( list(A) > maybe(A) ) ). + +%----Use of polymorphic symbols +tff(head_nil,axiom, + ! [A: $tType] : ( head(A,nil(A)) = none(A) )). + +tff(head_cons,axiom, + ! [A: $tType,X : A,XS : list(A)] : ( head(A,cons(A,X,XS)) = some(A,X) ) ). + +%----With integers +tff(solve_this,conjecture, + ! [A: $tType,X : A,Y : A,Z : A] : ( head(A,cons(A,X,cons(A,Y,cons(A,Z,nil(A))))) = some(A,X) ) ). diff --git a/devtools/test-suite/proofs/tf1_basic_thm.out b/devtools/test-suite/proofs/tf1_basic_thm.out new file mode 100644 index 00000000..3a5ce077 --- /dev/null +++ b/devtools/test-suite/proofs/tf1_basic_thm.out @@ -0,0 +1,16 @@ +[0] ALPHA_AND : (! [A14]: head(A14 ; nil(A14 ; )) = none(A14 ; )) & (! [A16, X18, XS20]: head(A16 ; cons(A16 ; X18, XS20)) = some(A16 ; X18)) & ~(head($int ; cons($int ; 1, cons($int ; 2, cons($int ; 3, nil($int ; ))))) = some($int ; 1)) + -> [1] ! [A14]: head(A14 ; nil(A14 ; )) = none(A14 ; ), ! [A16, X18, XS20]: head(A16 ; cons(A16 ; X18, XS20)) = some(A16 ; X18), ~(head($int ; cons($int ; 1, cons($int ; 2, cons($int ; 3, nil($int ; ))))) = some($int ; 1)) + +[1] GAMMA_FORALL : ! [A14]: head(A14 ; nil(A14 ; )) = none(A14 ; ) + -> [2] head(A14 ; nil(A14 ; )) = none(A14 ; ) + +[2] GAMMA_FORALL : ! [A16, X18, XS20]: head(A16 ; cons(A16 ; X18, XS20)) = some(A16 ; X18) + -> [3] ! [X18, XS20]: head($int ; cons($int ; X18, XS20)) = some($int ; X18) + +[3] GAMMA_FORALL : ! [X18, XS20]: head($int ; cons($int ; X18, XS20)) = some($int ; X18) + -> [4] ! [XS20]: head($int ; cons($int ; 1, XS20)) = some($int ; 1) + +[4] GAMMA_FORALL : ! [XS20]: head($int ; cons($int ; 1, XS20)) = some($int ; 1) + -> [5] head($int ; cons($int ; 1, cons($int ; 2, cons($int ; 3, nil($int ; ))))) = some($int ; 1) + +[5] CLOSURE : head($int ; cons($int ; 1, cons($int ; 2, cons($int ; 3, nil($int ; ))))) = some($int ; 1) diff --git a/devtools/test-suite/proofs/tf1_basic_thm.p b/devtools/test-suite/proofs/tf1_basic_thm.p new file mode 100644 index 00000000..5718a0f8 --- /dev/null +++ b/devtools/test-suite/proofs/tf1_basic_thm.p @@ -0,0 +1,40 @@ +% args: -proof +% result: VALID + +tff(list_type,type, + list: $tType > $tType ). + +tff(maybe_type,type, + maybe: $tType > $tType ). + +%----Polymorphic symbols +tff(nil_type,type, + nil: + !>[A: $tType] : list(A) ). + +tff(cons_type,type, + cons: + !>[A: $tType] : ( ( A * list(A) ) > list(A) ) ). + +tff(none_type,type, + none: + !>[A: $tType] : maybe(A) ). + +tff(some_type,type, + some: + !>[A: $tType] : ( A > maybe(A) ) ). + +tff(head_type,type, + head: + !>[A: $tType] : ( list(A) > maybe(A) ) ). + +%----Use of polymorphic symbols +tff(head_nil,axiom, + ! [A: $tType] : ( head(A,nil(A)) = none(A) )). + +tff(head_cons,axiom, + ! [A: $tType,X : A,XS : list(A)] : ( head(A,cons(A,X,XS)) = some(A,X) ) ). + +%----With integers +tff(solve_this,conjecture, + head($int,cons($int,1,cons($int,2,cons($int,3,nil($int))))) = some($int,1) ). diff --git a/LambdaPi/CCC.lp b/proof-certification/LambdaPi/CCC.lp similarity index 100% rename from LambdaPi/CCC.lp rename to proof-certification/LambdaPi/CCC.lp diff --git a/LambdaPi/FOL.lp b/proof-certification/LambdaPi/FOL.lp similarity index 100% rename from LambdaPi/FOL.lp rename to proof-certification/LambdaPi/FOL.lp diff --git a/LambdaPi/GS3.lp b/proof-certification/LambdaPi/GS3.lp similarity index 100% rename from LambdaPi/GS3.lp rename to proof-certification/LambdaPi/GS3.lp diff --git a/LambdaPi/ICC.lp b/proof-certification/LambdaPi/ICC.lp similarity index 100% rename from LambdaPi/ICC.lp rename to proof-certification/LambdaPi/ICC.lp diff --git a/LambdaPi/LL.lp b/proof-certification/LambdaPi/LL.lp similarity index 100% rename from LambdaPi/LL.lp rename to proof-certification/LambdaPi/LL.lp diff --git a/LambdaPi/LL_ND.lp b/proof-certification/LambdaPi/LL_ND.lp similarity index 100% rename from LambdaPi/LL_ND.lp rename to proof-certification/LambdaPi/LL_ND.lp diff --git a/proof-certification/LambdaPi/Makefile b/proof-certification/LambdaPi/Makefile new file mode 100644 index 00000000..0aa80a08 --- /dev/null +++ b/proof-certification/LambdaPi/Makefile @@ -0,0 +1,20 @@ +.POSIX: +SRC = CCC.lp FOL.lp GS3.lp ICC.lp LL.lp LL_ND.lp ND_eps_aux.lp ND_eps_full.lp ND_eps.lp ND.lp +OBJ = $(SRC:.lp=.lpo) +.SUFFIXES: + +all: $(OBJ) + +install: $(OBJ) lambdapi.pkg + lambdapi install lambdapi.pkg $(OBJ) $(SRC) + +uninstall: + lambdapi uninstall lambdapi.pkg + +clean: + rm -f $(OBJ) + +.SUFFIXES: .lp .lpo + +.lp.lpo: + lambdapi check --gen-obj $< diff --git a/LambdaPi/ND.lp b/proof-certification/LambdaPi/ND.lp similarity index 100% rename from LambdaPi/ND.lp rename to proof-certification/LambdaPi/ND.lp diff --git a/LambdaPi/ND_eps.lp b/proof-certification/LambdaPi/ND_eps.lp similarity index 100% rename from LambdaPi/ND_eps.lp rename to proof-certification/LambdaPi/ND_eps.lp diff --git a/LambdaPi/ND_eps_aux.lp b/proof-certification/LambdaPi/ND_eps_aux.lp similarity index 100% rename from LambdaPi/ND_eps_aux.lp rename to proof-certification/LambdaPi/ND_eps_aux.lp diff --git a/LambdaPi/ND_eps_full.lp b/proof-certification/LambdaPi/ND_eps_full.lp similarity index 100% rename from LambdaPi/ND_eps_full.lp rename to proof-certification/LambdaPi/ND_eps_full.lp diff --git a/proof-certification/LambdaPi/README.md b/proof-certification/LambdaPi/README.md new file mode 100644 index 00000000..1caa76e3 --- /dev/null +++ b/proof-certification/LambdaPi/README.md @@ -0,0 +1,12 @@ +# Proof Certification Using Goéland+LambdaPi + +To output a LambdaPi proof of a problem file `problem.p`, use the `-olp` option: +``` +./_build/goeland -olp problem.p +``` + +Assuming you are at the root of your local clone of this GitHub repo, checking this file +can be done using the following command: +``` +lambdapi check --lib-root . --map-dir Logic.Goeland:proof-certification/LambdaPi problem.lp +``` diff --git a/LambdaPi/lambdapi.pkg b/proof-certification/LambdaPi/lambdapi.pkg similarity index 100% rename from LambdaPi/lambdapi.pkg rename to proof-certification/LambdaPi/lambdapi.pkg diff --git a/proof-certification/README.md b/proof-certification/README.md new file mode 100644 index 00000000..a851dab1 --- /dev/null +++ b/proof-certification/README.md @@ -0,0 +1,5 @@ +# Proof Certification + +This directory contains all the files that are necessary for Goéland to translate its +proof in different languages. We provide a small documentation of their usage: +* for LambdaPi, see [this file](LambdaPi/README.md) diff --git a/shell.nix b/shell.nix index 121645eb..97d4cf1a 100644 --- a/shell.nix +++ b/shell.nix @@ -7,6 +7,7 @@ pkgs.mkShell { gotools python314 rocq-core + rocqPackages.stdlib ocamlPackages.lambdapi ]; } diff --git a/src/Typing/wf_rules.go b/src/AST/form-list.go similarity index 63% rename from src/Typing/wf_rules.go rename to src/AST/form-list.go index 6ed30f64..8c023ac8 100644 --- a/src/Typing/wf_rules.go +++ b/src/AST/form-list.go @@ -30,38 +30,34 @@ * knowledge of the CeCILL license and that you accept its terms. **/ -package Typing - /** - * This file defines the WF rules. - **/ +* This file contains utility functions for list of formulas +**/ -/* WF1 rule first empties the variables, and then the types. */ -func applyWF2(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - root.appliedRule = "WF_2" +package AST - // Try to empty vars first - if len(state.localContext.vars) > 0 { - // Launch child on the type of the first var - var_, newLocalContext := state.localContext.popVar() - child := []Sequent{ - { - localContext: newLocalContext, - globalContext: state.globalContext, - consequence: Consequence{a: var_.GetTypeApp()}, - }, - } - return launchChildren(child, root, fatherChan) +import ( + "github.com/GoelandProver/Goeland/Lib" +) + +// ex-name: ReplaceMetaByTerm +func LsSubstByTerm(formulas Lib.List[Form], meta Meta, term Term) Lib.List[Form] { + for i, f := range formulas.GetSlice() { + formulas.Upd(i, f.ReplaceMetaByTerm(meta, term)) } + return formulas +} + +func LsFlatten(formulas Lib.List[Form]) Lib.List[Form] { + result := Lib.NewList[Form]() - // Then, if vars is not empty, empty the types - _, newLocalContext := state.localContext.popTypeVar() - child := []Sequent{ - { - localContext: newLocalContext, - globalContext: state.globalContext, - consequence: Consequence{a: metaType}, - }, + for _, form := range formulas.GetSlice() { + if typed, ok := form.(And); ok { + result.Append(LsFlatten(typed.GetChildFormulas()).GetSlice()...) + } else { + result.Append(form) + } } - return launchChildren(child, root, fatherChan) + + return result } diff --git a/src/AST/formsDef.go b/src/AST/formsDef.go index e6839766..15894989 100644 --- a/src/AST/formsDef.go +++ b/src/AST/formsDef.go @@ -37,8 +37,7 @@ package AST import ( - "strings" - + "fmt" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) @@ -46,10 +45,10 @@ import ( // ----------------------------------------------------------------------------- // Utility functions -func getAllSubFormulasAppended(f Form) *FormList { - subforms := NewFormList(f.Copy()) - for _, sf := range f.GetChildFormulas().Slice() { - subforms.Append(sf.GetSubFormulasRecur().Slice()...) +func getAllSubFormulasAppended(f Form) Lib.List[Form] { + subforms := Lib.MkListV(f.Copy()) + for _, sf := range f.GetChildFormulas().GetSlice() { + subforms.Append(sf.GetSubFormulasRecur().GetSlice()...) } return subforms } @@ -57,14 +56,14 @@ func getAllSubFormulasAppended(f Form) *FormList { func substVarByMetaInFormList( old Var, new Meta, - formList *FormList, + formList Lib.List[Form], metas Lib.Set[Meta], -) (replacedFormList *FormList, newMetas Lib.Set[Meta]) { - replacedFormList = NewFormList() +) (replacedFormList Lib.List[Form], newMetas Lib.Set[Meta]) { + replacedFormList = Lib.NewList[Form]() newMetas = metas.Copy() found := false - for _, form := range formList.Slice() { + for _, form := range formList.GetSlice() { replacedForm := form.SubstituteVarByMeta(old, new) replacedFormList.Append(replacedForm) @@ -87,27 +86,26 @@ type All struct { quantifier } -func MakeAllSimple(i int, vars []Var, forms Form, metas Lib.Set[Meta]) All { - return All{makeQuantifier(i, vars, forms, metas, AllQuant)} +func MakeAllSimple(i int, vars Lib.List[TypedVar], forms Form, metas Lib.Set[Meta]) All { + return All{makeQuantifier(i, vars, forms, metas, ConnAll)} } -func MakeAll(i int, vars []Var, forms Form) All { +func MakeAll(i int, vars Lib.List[TypedVar], forms Form) All { return MakeAllSimple(i, vars, forms, Lib.EmptySet[Meta]()) } -func MakerAll(vars []Var, forms Form) All { +func MakerAll(vars Lib.List[TypedVar], forms Form) All { return MakeAll(MakerIndexFormula(), vars, forms) } func (a All) Equals(other any) bool { if typed, ok := other.(All); ok { - return AreEqualsVarList(a.GetVarList(), typed.GetVarList()) && a.GetForm().Equals(typed.GetForm()) + return a.quantifier.Equals(typed.quantifier) } - return false } -func (a All) GetSubFormulasRecur() *FormList { +func (a All) GetSubFormulasRecur() Lib.List[Form] { return getAllSubFormulasAppended(a) } @@ -119,15 +117,15 @@ func (a All) RenameVariables() Form { return All{a.quantifier.renameVariables()} } -func (a All) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return All{a.quantifier.replaceTypeByMeta(varList, index)} -} - func (a All) ReplaceTermByTerm(old Term, new Term) (Form, bool) { quant, isReplaced := a.quantifier.replaceTermByTerm(old, new) return All{quant}, isReplaced } +func (a All) SubstTy(old TyGenVar, new Ty) Form { + return All{a.quantifier.replaceTyVar(old, new)} +} + func (a All) SubstituteVarByMeta(old Var, new Meta) Form { return All{a.quantifier.substituteVarByMeta(old, new)} } @@ -143,27 +141,26 @@ type Ex struct { quantifier } -func MakeExSimple(i int, vars []Var, forms Form, metas Lib.Set[Meta]) Ex { - return Ex{makeQuantifier(i, vars, forms, metas, ExQuant)} +func MakeExSimple(i int, vars Lib.List[TypedVar], forms Form, metas Lib.Set[Meta]) Ex { + return Ex{makeQuantifier(i, vars, forms, metas, ConnEx)} } -func MakeEx(i int, vars []Var, forms Form) Ex { +func MakeEx(i int, vars Lib.List[TypedVar], forms Form) Ex { return MakeExSimple(i, vars, forms, Lib.EmptySet[Meta]()) } -func MakerEx(vars []Var, forms Form) Ex { +func MakerEx(vars Lib.List[TypedVar], forms Form) Ex { return MakeEx(MakerIndexFormula(), vars, forms) } func (e Ex) Equals(other any) bool { if typed, ok := other.(Ex); ok { - return AreEqualsVarList(e.GetVarList(), typed.GetVarList()) && e.GetForm().Equals(typed.GetForm()) + return e.quantifier.Equals(typed.quantifier) } - return false } -func (e Ex) GetSubFormulasRecur() *FormList { +func (e Ex) GetSubFormulasRecur() Lib.List[Form] { return getAllSubFormulasAppended(e) } @@ -175,15 +172,15 @@ func (e Ex) RenameVariables() Form { return Ex{e.quantifier.renameVariables()} } -func (e Ex) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return Ex{e.quantifier.replaceTypeByMeta(varList, index)} -} - func (e Ex) ReplaceTermByTerm(old Term, new Term) (Form, bool) { quant, isReplaced := e.quantifier.replaceTermByTerm(old, new) return Ex{quant}, isReplaced } +func (e Ex) SubstTy(old TyGenVar, new Ty) Form { + return Ex{e.quantifier.replaceTyVar(old, new)} +} + func (e Ex) SubstituteVarByMeta(old Var, new Meta) Form { return Ex{e.quantifier.substituteVarByMeta(old, new)} } @@ -192,162 +189,26 @@ func (e Ex) ReplaceMetaByTerm(meta Meta, term Term) Form { return Ex{e.quantifier.replaceMetaByTerm(meta, term)} } -// ----------------------------------------------------------------------------- -// Π-types - -type AllType struct { - *MappedString - index int - tvList []TypeVar - form Form - metas Lib.Cache[Lib.Set[Meta], AllType] -} - -func MakeAllTypeSimple( - i int, - typeVars []TypeVar, - form Form, - metas Lib.Set[Meta], -) AllType { - fms := &MappedString{} - at := AllType{ - fms, - i, - typeVars, - form, - Lib.MkCache(metas, AllType.forceGetMetas), - } - fms.MappableString = &at - return at -} - -func MakeAllType(i int, typeVars []TypeVar, form Form) AllType { - return MakeAllTypeSimple(i, typeVars, form, Lib.EmptySet[Meta]()) -} - -func MakerAllType(typeVars []TypeVar, form Form) AllType { - return MakeAllType(MakerIndexFormula(), typeVars, form) -} - -/* Methods */ - -func (a AllType) GetIndex() int { return a.index } -func (a AllType) GetVarList() []TypeVar { return copyTypeVarList(a.tvList) } -func (a AllType) GetForm() Form { return a.form.Copy() } -func (a AllType) GetType() TypeScheme { return DefaultPropType(0) } - -/* Form interface */ - -func (a AllType) ToMappedString(mapping MapString, displayTypes bool) string { - return mapping[QuantVarOpen] + Glob.ListToString(a.GetVarList(), ", ", "") + " : " + mapping[TypeVarType] + mapping[QuantVarClose] + mapping[QuantVarSep] + " (" + a.GetForm().ToString() + ")" -} - -func (a AllType) ToString() string { - return a.MappedString.ToString() -} - -func (a AllType) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "(" + mapping[AllTypeQuant] + " " + mapping[QuantVarOpen] + Glob.ListToString(a.GetVarList(), ", ", "") + " : " + mapping[TypeVarType] + mapping[QuantVarClose] + mapping[QuantVarSep] + " (%s))" -} - -func (a AllType) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return "", "" -} - -func (a AllType) GetChildrenForMappedString() []MappableString { - return a.GetChildFormulas().ToMappableStringSlice() -} - -func (a AllType) forceGetMetas() Lib.Set[Meta] { - return a.GetForm().GetMetas() -} - -func (a AllType) GetMetas() Lib.Set[Meta] { - return a.metas.Get(a) -} - -func (a AllType) Copy() Form { - fms := &MappedString{} - at := AllType{ - fms, - a.index, - copyTypeVarList(a.tvList), - a.form.Copy(), - a.metas.Copy(Lib.Set[Meta].Copy), - } - fms.MappableString = &at - return at -} - -func (a AllType) Equals(f any) bool { - oth, isAll := f.(AllType) - return isAll && - AreEqualsTypeVarList(a.tvList, oth.tvList) && - a.form.Equals(oth.form) -} - -func (a AllType) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeAllType(a.GetIndex(), a.tvList, a.GetForm().ReplaceTypeByMeta(varList, index)) -} - -func (a AllType) ReplaceTermByTerm(old Term, new Term) (Form, bool) { - f, res := a.GetForm().ReplaceTermByTerm(old, new) - na := MakeAllTypeSimple(a.GetIndex(), a.GetVarList(), f, a.metas.Raw()) - if !res && !a.metas.NeedsUpd() { - na.metas.AvoidUpd() - } - return na, res -} - -func (a AllType) RenameVariables() Form { - return MakeAllType(a.GetIndex(), a.GetVarList(), a.GetForm().RenameVariables()) -} - -func (a AllType) GetSubTerms() Lib.List[Term] { - return a.GetForm().GetSubTerms() -} - -func (a AllType) SubstituteVarByMeta(old Var, new Meta) Form { - f := a.GetForm().SubstituteVarByMeta(old, new) - return MakeAllTypeSimple(a.index, a.tvList, f, a.metas.Raw()) -} - -func (a AllType) GetSubFormulasRecur() *FormList { - return getAllSubFormulasAppended(a) -} - -func (a AllType) GetChildFormulas() *FormList { - return NewFormList(a.GetForm()) -} - -func (e AllType) ReplaceMetaByTerm(meta Meta, term Term) Form { - return MakeAllType(e.GetIndex(), e.GetVarList(), e.GetForm().ReplaceMetaByTerm(meta, term)) -} - // ----------------------------------------------------------------------------- // Or type Or struct { - *MappedString index int - *FormList + forms Lib.List[Form] metas Lib.Cache[Lib.Set[Meta], Or] } /** Constructors **/ -func MakeOrSimple(i int, forms *FormList, metas Lib.Set[Meta]) Or { - fms := &MappedString{} - or := Or{fms, i, forms, Lib.MkCache(metas, Or.forceGetMetas)} - fms.MappableString = &or - return or +func MakeOrSimple(i int, forms Lib.List[Form], metas Lib.Set[Meta]) Or { + return Or{i, forms, Lib.MkCache(metas, Or.forceGetMetas)} } -func MakeOr(i int, forms *FormList) Or { +func MakeOr(i int, forms Lib.List[Form]) Or { return MakeOrSimple(i, forms, Lib.EmptySet[Meta]()) } -func MakerOr(forms *FormList) Or { +func MakerOr(forms Lib.List[Form]) Or { return MakeOr(MakerIndexFormula(), forms) } @@ -360,21 +221,17 @@ func (o Or) GetIndex() int { } func (o Or) forceGetMetas() Lib.Set[Meta] { - return metasUnion(o.FormList) + return metasUnion(o.forms) } func (o Or) GetMetas() Lib.Set[Meta] { return o.metas.Get(o) } -func (o Or) GetType() TypeScheme { - return DefaultPropType(0) -} - func (o Or) GetSubTerms() Lib.List[Term] { res := Lib.NewList[Term]() - for _, tl := range o.FormList.Slice() { + for _, tl := range o.forms.GetSlice() { res.Add(TermEquals, tl.GetSubTerms().GetSlice()...) } @@ -383,43 +240,26 @@ func (o Or) GetSubTerms() Lib.List[Term] { func (o Or) Equals(f any) bool { oth, isOr := f.(Or) - return isOr && oth.FormList.Equals(o.FormList) + return isOr && Lib.ListEquals(oth.forms, o.forms) } func (o Or) Copy() Form { - fms := &MappedString{} - or := Or{ - fms, + return Or{ o.index, - o.FormList.Copy(), + Lib.ListCpy(o.forms), o.metas.Copy(Lib.Set[Meta].Copy), } - fms.MappableString = &or - return or } func (o Or) ToString() string { - return o.MappedString.ToString() -} - -func (o Or) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "(%s)" -} - -func (o Or) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return " " + mapping[OrConn] + " ", "" -} - -func (o Or) GetChildrenForMappedString() []MappableString { - return o.GetChildFormulas().ToMappableStringSlice() -} - -func (o Or) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeOr(o.GetIndex(), replaceList(o.FormList, varList, index)) + return o.forms.ToString( + func(f Form) string { return printer.Str(printer.SurroundChild(f.ToString())) }, + printer.StrConn(ConnOr), "", + ) } func (o Or) ReplaceTermByTerm(old Term, new Term) (Form, bool) { - formList, res := replaceTermInFormList(o.FormList, old, new) + formList, res := replaceTermInFormList(o.forms, old, new) no := MakeOrSimple(o.GetIndex(), formList, o.metas.Raw()) if !res && !o.metas.NeedsUpd() { no.metas.AvoidUpd() @@ -427,59 +267,61 @@ func (o Or) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return no, res } +func (o Or) SubstTy(old TyGenVar, new Ty) Form { + formList := replaceTyVarInFormList(o.forms, old, new) + return MakeOrSimple(o.GetIndex(), formList, o.metas.Raw()) +} + func (o Or) RenameVariables() Form { - return MakeOr(o.GetIndex(), renameFormList(o.FormList)) + return MakeOr(o.GetIndex(), renameFormList(o.forms)) } func (o Or) SubstituteVarByMeta(old Var, new Meta) Form { - newFormList, newMetas := substVarByMetaInFormList(old, new, o.FormList, o.metas.Raw()) + newFormList, newMetas := substVarByMetaInFormList(old, new, o.forms, o.metas.Raw()) return MakeOrSimple(o.index, newFormList, newMetas) } -func (o Or) GetSubFormulasRecur() *FormList { +func (o Or) GetSubFormulasRecur() Lib.List[Form] { return getAllSubFormulasAppended(o) } -func (o Or) GetChildFormulas() *FormList { - return o.FormList +func (o Or) GetChildFormulas() Lib.List[Form] { + return o.forms } func (o Or) ReplaceMetaByTerm(meta Meta, term Term) Form { - return MakeOr(o.GetIndex(), o.FormList.ReplaceMetaByTerm(meta, term)) + return MakeOr(o.GetIndex(), LsSubstByTerm(o.forms, meta, term)) } // ----------------------------------------------------------------------------- // And type And struct { - *MappedString index int - *FormList + forms Lib.List[Form] metas Lib.Cache[Lib.Set[Meta], And] } /** Constructors **/ -func MakeAndSimple(i int, forms *FormList, metas Lib.Set[Meta]) And { - fms := &MappedString{} - and := And{fms, i, forms, Lib.MkCache(metas, And.forceGetMetas)} - fms.MappableString = &and - return and +func MakeAndSimple(i int, forms Lib.List[Form], metas Lib.Set[Meta]) And { + return And{i, forms, Lib.MkCache(metas, And.forceGetMetas)} } -func MakeAndSimpleBinary(i int, forms *FormList, metas Lib.Set[Meta]) And { +func MakeAndSimpleBinary(i int, forms Lib.List[Form], metas Lib.Set[Meta]) And { switch forms.Len() { + // FIXME: case 0 and 1 should error, no? case 0, 1, 2: return MakeAndSimple(i, forms, metas) default: return MakeAndSimple( i, - NewFormList([]Form{forms.Get(0), MakerAnd(NewFormList(forms.GetElements(1, forms.Len())...), true)}...), + Lib.MkListV[Form](forms.At(0), MakerAnd(forms.Slice(1, forms.Len()), true)), metas) } } -func MakeAnd(i int, forms *FormList, binary ...bool) And { +func MakeAnd(i int, forms Lib.List[Form], binary ...bool) And { if binary != nil { return MakeAndSimpleBinary(i, forms, Lib.EmptySet[Meta]()) } else { @@ -487,7 +329,7 @@ func MakeAnd(i int, forms *FormList, binary ...bool) And { } } -func MakerAnd(forms *FormList, binary ...bool) And { +func MakerAnd(forms Lib.List[Form], binary ...bool) And { return MakeAnd(MakerIndexFormula(), forms, binary...) } @@ -500,21 +342,17 @@ func (a And) GetIndex() int { } func (a And) forceGetMetas() Lib.Set[Meta] { - return metasUnion(a.FormList) + return metasUnion(a.forms) } func (a And) GetMetas() Lib.Set[Meta] { return a.metas.Get(a) } -func (a And) GetType() TypeScheme { - return DefaultPropType(0) -} - func (a And) GetSubTerms() Lib.List[Term] { res := Lib.NewList[Term]() - for _, tl := range a.FormList.Slice() { + for _, tl := range a.forms.GetSlice() { res.Add(TermEquals, tl.GetSubTerms().GetSlice()...) } @@ -523,46 +361,29 @@ func (a And) GetSubTerms() Lib.List[Term] { func (a And) Equals(other any) bool { if typed, ok := other.(And); ok { - return typed.FormList.Equals(a.FormList) + return Lib.ListEquals(typed.forms, a.forms) } return false } func (a And) Copy() Form { - fms := &MappedString{} - and := And{ - fms, + return And{ a.index, - a.FormList.Copy(), + Lib.ListCpy(a.forms), a.metas.Copy(Lib.Set[Meta].Copy), } - fms.MappableString = &and - return and } func (a And) ToString() string { - return a.MappedString.ToString() -} - -func (a And) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "(%s)" -} - -func (a And) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return " " + mapping[AndConn] + " ", "" -} - -func (a And) GetChildrenForMappedString() []MappableString { - return a.GetChildFormulas().ToMappableStringSlice() -} - -func (a And) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeAnd(a.GetIndex(), replaceList(a.FormList, varList, index)) + return a.forms.ToString( + func(f Form) string { return printer.Str(printer.SurroundChild(f.ToString())) }, + printer.StrConn(ConnAnd), "", + ) } func (a And) ReplaceTermByTerm(old Term, new Term) (Form, bool) { - varList, res := replaceTermInFormList(a.FormList, old, new) + varList, res := replaceTermInFormList(a.forms, old, new) na := MakeAndSimple(a.index, varList, a.metas.Raw()) if !res && !a.metas.NeedsUpd() { na.metas.AvoidUpd() @@ -570,48 +391,48 @@ func (a And) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return na, res } +func (a And) SubstTy(old TyGenVar, new Ty) Form { + formList := replaceTyVarInFormList(a.forms, old, new) + return MakeAndSimple(a.GetIndex(), formList, a.metas.Raw()) +} + func (a And) RenameVariables() Form { - return MakeAnd(a.GetIndex(), renameFormList(a.FormList)) + return MakeAnd(a.GetIndex(), renameFormList(a.forms)) } func (a And) SubstituteVarByMeta(old Var, new Meta) Form { - newFormList, newMetas := substVarByMetaInFormList(old, new, a.FormList, a.metas.Raw()) + newFormList, newMetas := substVarByMetaInFormList(old, new, a.forms, a.metas.Raw()) return MakeAndSimple(a.index, newFormList, newMetas) } -func (a And) GetSubFormulasRecur() *FormList { +func (a And) GetSubFormulasRecur() Lib.List[Form] { return getAllSubFormulasAppended(a) } -func (a And) GetChildFormulas() *FormList { - return a.FormList +func (a And) GetChildFormulas() Lib.List[Form] { + return a.forms } func (a And) ReplaceMetaByTerm(meta Meta, term Term) Form { - return MakeAnd(a.GetIndex(), a.FormList.ReplaceMetaByTerm(meta, term)) + return MakeAnd(a.GetIndex(), LsSubstByTerm(a.forms, meta, term)) } // ----------------------------------------------------------------------------- // Equivalence type Equ struct { - *MappedString index int f1, f2 Form metas Lib.Cache[Lib.Set[Meta], Equ] } func MakeEquSimple(i int, firstForm, secondForm Form, metas Lib.Set[Meta]) Equ { - fms := &MappedString{} - equ := Equ{ - fms, + return Equ{ i, firstForm, secondForm, Lib.MkCache(metas, Equ.forceGetMetas), } - fms.MappableString = &equ - return equ } func MakeEqu(i int, firstForm, secondForm Form) Equ { @@ -622,32 +443,16 @@ func MakerEqu(firstForm, secondForm Form) Equ { return MakeEqu(MakerIndexFormula(), firstForm, secondForm) } -func (e Equ) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "(%s)" -} - -func (e Equ) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return " " + mapping[EquConn] + " ", "" -} - -func (e Equ) GetChildrenForMappedString() []MappableString { - return e.GetChildFormulas().ToMappableStringSlice() -} - func (e Equ) GetIndex() int { return e.index } func (e Equ) GetF1() Form { return e.f1.Copy() } func (e Equ) GetF2() Form { return e.f2.Copy() } func (e Equ) Copy() Form { - fms := &MappedString{} - equ := Equ{ - fms, + return Equ{ e.index, e.GetF1(), e.GetF2(), e.metas.Copy(Lib.Set[Meta].Copy), } - fms.MappableString = &equ - return equ } func (e Equ) forceGetMetas() Lib.Set[Meta] { @@ -661,8 +466,13 @@ func (e Equ) GetMetas() Lib.Set[Meta] { return e.metas.Get(e) } -func (e Equ) GetType() TypeScheme { return DefaultPropType(0) } -func (e Equ) ToString() string { return e.ToMappedString(DefaultMapString, true) } +func (e Equ) ToString() string { + return printer.Str(fmt.Sprintf("%s %s %s", + printer.Str(printer.SurroundChild(e.f1.ToString())), + printer.StrConn(ConnEqu), + printer.Str(printer.SurroundChild(e.f2.ToString())), + )) +} func (e Equ) Equals(f any) bool { oth, isEqu := f.(Equ) @@ -670,10 +480,6 @@ func (e Equ) Equals(f any) bool { e.f1.Equals(oth.f1) && e.f2.Equals(oth.f2) } -func (e Equ) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeEqu(e.GetIndex(), e.GetF1().ReplaceTypeByMeta(varList, index), e.GetF2().ReplaceTypeByMeta(varList, index)) -} - func (e Equ) ReplaceTermByTerm(old Term, new Term) (Form, bool) { f1, res1 := e.GetF1().ReplaceTermByTerm(old, new) f2, res2 := e.GetF2().ReplaceTermByTerm(old, new) @@ -686,6 +492,15 @@ func (e Equ) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return ne, res1 || res2 } +func (e Equ) SubstTy(old TyGenVar, new Ty) Form { + return MakeEquSimple( + e.GetIndex(), + e.f1.SubstTy(old, new), + e.f2.SubstTy(old, new), + e.metas.Raw(), + ) +} + func (e Equ) RenameVariables() Form { return MakeEqu(e.GetIndex(), e.GetF1().RenameVariables(), e.GetF2().RenameVariables()) } @@ -698,16 +513,16 @@ func (e Equ) GetSubTerms() Lib.List[Term] { } func (e Equ) SubstituteVarByMeta(old Var, new Meta) Form { - fl, metas := substVarByMetaInFormList(old, new, NewFormList(e.f1, e.f2), e.metas.Raw()) - return MakeEquSimple(e.index, fl.Get(0), fl.Get(1), metas) + fl, metas := substVarByMetaInFormList(old, new, Lib.MkListV(e.f1, e.f2), e.metas.Raw()) + return MakeEquSimple(e.index, fl.At(0), fl.At(1), metas) } -func (e Equ) GetSubFormulasRecur() *FormList { +func (e Equ) GetSubFormulasRecur() Lib.List[Form] { return getAllSubFormulasAppended(e) } -func (e Equ) GetChildFormulas() *FormList { - return NewFormList(e.f1, e.f2) +func (e Equ) GetChildFormulas() Lib.List[Form] { + return Lib.MkListV(e.f1, e.f2) } func (e Equ) ReplaceMetaByTerm(meta Meta, term Term) Form { @@ -718,23 +533,18 @@ func (e Equ) ReplaceMetaByTerm(meta Meta, term Term) Form { // Implication type Imp struct { - *MappedString index int f1, f2 Form metas Lib.Cache[Lib.Set[Meta], Imp] } func MakeImpSimple(i int, firstForm, secondForm Form, metas Lib.Set[Meta]) Imp { - fms := &MappedString{} - imp := Imp{ - fms, + return Imp{ i, firstForm, secondForm, Lib.MkCache(metas, Imp.forceGetMetas), } - fms.MappableString = &imp - return imp } func MakeImp(i int, firstForm, secondForm Form) Imp { @@ -745,32 +555,16 @@ func MakerImp(firstForm, secondForm Form) Imp { return MakeImp(MakerIndexFormula(), firstForm, secondForm) } -func (i Imp) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "(%s)" -} - -func (i Imp) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return " " + mapping[ImpConn] + " ", "" -} - -func (i Imp) GetChildrenForMappedString() []MappableString { - return i.GetChildFormulas().ToMappableStringSlice() -} - func (i Imp) GetIndex() int { return i.index } func (i Imp) GetF1() Form { return i.f1.Copy() } func (i Imp) GetF2() Form { return i.f2.Copy() } func (i Imp) Copy() Form { - fms := &MappedString{} - imp := Imp{ - fms, + return Imp{ i.index, i.GetF1(), i.GetF2(), i.metas.Copy(Lib.Set[Meta].Copy), } - fms.MappableString = &imp - return imp } func (i Imp) forceGetMetas() Lib.Set[Meta] { @@ -784,8 +578,13 @@ func (i Imp) GetMetas() Lib.Set[Meta] { return i.metas.Get(i) } -func (i Imp) GetType() TypeScheme { return DefaultPropType(0) } -func (i Imp) ToString() string { return i.ToMappedString(DefaultMapString, true) } +func (i Imp) ToString() string { + return printer.Str(fmt.Sprintf("%s %s %s", + printer.Str(printer.SurroundChild(i.f1.ToString())), + printer.StrConn(ConnImp), + printer.Str(printer.SurroundChild(i.f2.ToString())), + )) +} func (i Imp) Equals(other any) bool { if typed, ok := other.(Imp); ok { @@ -795,10 +594,6 @@ func (i Imp) Equals(other any) bool { return false } -func (i Imp) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeImp(i.GetIndex(), i.GetF1().ReplaceTypeByMeta(varList, index), i.GetF2().ReplaceTypeByMeta(varList, index)) -} - func (i Imp) ReplaceTermByTerm(old Term, new Term) (Form, bool) { f1, res1 := i.GetF1().ReplaceTermByTerm(old, new) f2, res2 := i.GetF2().ReplaceTermByTerm(old, new) @@ -812,6 +607,15 @@ func (i Imp) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return ni, res1 || res2 } +func (i Imp) SubstTy(old TyGenVar, new Ty) Form { + return MakeImpSimple( + i.GetIndex(), + i.f1.SubstTy(old, new), + i.f2.SubstTy(old, new), + i.metas.Raw(), + ) +} + func (i Imp) RenameVariables() Form { return MakeImp(i.GetIndex(), i.GetF1().RenameVariables(), i.GetF2().RenameVariables()) } @@ -824,16 +628,16 @@ func (i Imp) GetSubTerms() Lib.List[Term] { } func (i Imp) SubstituteVarByMeta(old Var, new Meta) Form { - fl, metas := substVarByMetaInFormList(old, new, NewFormList(i.f1, i.f2), i.metas.Raw()) - return MakeImpSimple(i.index, fl.Get(0), fl.Get(1), metas) + fl, metas := substVarByMetaInFormList(old, new, Lib.MkListV(i.f1, i.f2), i.metas.Raw()) + return MakeImpSimple(i.index, fl.At(0), fl.At(1), metas) } -func (i Imp) GetSubFormulasRecur() *FormList { +func (i Imp) GetSubFormulasRecur() Lib.List[Form] { return getAllSubFormulasAppended(i) } -func (i Imp) GetChildFormulas() *FormList { - return NewFormList(i.f1, i.f2) +func (i Imp) GetChildFormulas() Lib.List[Form] { + return Lib.MkListV(i.f1, i.f2) } func (i Imp) ReplaceMetaByTerm(meta Meta, term Term) Form { @@ -844,7 +648,6 @@ func (i Imp) ReplaceMetaByTerm(meta Meta, term Term) Form { // Not type Not struct { - *MappedString index int f Form metas Lib.Cache[Lib.Set[Meta], Not] @@ -853,10 +656,7 @@ type Not struct { /** Constructors **/ func MakeNotSimple(i int, form Form, metas Lib.Set[Meta]) Not { - fms := &MappedString{} - not := Not{fms, i, form, Lib.MkCache(metas, Not.forceGetMetas)} - fms.MappableString = ¬ - return not + return Not{i, form, Lib.MkCache(metas, Not.forceGetMetas)} } func MakeNot(i int, form Form) Not { @@ -883,10 +683,6 @@ func (n Not) GetMetas() Lib.Set[Meta] { return n.metas.Get(n) } -func (n Not) GetType() TypeScheme { - return DefaultPropType(0) -} - func (n Not) GetSubTerms() Lib.List[Term] { return n.GetForm().GetSubTerms() } @@ -908,23 +704,10 @@ func (n Not) Copy() Form { } func (n Not) ToString() string { - return n.MappedString.ToString() -} - -func (n Not) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return mapping[NotConn] + "(%s)" -} - -func (n Not) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return "", "" -} - -func (n Not) GetChildrenForMappedString() []MappableString { - return n.GetChildFormulas().ToMappableStringSlice() -} - -func (n Not) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakeNot(n.GetIndex(), n.f.ReplaceTypeByMeta(varList, index)) + return printer.Str(fmt.Sprintf("%s%s", + printer.StrConn(ConnNot), + printer.Str(printer.SurroundChild(n.f.ToString())), + )) } func (n Not) ReplaceTermByTerm(old Term, new Term) (Form, bool) { @@ -938,6 +721,14 @@ func (n Not) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return nn, res } +func (n Not) SubstTy(old TyGenVar, new Ty) Form { + return MakeNotSimple( + n.GetIndex(), + n.f.SubstTy(old, new), + n.metas.Raw(), + ) +} + func (n Not) RenameVariables() Form { return MakeNot(n.GetIndex(), n.f.RenameVariables()) } @@ -957,12 +748,12 @@ func (n Not) SubstituteVarByMeta(old Var, new Meta) Form { return MakeNotSimple(n.index, f, f.GetMetas().Copy()) } -func (n Not) GetSubFormulasRecur() *FormList { +func (n Not) GetSubFormulasRecur() Lib.List[Form] { return getAllSubFormulasAppended(n) } -func (n Not) GetChildFormulas() *FormList { - return NewFormList(n.GetForm()) +func (n Not) GetChildFormulas() Lib.List[Form] { + return Lib.MkListV(n.GetForm()) } /** Utils **/ @@ -996,127 +787,78 @@ func getDeepFormWithoutNot(form Form, isEven bool) (Form, bool) { // Predicates type Pred struct { - *MappedString - index int - id Id - args Lib.List[Term] - typeVars []TypeApp - typeHint TypeScheme - metas Lib.Cache[Lib.Set[Meta], Pred] + index int + id Id + tys Lib.List[Ty] + args Lib.List[Term] + metas Lib.Cache[Lib.Set[Meta], Pred] } func MakePredSimple( index int, id Id, + tys Lib.List[Ty], terms Lib.List[Term], - typeApps []TypeApp, metas Lib.Set[Meta], - typeSchemes ...TypeScheme, ) Pred { - var ts TypeScheme - // FIXME: this condition is very suspect - if len(typeSchemes) == 1 { - ts = typeSchemes[0] - } else { - ts = DefaultPropType(terms.Len()) - } - fms := &MappedString{} - pred := Pred{ - fms, + return Pred{ index, id, + tys, terms, - typeApps, - ts, Lib.MkCache(metas, Pred.forceGetMetas), } - fms.MappableString = &pred - return pred } func MakePred( index int, id Id, + tys Lib.List[Ty], terms Lib.List[Term], - typeApps []TypeApp, - typeSchemes ...TypeScheme, ) Pred { return MakePredSimple( index, id, + tys, terms, - typeApps, Lib.EmptySet[Meta](), - typeSchemes..., ) } func MakerPred( id Id, + tys Lib.List[Ty], terms Lib.List[Term], - typeApps []TypeApp, - typeSchemes ...TypeScheme, ) Pred { - return MakePred(MakerIndexFormula(), id, terms, typeApps, typeSchemes...) + return MakePred(MakerIndexFormula(), id, tys, terms) } /* Pred attributes getters */ func (p Pred) GetIndex() int { return p.index } func (p Pred) GetID() Id { return p.id.Copy().(Id) } +func (p Pred) GetTyArgs() Lib.List[Ty] { return p.tys } func (p Pred) GetArgs() Lib.List[Term] { return p.args } -func (p Pred) GetTypeVars() []TypeApp { return CopyTypeAppList(p.typeVars) } /* Formula methods */ -func (p Pred) GetType() TypeScheme { return p.typeHint } func (p Pred) RenameVariables() Form { return p } func (p Pred) ToString() string { - return p.MappedString.ToString() -} - -func (p Pred) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - if len(p.typeVars) == 0 && p.GetArgs().Len() == 0 { - return p.GetID().ToMappedString(mapping, displayTypes) + "%s" - } - args := []string{} - - if len(p.typeVars) > 0 { - if tv := Glob.ListToString(p.typeVars, ", ", mapping[PredEmpty]); tv != "" { - args = append(args, tv) - } - } - args = append(args, "%s") - - if p.GetID().GetName() == "=" { - return "(" + strings.Join(args, " "+mapping[PredTypeVarSep]+" ") + ")" - } - - return p.GetID().ToMappedString(mapping, displayTypes) + "(" + strings.Join(args, " "+mapping[PredTypeVarSep]+" ") + ")" -} - -func (p Pred) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - if p.GetID().GetName() == "=" { - return " = ", mapping[PredEmpty] - } - - return ", ", mapping[PredEmpty] -} - -func (p Pred) GetChildrenForMappedString() []MappableString { - mappableStringList := Lib.ListMap(p.GetArgs(), Glob.To[MappableString]) - return mappableStringList.GetSlice() + return printer.StrFunctional( + p.id, + Lib.ListMap(p.tys, Ty.ToString), + Lib.ListMap(p.args, Term.ToString), + ) } func (p Pred) Copy() Form { np := MakePredSimple( p.index, p.id, + p.GetTyArgs(), p.GetArgs(), - CopyTypeAppList(p.GetTypeVars()), p.metas.Raw().Copy(), - p.GetType(), ) if !p.metas.NeedsUpd() { @@ -1129,9 +871,8 @@ func (p Pred) Copy() Form { func (p Pred) Equals(other any) bool { if typed, ok := other.(Pred); ok { return typed.id.Equals(p.id) && - Lib.ComparableList[TypeApp](p.typeVars).Equals(typed.typeVars) && - Lib.ListEquals(typed.args, p.args) && - p.typeHint.Equals(typed.typeHint) + Lib.ListEquals(typed.tys, p.tys) && + Lib.ListEquals(typed.args, p.args) } return false @@ -1166,25 +907,15 @@ func (p Pred) GetMetaList() Lib.List[Meta] { return metas } -func (p Pred) ReplaceTypeByMeta(varList []TypeVar, index int) Form { - return MakePred( - p.GetIndex(), - p.GetID(), - replaceTermListTypesByMeta(p.GetArgs(), varList, index), - instanciateTypeAppList(p.typeVars, varList, index), p.GetType(), - ) -} - func (p Pred) ReplaceTermByTerm(old Term, new Term) (Form, bool) { termList, res := replaceTermInTermList(p.GetArgs(), old, new) np := MakePredSimple( p.GetIndex(), p.GetID(), + p.GetTyArgs(), termList, - p.GetTypeVars(), p.metas.Raw(), - p.GetType(), ) if !res && !p.metas.NeedsUpd() { @@ -1194,6 +925,24 @@ func (p Pred) ReplaceTermByTerm(old Term, new Term) (Form, bool) { return np, res } +func (p Pred) SubstTy(old TyGenVar, new Ty) Form { + typed_args := Lib.ListMap( + p.tys, + func(t Ty) Ty { return t.SubstTy(old, new) }, + ) + args := Lib.ListMap( + p.args, + func(t Term) Term { return t.SubstTy(old, new) }, + ) + return MakePredSimple( + p.GetIndex(), + p.GetID(), + typed_args, + args, + p.metas.Raw(), + ) +} + func (p Pred) GetSubTerms() Lib.List[Term] { res := Lib.NewList[Term]() @@ -1214,10 +963,9 @@ func (p Pred) SubstituteVarByMeta(old Var, new Meta) Form { return MakePredSimple( nf.index, nf.id, + nf.tys, nf.args, - nf.typeVars, nf.metas.Raw(), - nf.typeHint, ) } return nf @@ -1228,115 +976,77 @@ func (p Pred) SubstituteVarByMeta(old Var, new Meta) Form { return f } -func (p Pred) GetSubFormulasRecur() *FormList { - return NewFormList(p.Copy()) +func (p Pred) GetSubFormulasRecur() Lib.List[Form] { + return Lib.MkListV(p.Copy()) } -func (p Pred) GetChildFormulas() *FormList { - return NewFormList() +func (p Pred) GetChildFormulas() Lib.List[Form] { + return Lib.NewList[Form]() } func (p Pred) ReplaceMetaByTerm(meta Meta, term Term) Form { - newTerms := Lib.MkList[Term](p.args.Len()) - - for i, old := range p.args.GetSlice() { - // FIXME: old.GetName() == meta.GetName() ?? - if old.Equals(meta) { - newTerms.Upd(i, term) - } else { - newTerms.Upd(i, old) - } - } - - return MakePred(p.GetIndex(), p.id, newTerms, p.typeVars, p.GetType()) + return MakePred( + p.GetIndex(), + p.id, + p.tys, + Lib.ListMap(p.args, func(t Term) Term { return t.ReplaceSubTermBy(meta, term) }), + ) } // ----------------------------------------------------------------------------- // True and False type Top struct { - *MappedString index int } func MakeTop(i int) Top { - fms := &MappedString{} - top := Top{fms, i} - fms.MappableString = &top - return top + return Top{i} } func MakerTop() Top { return MakeTop(MakerIndexFormula()) } -func (t Top) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "%s" -} - -func (t Top) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return "", mapping[TopType] -} - -func (t Top) GetChildrenForMappedString() []MappableString { - return t.GetChildFormulas().ToMappableStringSlice() -} - -func (t Top) GetType() TypeScheme { return DefaultPropType(0) } +func (Top) ToString() string { return printer.StrConn(ConnTop) } func (t Top) Copy() Form { return MakeTop(t.GetIndex()) } func (Top) Equals(f any) bool { _, isTop := f.(Top); return isTop } func (Top) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } -func (t Top) ReplaceTypeByMeta([]TypeVar, int) Form { return MakeTop(t.GetIndex()) } func (t Top) ReplaceTermByTerm(Term, Term) (Form, bool) { return MakeTop(t.GetIndex()), false } +func (t Top) SubstTy(TyGenVar, Ty) Form { return t } func (t Top) RenameVariables() Form { return MakeTop(t.GetIndex()) } func (t Top) GetIndex() int { return t.index } func (t Top) GetSubTerms() Lib.List[Term] { return Lib.NewList[Term]() } func (t Top) SubstituteVarByMeta(Var, Meta) Form { return t } func (t Top) GetInternalMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } -func (t Top) GetSubFormulasRecur() *FormList { return NewFormList(t.Copy()) } -func (t Top) GetChildFormulas() *FormList { return NewFormList() } +func (t Top) GetSubFormulasRecur() Lib.List[Form] { return Lib.MkListV[Form](t) } +func (t Top) GetChildFormulas() Lib.List[Form] { return Lib.NewList[Form]() } func (t Top) ReplaceMetaByTerm(meta Meta, term Term) Form { return t } /* Bot (always false) definition */ type Bot struct { - *MappedString index int } func MakeBot(i int) Bot { - fms := &MappedString{} - bot := Bot{fms, i} - fms.MappableString = &bot - return bot + return Bot{i} } func MakerBot() Bot { return MakeBot(MakerIndexFormula()) } -func (b Bot) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "%s" -} - -func (b Bot) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return "", mapping[BotType] -} - -func (b Bot) GetChildrenForMappedString() []MappableString { - return b.GetChildFormulas().ToMappableStringSlice() -} - -func (b Bot) GetType() TypeScheme { return DefaultPropType(0) } +func (Bot) ToString() string { return printer.StrConn(ConnBot) } func (b Bot) Copy() Form { return MakeBot(b.GetIndex()) } func (Bot) Equals(f any) bool { _, isBot := f.(Bot); return isBot } func (Bot) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } -func (b Bot) ReplaceTypeByMeta([]TypeVar, int) Form { return MakeBot(b.GetIndex()) } func (b Bot) ReplaceTermByTerm(Term, Term) (Form, bool) { return MakeBot(b.GetIndex()), false } +func (b Bot) SubstTy(TyGenVar, Ty) Form { return b } func (b Bot) RenameVariables() Form { return MakeBot(b.GetIndex()) } func (b Bot) GetIndex() int { return b.index } func (b Bot) GetSubTerms() Lib.List[Term] { return Lib.NewList[Term]() } func (b Bot) SubstituteVarByMeta(Var, Meta) Form { return b } func (b Bot) GetInternalMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } -func (b Bot) GetSubFormulasRecur() *FormList { return NewFormList(b.Copy()) } -func (b Bot) GetChildFormulas() *FormList { return NewFormList() } +func (b Bot) GetSubFormulasRecur() Lib.List[Form] { return Lib.MkListV[Form](b) } +func (b Bot) GetChildFormulas() Lib.List[Form] { return Lib.NewList[Form]() } func (b Bot) ReplaceMetaByTerm(meta Meta, term Term) Form { return b } diff --git a/src/AST/formula.go b/src/AST/formula.go index 87bb1033..05ceb63b 100644 --- a/src/AST/formula.go +++ b/src/AST/formula.go @@ -46,16 +46,16 @@ import ( type Form interface { GetIndex() int GetMetas() Lib.Set[Meta] - GetType() TypeScheme GetSubTerms() Lib.List[Term] - GetSubFormulasRecur() *FormList - GetChildFormulas() *FormList + GetSubFormulasRecur() Lib.List[Form] + GetChildFormulas() Lib.List[Form] Lib.Copyable[Form] - MappableString + Lib.Stringable + Lib.Comparable - ReplaceTypeByMeta([]TypeVar, int) Form ReplaceTermByTerm(old Term, new Term) (Form, bool) + SubstTy(old TyGenVar, new Ty) Form RenameVariables() Form SubstituteVarByMeta(old Var, new Meta) Form ReplaceMetaByTerm(meta Meta, term Term) Form @@ -91,9 +91,8 @@ func replaceTermInTermList( ) newTermList.Upd(i, MakerFun( nf.GetP(), + nf.GetTyArgs(), termList, - nf.GetTypeVars(), - nf.GetTypeHint(), )) res = res || r } @@ -114,65 +113,42 @@ func replaceTermInTermList( /* Utils */ -func instanciateTypeAppList(typeApps []TypeApp, vars []TypeVar, index int) []TypeApp { - // For each typeVar € nf.GetTypeVars(), if typeVar € varList, instanciate typeVar - typeVars := []TypeApp{} - for _, typeVar := range typeApps { - if Glob.Is[TypeVar](typeVar) { - tv := Glob.To[TypeVar](typeVar) - if Lib.ComparableList[TypeVar](vars).Contains(tv) { - tv.ShouldBeMeta(index) - } - typeVars = append(typeVars, tv) - } else { - typeVars = append(typeVars, typeVar) - } - } - - return typeVars -} - -// Creates and returns a MetaList from a FormList, making sure there are no duplicates -func metasUnion(forms *FormList) Lib.Set[Meta] { +func metasUnion(forms Lib.List[Form]) Lib.Set[Meta] { res := Lib.EmptySet[Meta]() - for _, form := range forms.Slice() { + for _, form := range forms.GetSlice() { res = res.Union(form.GetMetas()) } return res } -// Creates and returns a FormList -func replaceList(oldForms *FormList, vars []TypeVar, index int) *FormList { - newForms := NewFormList() - - for _, form := range oldForms.Slice() { - newForms.Append(form.ReplaceTypeByMeta(vars, index)) - } - - return newForms -} - -func replaceTermInFormList(oldForms *FormList, oldTerm Term, newTerm Term) (*FormList, bool) { - newForms := NewFormList() +// Returns whether the term has been replaced in a subformula or not +func replaceTermInFormList(oldForms Lib.List[Form], oldTerm Term, newTerm Term) (Lib.List[Form], bool) { + newForms := Lib.MkList[Form](oldForms.Len()) res := false - for _, form := range oldForms.Slice() { + for i, form := range oldForms.GetSlice() { newForm, r := form.ReplaceTermByTerm(oldTerm, newTerm) res = res || r - newForms.Append(newForm) + newForms.Upd(i, newForm) } return newForms, res } -// Creates and returns a FormList with its Forms renamed -func renameFormList(forms *FormList) *FormList { - newForms := NewFormList() +func replaceTyVarInFormList(oldForms Lib.List[Form], old TyGenVar, new Ty) Lib.List[Form] { + return Lib.ListMap( + oldForms, + func(f Form) Form { return f.SubstTy(old, new) }, + ) +} + +func renameFormList(forms Lib.List[Form]) Lib.List[Form] { + newForms := Lib.MkList[Form](forms.Len()) - for _, form := range forms.Slice() { - newForms.Append(form.RenameVariables()) + for i, form := range forms.GetSlice() { + newForms.Upd(i, form.RenameVariables()) } return newForms diff --git a/src/AST/maker.go b/src/AST/maker.go index 1289206e..427701e2 100644 --- a/src/AST/maker.go +++ b/src/AST/maker.go @@ -66,15 +66,10 @@ var EmptyPredEq Pred /* Initialization */ func Init() { Reset() - initTypes() Id_eq = MakerId("=") - EmptyPredEq = MakerPred(Id_eq, Lib.NewList[Term](), make([]TypeApp, 0)) - - // Eq/Neq types - tv := MkTypeVar("α") - scheme := MkQuantifiedType([]TypeVar{tv}, MkTypeArrow(MkTypeCross(tv, tv), tv)) - SavePolymorphScheme(Id_eq.GetName(), scheme) - initDefaultMap() + EmptyPredEq = MakerPred(Id_eq, Lib.NewList[Ty](), Lib.NewList[Term]()) + initPrinters() + initTPTPNativeTypes() } /* Reset all the maps and counters */ @@ -113,28 +108,28 @@ func MakerNewId(s string) Id { } /* Var maker */ -func MakerVar(s string, t ...TypeApp) Var { +func MakerVar(s string) Var { lock_term.Lock() i, ok := idVar[s] lock_term.Unlock() if ok { - return MakeVar(i, s, getType(t)) + return MakeVar(i, s) } else { - return MakerNewVar(s, getType(t)) + return MakerNewVar(s) } } -func MakerNewVar(s string, t ...TypeApp) Var { +func MakerNewVar(s string) Var { lock_term.Lock() idVar[s] = cpt_term - vr := MakeVar(cpt_term, s, getType(t)) + vr := MakeVar(cpt_term, s) cpt_term += 1 lock_term.Unlock() return vr } /* Meta maker */ -func MakerMeta(s string, formula int, t ...TypeApp) Meta { +func MakerMeta(s string, formula int, ty Ty) Meta { lock_term.Lock() i, ok := occurenceMeta[s] lock_term.Unlock() @@ -144,39 +139,25 @@ func MakerMeta(s string, formula int, t ...TypeApp) Meta { new_index := cpt_term cpt_term += 1 lock_term.Unlock() - return MakeMeta(new_index, i, s, formula, getType(t)) + return MakeMeta(new_index, i, s, formula, ty) } else { lock_term.Lock() occurenceMeta[s] = 1 new_index := cpt_term cpt_term += 1 lock_term.Unlock() - return MakeMeta(new_index, 0, s, formula, getType(t)) + return MakeMeta(new_index, 0, s, formula, ty) } } /* Const maker (given a id, create a fun without args) */ -func MakerConst(id Id, t ...TypeApp) Fun { - return MakeFun(id, Lib.NewList[Term](), []TypeApp{}, getType(t).(TypeScheme), Lib.EmptySet[Meta]()) +func MakerConst(id Id) Fun { + return MakeFun(id, Lib.NewList[Ty](), Lib.NewList[Term](), Lib.EmptySet[Meta]()) } /* Fun maker, with given id and args */ -func MakerFun(id Id, terms Lib.List[Term], typeVars []TypeApp, t ...TypeScheme) Fun { - var ts TypeScheme - if len(t) == 1 { - ts = t[0] - } else { - ts = DefaultFunType(terms.Len()) - } - return MakeFun(id, terms, typeVars, ts, Lib.EmptySet[Meta]()) -} - -func getType(t []TypeApp) TypeApp { - if len(t) == 1 { - return t[0] - } else { - return DefaultType() - } +func MakerFun(id Id, ty_args Lib.List[Ty], terms Lib.List[Term]) Fun { + return MakeFun(id, ty_args, terms, Lib.EmptySet[Meta]()) } /* Index make for formula */ diff --git a/src/AST/manage_apps_types.go b/src/AST/manage_apps_types.go deleted file mode 100644 index 06b6bbb9..00000000 --- a/src/AST/manage_apps_types.go +++ /dev/null @@ -1,297 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package AST - -import ( - "fmt" - "sync" - - "github.com/GoelandProver/Goeland/Glob" -) - -/** - * This file contains the logic behind the Type Schemes of polymorphic functions - * or predicates. - * A function can have different types of arguments, for example : - * sum: int * int > int - * sum: rat * rat > rat - * but both type schemes should be valid, and kept in memory. - **/ - -/* Maps an application: input type scheme and output type scheme. */ -type App struct { - in TypeApp - out TypeApp - App TypeScheme -} - -/* Map of Type Schemes for a function or a predicate. */ -var typeSchemesMap struct { - tsMap map[string][]App - lock sync.Mutex -} - -var pMap struct { - parametersMap map[string][]TypeApp - lock sync.Mutex -} - -const ( - IsFun = iota - IsProp = iota -) - -/* Saves a TypeScheme in the map of schemes. */ -func SaveTypeScheme(name string, in TypeApp, out TypeApp) error { - tArrow := MkTypeArrow(in, out) - - // If the map contains the name of the function/predicate, a type scheme has already been - // defined for it. It means that the out types shouldn't clash, otherwise, the new type - // scheme is wrong. - tScheme, found := getSchemeFromArgs(name, in) - if tScheme != nil { - if tScheme.Equals(tArrow) { - return nil - } - return fmt.Errorf("trying to save a known type scheme with different return types for the function %s", name) - } - - // It's not in the map, it should be added - typeSchemesMap.lock.Lock() - if found { - typeSchemesMap.tsMap[name] = append(typeSchemesMap.tsMap[name], App{in: in, out: out, App: tArrow}) - } else { - typeSchemesMap.tsMap[name] = []App{{in: in, out: out, App: tArrow}} - } - typeSchemesMap.lock.Unlock() - - return nil -} - -func SavePolymorphScheme(name string, scheme TypeScheme) error { - tScheme, found := getPolymorphSchemeFromArgs(name, scheme) - if tScheme != nil { - if !GetOutType(tScheme).Equals(GetOutType(scheme)) { - return fmt.Errorf("trying to save a known type scheme with different return types for the function %s", name) - } - return nil - } - - // It's not in the map, it should be added - typeSchemesMap.lock.Lock() - if found { - typeSchemesMap.tsMap[name] = append(typeSchemesMap.tsMap[name], App{App: scheme}) - } else { - typeSchemesMap.tsMap[name] = []App{{App: scheme}} - } - typeSchemesMap.lock.Unlock() - - return nil -} - -/* Saves the TypeScheme of a constant function */ -func SaveConstant(name string, out TypeApp) error { - // Check if the constant is already saved in the context - typeSchemesMap.lock.Lock() - if arr, found := typeSchemesMap.tsMap[name]; found { - var err error - if !arr[0].out.Equals(out) { - err = fmt.Errorf("trying to save a known type scheme with different return types for the function %s", name) - } - typeSchemesMap.lock.Unlock() - return err - } - - // Save the constant in the context. - // The line out.(TypeScheme) shouldn't fail : it's never a TypeVar. - typeSchemesMap.tsMap[name] = []App{ - {out: out, App: Glob.To[TypeScheme](out)}, - } - - typeSchemesMap.lock.Unlock() - return nil -} - -/* Checks if the given name is a constant (TypeHint) */ -func IsConstant(name string) bool { - typeSchemesMap.lock.Lock() - _, res := typeSchemesMap.tsMap[name] - typeSchemesMap.lock.Unlock() - return res -} - -/* Gets the TypeScheme from the global context. Returns default type if it doesn't exists. */ -func GetTypeOrDefault(name string, outDefault int, inArgs ...TypeApp) TypeScheme { - typeScheme := GetType(name, inArgs...) - if typeScheme == nil { - var size int - if len(inArgs) == 0 { - size = 0 - } else { - size = inArgs[0].Size() - } - - switch outDefault { - case IsFun: - return DefaultFunType(size) - case IsProp: - return DefaultPropType(size) - } - } - return typeScheme -} - -/* Gets a TypeScheme from the map of schemes with the name. Nil if it doesn't exists in the global context. */ -func GetType(name string, inArgs ...TypeApp) TypeScheme { - if len(inArgs) == 0 { - return getConstantTypeScheme(name) - } - args := inArgs[0] - - if tScheme, _ := getSchemeFromArgs(name, args); tScheme != nil { - return tScheme - } else { - return nil - } -} - -/* Gets a TypeScheme from the map of schemes with the name. Nil if it doesn't exists in the global context. */ -func GetPolymorphicType(name string, lenVars, lenTerms int) TypeScheme { - typeSchemesMap.lock.Lock() - if arr, found := typeSchemesMap.tsMap[name]; found { - for _, fun := range arr { - if fun.App.Size()-1 == lenTerms && (Glob.Is[QuantifiedType](fun.App) && len(fun.App.(QuantifiedType).vars) == lenVars) { - typeSchemesMap.lock.Unlock() - return fun.App - } - } - } - typeSchemesMap.lock.Unlock() - return nil -} - -/* Saves a parameterized type. A TypeApp should be nil if it's unknown */ -func SaveParamereterizedType(name string, types []TypeApp) { - pMap.lock.Lock() - if _, found := pMap.parametersMap[name]; !found { - pMap.parametersMap[name] = types - } - pMap.lock.Unlock() -} - -/* Gets the constants saved in the context */ -func getConstantTypeScheme(name string) TypeScheme { - var tScheme TypeScheme - typeSchemesMap.lock.Lock() - if typeSchemes, found := typeSchemesMap.tsMap[name]; found { - tScheme = typeSchemes[0].App - } else { - // If it's not found, the type is inferred with $i - tScheme = nil - } - typeSchemesMap.lock.Unlock() - return tScheme -} - -/* Returns the TypeScheme from the name & inArgs if it exists in the map. Else, nil. true means fun name is in the map. */ -func getSchemeFromArgs(name string, inArgs TypeApp) (TypeScheme, bool) { - typeSchemesMap.lock.Lock() - if arr, found := typeSchemesMap.tsMap[name]; found { - for _, fun := range arr { - // Polymorphic schemes don't have any of them. - if fun.in == nil || !Glob.Is[TypeScheme](inArgs) { - continue - } - if fun.in.Equals(inArgs) { - typeSchemesMap.lock.Unlock() - return fun.App, true - } - } - typeSchemesMap.lock.Unlock() - return nil, true - } - typeSchemesMap.lock.Unlock() - return nil, false -} - -/* Returns the TypeScheme from the name & inArgs if it exists in the map. Else, nil. true means fun name is in the map. */ -func getPolymorphSchemeFromArgs(name string, scheme TypeScheme) (TypeScheme, bool) { - typeSchemesMap.lock.Lock() - if arr, found := typeSchemesMap.tsMap[name]; found { - for _, fun := range arr { - if GetInputType(fun.App).Equals(GetInputType(scheme)) { - typeSchemesMap.lock.Unlock() - return fun.App, true - } - } - typeSchemesMap.lock.Unlock() - return nil, true - } - typeSchemesMap.lock.Unlock() - return nil, false -} - -/* Returns the global context. Use this only in polyrules. */ -func GetGlobalContext() map[string][]App { - // Get type schemes - typeSchemesMap.lock.Lock() - globalContext := make(map[string][]App) - - for name, app := range typeSchemesMap.tsMap { - globalContext[name] = make([]App, len(app)) - copy(globalContext[name], app) - } - - typeSchemesMap.lock.Unlock() - // Add TypeHints - tMap.lock.Lock() - for name, type_ := range tMap.uidsMap { - globalContext[name] = []App{{App: type_}} - } - tMap.lock.Unlock() - - // Add parameterized types - pMap.lock.Lock() - for name := range pMap.parametersMap { - globalContext[name] = []App{} - } - pMap.lock.Unlock() - return globalContext -} - -func IsPrimitive(name string) bool { - tMap.lock.Lock() - _, found := tMap.uidsMap[name] - tMap.lock.Unlock() - return found -} diff --git a/src/AST/mapped_strings.go b/src/AST/mapped_strings.go deleted file mode 100644 index 1496913e..00000000 --- a/src/AST/mapped_strings.go +++ /dev/null @@ -1,172 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** -* This file provides things. -**/ - -package AST - -import ( - "fmt" - "strings" - - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -type FormulaType int -type MapString map[FormulaType]string - -const ( - AndConn FormulaType = iota - OrConn - ImpConn - EquConn - NotConn - TopType - BotType - AllQuant - ExQuant - AllTypeQuant - QuantVarOpen - QuantVarClose - QuantVarSep - PredEmpty - PredTypeVarSep - TypeVarType -) - -var DefaultMapString = make(map[FormulaType]string) - -func initDefaultMap() { - if Glob.IsPrettyPrint() { - DefaultMapString[AndConn] = "∧" - DefaultMapString[OrConn] = "∨" - DefaultMapString[ImpConn] = "⇒" - DefaultMapString[EquConn] = "⇔" - DefaultMapString[NotConn] = "¬" - DefaultMapString[TopType] = "⊤" - DefaultMapString[BotType] = "⊥" - DefaultMapString[AllQuant] = "∀" - DefaultMapString[ExQuant] = "∃" - DefaultMapString[AllTypeQuant] = "∀" - DefaultMapString[PredEmpty] = "∅" - } else { - DefaultMapString[AndConn] = "&" - DefaultMapString[OrConn] = "|" - DefaultMapString[ImpConn] = "=>" - DefaultMapString[EquConn] = "<=>" - DefaultMapString[NotConn] = "~" - DefaultMapString[TopType] = "$true" - DefaultMapString[BotType] = "$false" - DefaultMapString[AllQuant] = "!" - DefaultMapString[ExQuant] = "?" - DefaultMapString[AllTypeQuant] = ">!" - DefaultMapString[PredEmpty] = "" - } - DefaultMapString[QuantVarOpen] = "[" - DefaultMapString[QuantVarClose] = "]" - DefaultMapString[QuantVarSep] = ":" - DefaultMapString[PredTypeVarSep] = ";" - DefaultMapString[TypeVarType] = "$tType" -} - -type MappableString interface { - Glob.Stringable - Lib.Comparable - - ToMappedString(MapString, bool) string - ToMappedStringSurround(MapString, bool) string - //Return the separator for each child as 1st return, and if there are no children, return the value as 2nd return - ToMappedStringChild(MapString, bool) (separator string, emptyValue string) - GetChildrenForMappedString() []MappableString -} - -type MappedString struct { - MappableString -} - -func (fms MappedString) ToString() string { - return fms.ToMappedString(DefaultMapString, true) -} - -func (fms MappedString) ToMappedString(mapping MapString, displayType bool) string { - surround := fms.ToMappedStringSurround(mapping, displayType) - separator, emptyValue := fms.ToMappedStringChild(mapping, displayType) - children := ListToMappedString(fms.GetChildrenForMappedString(), separator, emptyValue, mapping, displayType) - return fmt.Sprintf(surround, children) -} - -func ListToMappedString[T MappableString](sgbl []T, separator, emptyValue string, mapping MapString, displayTypes bool) string { - strArr := []string{} - - for _, element := range sgbl { - strArr = append(strArr, element.ToMappedString(mapping, displayTypes)) - } - - if len(strArr) == 0 && emptyValue != "" { - strArr = append(strArr, emptyValue) - } - - return strings.Join(strArr, separator) -} - -type SimpleStringMappable string - -func (ssm *SimpleStringMappable) ToString() string { - return string(*ssm) -} - -func (ssm *SimpleStringMappable) Equals(other any) bool { - if typed, ok := other.(*SimpleStringMappable); ok { - return string(*typed) == string(*ssm) - } - - return false -} - -func (ssm *SimpleStringMappable) ToMappedString(MapString, bool) string { - return string(*ssm) -} - -func (ssm *SimpleStringMappable) ToMappedStringSurround(MapString, bool) string { - return "" -} - -func (ssm *SimpleStringMappable) ToMappedStringChild(MapString, bool) (separator string, emptyValue string) { - return "", "" -} - -func (ssm *SimpleStringMappable) GetChildrenForMappedString() []MappableString { - return []MappableString{} -} diff --git a/src/AST/modular-printing.go b/src/AST/modular-printing.go new file mode 100644 index 00000000..97d886e5 --- /dev/null +++ b/src/AST/modular-printing.go @@ -0,0 +1,370 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file provides: + * 1. an interface of modular printers + * 2. printers for multiple outputs (default one, TPTP, Rocq, etc) + * + * A modular printer is composed of two objects: + * - the PrinterAction object that defines a *function* to apply on e.g., ids, variables, everything, etc + * so that generic transformation of stuff can be applied. These actions can be composed (e.g., if you + * wish to avoid printing IDs and also sanitize your string, you can get a PrinterAction that does both + * by using noIdAction.Compose(sanitizeAction)). Note that the operations are not always commutative, + * it is your responsibility to ensure that stuff is composed in the right order. + * + * - the PrinterConnective object that defines all the connectives and a printer for them. A PrinterConnective + * can inherit from another one, and if a connective isn't defined for it, it will search for it in its parent + * connective. All PrinterConnective should inherit from the default one (where everything is defined) by default. + * + * If you wish to implement a new printer, simply provide a PrinterAction and a PrinterConnective to it. +**/ + +package AST + +import ( + "fmt" + "strings" + "unicode" + "unicode/utf8" + + "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" +) + +var printer_debug Glob.Debugger + +type PrinterAction struct { + genericAction func(string) string // Always executed + actionOnId func(Id) string + actionOnBoundVar func(string, int) string + actionOnMeta func(string, int) string + actionOnType func(string) string + actionOnTypedVar func(Lib.Pair[string, Ty]) string + actionOnFunctional func(id Id, tys Lib.List[string], args Lib.List[string]) string +} + +func (p PrinterAction) Compose(oth PrinterAction) PrinterAction { + return PrinterAction{ + genericAction: func(s string) string { return oth.genericAction(p.genericAction(s)) }, + actionOnId: func(i Id) string { return oth.actionOnId(MakeId(i.index, p.actionOnId(i))) }, + actionOnBoundVar: func(name string, index int) string { + return oth.actionOnBoundVar(p.actionOnBoundVar(name, index), index) + }, + actionOnMeta: func(name string, index int) string { + return oth.actionOnMeta(p.actionOnMeta(name, index), index) + }, + actionOnType: func(name string) string { + return oth.actionOnType(p.actionOnType(name)) + }, + actionOnTypedVar: func(pair Lib.Pair[string, Ty]) string { + return oth.actionOnTypedVar(Lib.MkPair(p.actionOnTypedVar(pair), pair.Snd)) + }, + actionOnFunctional: func(id Id, tys Lib.List[string], args Lib.List[string]) string { + return p.actionOnFunctional(id, tys, args) // we can't compose that + }, + } +} + +func (p PrinterAction) Str(s string) string { + return p.genericAction(s) +} + +func (p PrinterAction) StrId(i Id) string { + return p.Str(p.actionOnId(i)) +} + +func (p PrinterAction) StrBound(name string, index int) string { + return p.Str(p.actionOnBoundVar(name, index)) +} + +func (p PrinterAction) StrMeta(name string, index int) string { + return p.Str(p.actionOnMeta(name, index)) +} + +func (p PrinterAction) StrTy(name string) string { + return p.Str(p.actionOnType(name)) +} + +func (p PrinterAction) StrTyVar(pair Lib.Pair[string, Ty]) string { + return p.Str(p.actionOnTypedVar(pair)) +} + +func (p PrinterAction) StrFunctional(i Id, tys, args Lib.List[string]) string { + return p.Str(p.actionOnFunctional(i, tys, args)) +} + +func PrinterIdentity(x string) string { return x } +func PrinterIdentityPair[T any](p Lib.Pair[string, T]) string { return p.Fst } +func PrinterIdentity2[T any](s string, _ T) string { return s } + +func MkPrinterAction( + genericAction func(string) string, + actionOnId func(Id) string, + actionOnBoundVar func(string, int) string, + actionOnMeta func(string, int) string, + actionOnType func(string) string, + actionOnTypedVar func(Lib.Pair[string, Ty]) string, + actionOnFunctional func(id Id, tys Lib.List[string], args Lib.List[string]) string, +) PrinterAction { + return PrinterAction{genericAction, actionOnId, actionOnBoundVar, actionOnMeta, actionOnType, actionOnTypedVar, actionOnFunctional} +} + +type Connective int + +type PrinterConnective struct { + name string + connectives map[Connective]string + inherit Lib.Option[PrinterConnective] +} + +func (p *PrinterConnective) StrConn(conn Connective) string { + var default_connective PrinterConnective + switch connective := p.inherit.(type) { + case Lib.None[PrinterConnective]: + default_connective = DefaultPrinterConnectives() + p.inherit = Lib.MkSome(default_connective) + case Lib.Some[PrinterConnective]: + default_connective = connective.Val + } + + if val, ok := p.connectives[conn]; ok { + printer_debug( + Lib.MkLazy(func() string { return fmt.Sprintf("Found connective %d in %s as %s", conn, p.name, val) })) + return val + } else { + if p.name == DefaultPrinterConnectives().name { + Glob.Anomaly( + "printer", + fmt.Sprintf("Connective %d not found in default connective", conn), + ) + } + } + + printer_debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Connective %d not found in %s, trying in %s", conn, p.name, default_connective.name) + })) + return default_connective.StrConn(conn) +} + +func (p PrinterConnective) SurroundQuantified(s string) string { + return fmt.Sprintf("%s%s%s", p.StrConn(SurQuantStart), s, p.StrConn(SurQuantEnd)) +} + +func (p PrinterConnective) SurroundArgs(s string) string { + if len(s) == 0 { + return s + } + return fmt.Sprintf("%s%s%s", p.StrConn(SurFunctionalStart), s, p.StrConn(SurFunctionalEnd)) +} + +func (p PrinterConnective) SurroundChild(s string) string { + return fmt.Sprintf("%s%s%s", p.StrConn(SurComplexChildStart), s, p.StrConn(SurComplexChildEnd)) +} + +type Printer struct { + PrinterAction + *PrinterConnective +} + +func (c PrinterConnective) DefaultOnFunctionalArgs(id Id, tys Lib.List[string], args Lib.List[string]) string { + infix := Lib.MkListV(Id_eq) + is_infix := Lib.ListMem(id, infix) + types := strings.Join(tys.GetSlice(), c.StrConn(SepTyArgs)) + arguments := strings.Join(args.GetSlice(), c.StrConn(SepArgs)) + + if is_infix { + if args.Len() != 2 { + Glob.Anomaly("Printer", fmt.Sprintf( + "invalid number of infix arguments: expected 2, got %d (in %s)", + args.Len(), + arguments, + )) + } + return fmt.Sprintf("%s %s %s", args.At(0), id.ToString(), args.At(1)) + } else { + if tys.Len() > 0 { + arguments = types + c.StrConn(SepArgsTyArgs) + arguments + } + return fmt.Sprintf("%s%s", id.ToString(), c.SurroundArgs(arguments)) + } +} + +func MkPrinterConnective(name string, connective_map map[Connective]string) PrinterConnective { + return PrinterConnective{ + name: name, + connectives: connective_map, + inherit: Lib.MkNone[PrinterConnective](), + } +} + +const ( + // Formula connectives + ConnAll Connective = iota + ConnEx + ConnAnd + ConnOr + ConnImp + ConnEqu + ConnNot + ConnTop + ConnBot + + // Type connectives + ConnPi + ConnMap + ConnProd + + SepVarsForm // separator between variables and a formula in quantifiers + SepArgs // separator of arguments in functionals + SepTyArgs // separator of type arguments in functionals + SepArgsTyArgs // separator between type arguments and arguments in functionals + SepTyVars // separator between typed variables (in quantifiers) + SepVarTy // separator between a var and its type (in quantifiers) + + SurQuantStart // Stuff that surrounds the variables of quantifiers + SurQuantEnd + SurFunctionalStart // Stuff that surrounds the arguments of functionals + SurFunctionalEnd + SurComplexChildStart // Surrounds "complex" child of formula/type (e.g. (A * B) > C) + SurComplexChildEnd +) + +func DefaultPrinterConnectives() PrinterConnective { + return MkPrinterConnective( + "DefaultPrinterConnective", + map[Connective]string{ + ConnAll: "!", + ConnEx: "?", + ConnAnd: " & ", + ConnOr: " | ", + ConnImp: "=>", + ConnEqu: "<=>", + ConnNot: "~", + ConnTop: "$true", + ConnBot: "$false", + + ConnPi: "!>", + ConnMap: ">", + ConnProd: "*", + + SepVarsForm: ": ", + SepArgs: ", ", + SepTyArgs: ", ", + SepArgsTyArgs: " ; ", + SepTyVars: ", ", + SepVarTy: ": ", + + SurQuantStart: "[", + SurQuantEnd: "]", + SurFunctionalStart: "(", + SurFunctionalEnd: ")", + SurComplexChildStart: "(", + SurComplexChildEnd: ")", + }, + ) +} + +var ( + printer Printer + PrettyPrinter Printer + PrintIDAction PrinterAction + + QuoteID PrinterAction +) + +func initPrinters() { + printer_debug = Glob.CreateDebugger("printer") + + default_connectives := DefaultPrinterConnectives() + printer = Printer{RemoveSuperfluousParenthesesAction(default_connectives), &default_connectives} + + prettyPrinterConnectives := MkPrinterConnective( + "PrettyPrinterConnective", + map[Connective]string{ + ConnAll: "∀", + ConnEx: "∃", + ConnAnd: " ∧ ", + ConnOr: " ∨ ", + ConnImp: "⇒", + ConnEqu: "⇔", + ConnNot: "¬", + ConnTop: "⊤", + ConnBot: "⊥", + + ConnPi: "Π", + ConnMap: "→", + ConnProd: "×", + }, + ) + + PrettyPrinter = Printer{ + RemoveSuperfluousParenthesesAction(prettyPrinterConnectives), + &prettyPrinterConnectives, + } + + PrintIDAction = PrinterAction{ + genericAction: PrinterIdentity, + actionOnId: func(i Id) string { return fmt.Sprintf("%s_%d", i.name, i.index) }, + actionOnBoundVar: PrinterIdentity2[int], + actionOnMeta: PrinterIdentity2[int], + actionOnType: PrinterIdentity, + actionOnTypedVar: PrinterIdentityPair[Ty], + } + + QuoteID = PrinterAction{ + genericAction: PrinterIdentity, + actionOnId: func(i Id) string { + r, _ := utf8.DecodeRuneInString(i.name) + if unicode.IsUpper(r) { + return fmt.Sprintf("'%s'", i.name) + } + return i.name + }, + actionOnBoundVar: PrinterIdentity2[int], + actionOnMeta: PrinterIdentity2[int], + actionOnType: PrinterIdentity, + actionOnTypedVar: PrinterIdentityPair[Ty], + } +} + +func ComposePrinter(p PrinterAction) { + printer.PrinterAction = printer.Compose(p) +} + +func GetPrinter() Printer { + return printer +} + +func SetPrinter(p Printer) { + printer = p +} diff --git a/src/AST/parameterizedtype.go b/src/AST/parameterizedtype.go deleted file mode 100644 index 5b2d4a42..00000000 --- a/src/AST/parameterizedtype.go +++ /dev/null @@ -1,163 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares one of the basic types used for typing the prover : - * ParameterizedType, a type which is parameterized with other types. - **/ - -package AST - -import ( - "strings" - - "fmt" - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * Parameterized Type (TypeApp + TypeScheme) - * A Type which is parameterized with type apps to compose types. - * Example: map(int, int) - **/ -type ParameterizedType struct { - name string - parameters Lib.ComparableList[TypeApp] -} - -/* TypeScheme interface */ -func (pt ParameterizedType) isScheme() {} -func (pt ParameterizedType) toMappedString(subst map[string]string) string { - mappedString := []string{} - for _, typeScheme := range convert(pt.parameters, typeAppToTypeScheme) { - mappedString = append(mappedString, typeScheme.toMappedString(subst)) - } - return pt.name + "(" + strings.Join(mappedString, ", ") + ")" -} - -/* TypeApp interface */ -func (pt ParameterizedType) isTypeApp() {} -func (pt ParameterizedType) substitute(mapSubst map[TypeVar]string) TypeScheme { - newPt := ParameterizedType{pt.name, Lib.ComparableList[TypeApp]{}} - for _, param := range pt.parameters { - newPt.parameters = append(newPt.parameters, param.substitute(mapSubst).(TypeApp)) - } - return newPt -} -func (pt ParameterizedType) instanciate(substMap map[TypeVar]TypeApp) TypeApp { - newPt := ParameterizedType{pt.name, Lib.ComparableList[TypeApp]{}} - for _, param := range pt.parameters { - newPt.parameters = append(newPt.parameters, param.instanciate(substMap)) - } - return newPt -} - -// Exported methods - -func (pt ParameterizedType) ToString() string { return pt.toMappedString(make(map[string]string)) } -func (pt ParameterizedType) Equals(oth interface{}) bool { - if !Glob.Is[ParameterizedType](oth) { - return false - } - othPT := Glob.To[ParameterizedType](oth) - return pt.name == othPT.name && pt.parameters.Equals(othPT.parameters) -} -func (pt ParameterizedType) Size() int { return 1 } -func (pt ParameterizedType) GetPrimitives() []TypeApp { return []TypeApp{pt} } -func (pt ParameterizedType) GetParameters() []TypeApp { - res := []TypeApp{} - for _, param := range pt.parameters { - if Glob.Is[ParameterizedType](param) { - res = append(res, Glob.To[ParameterizedType](param).GetParameters()...) - } else { - res = append(res, param) - } - } - return res -} - -func (pt ParameterizedType) Copy() TypeApp { - newPT := ParameterizedType{name: pt.name, parameters: make(Lib.ComparableList[TypeApp], len(pt.parameters))} - copy(newPT.parameters, pt.parameters) - return newPT -} - -func (pt ParameterizedType) GetName() string { - return pt.name -} - -/* Makes a Parameterized Type from name and parameters */ -func MkParameterizedType(name string, types []TypeApp) ParameterizedType { - pMap.lock.Lock() - if parameters, found := pMap.parametersMap[name]; found { - k := 0 - nextTypes := make([]TypeApp, len(parameters)) - copy(nextTypes, parameters) - for i, param := range nextTypes { - if param == nil { - nextTypes[i] = types[k] - k++ - } - } - if k != len(types) { - pMap.lock.Unlock() - Glob.PrintInfo("PRMTR_TYPE", fmt.Sprintf("Name of the type: %s, length of the args: %d", name, len(types))) - Glob.PrintError("PRMTR_TYPE", "Parameterized type can not be instanciated with this number of arguments.") - return ParameterizedType{} - } - types = nextTypes - } else { - pMap.lock.Unlock() - Glob.PrintError("PRMTR_TYPE", "Parameterized type not found.") - return ParameterizedType{} - } - pMap.lock.Unlock() - - parameterizedType := ParameterizedType{name, types} - - vars := []TypeVar{} - for _, type_ := range types { - if var_, ok := type_.(TypeVar); ok { - vars = append(vars, var_) - } - } - - return parameterizedType -} - -func IsParameterizedType(name string) bool { - pMap.lock.Lock() - _, found := pMap.parametersMap[name] - pMap.lock.Unlock() - return found -} diff --git a/src/AST/polytypes.go b/src/AST/polytypes.go deleted file mode 100644 index a15a1267..00000000 --- a/src/AST/polytypes.go +++ /dev/null @@ -1,177 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares the basic interfaces used for typing the prover. - **/ - -package AST - -import ( - "fmt" - "sync" - - "github.com/GoelandProver/Goeland/Glob" -) - -/** - * Polymorphic type, used either as a TypeHint, TypeCross or a TypeArrow to allow the inductive - * composition of either of the 3 to give a TypeScheme. - **/ -type TypeScheme interface { - /* Non-exported methods */ - isScheme() - toMappedString(map[string]string) string - - /* Exported methods */ - ToString() string - Size() int - GetPrimitives() []TypeApp - Equals(oth interface{}) bool -} - -/** - * Used for types which can be put inside a function or a predicate as arguments - * for a polymorphic scheme. - * It includes : TypeVar, TypeHint and TypeCross. - * In TFF, TypeArrow can not be the type of a variable. - * Furthermore, a TypeApp is not a quantified type scheme. - **/ -type TypeApp interface { - /* Non-exported methods */ - isTypeApp() - substitute(map[TypeVar]string) TypeScheme - instanciate(map[TypeVar]TypeApp) TypeApp - - /* Exported methods */ - ToString() string - Copy() TypeApp - Size() int - Equals(oth interface{}) bool -} - -/** - * Makers. - * As each type is unique, and stored in a Glob map (in shared memory), a lock should - * be defined. - **/ - -/* Call the init function before any type is created with MkType. */ -func initTypes() { - // Instantiate tCounter - tCounter.count = 1 - tCounter.lock = sync.Mutex{} - - // Instantiate tMap - tMap.uidsMap = make(map[string]TypeHint) - tMap.lock = sync.Mutex{} - - // Instantiate typeSchemesMap - typeSchemesMap.tsMap = make(map[string][]App) - typeSchemesMap.lock = sync.Mutex{} - - // Instanciate parameters map - pMap.parametersMap = make(map[string][]TypeApp) - pMap.lock = sync.Mutex{} - - // Default types - defaultType = MkTypeHint("$i") - defaultProp = MkTypeHint("$o") - - if Glob.GetArithModule() { - InitTPTPArithmetic() - } -} - -func EmptyTAArray() []TypeApp { - return []TypeApp{} -} - -/* Utils */ - -func utilMapCreation(vars []TypeVar) map[TypeVar]string { - metaTypeMap := make(map[TypeVar]string) - for i, var_ := range vars { - metaTypeMap[var_] = fmt.Sprintf("*_%d", i) - } - return metaTypeMap -} - -func utilMapReverseCreation(vars []TypeVar) map[string]string { - metaTypeMap := make(map[string]string) - for i, var_ := range vars { - metaTypeMap[fmt.Sprintf("*_%d", i)] = var_.ToString() - } - return metaTypeMap -} - -func substTypeAppList(mapSubst map[TypeVar]string, typeApp []TypeApp) []TypeApp { - newTypeApp := []TypeApp{} - for _, type_ := range typeApp { - newTypeApp = append(newTypeApp, type_.substitute(mapSubst).(TypeApp)) - } - return newTypeApp -} - -func instanciateList(mapSubst map[TypeVar]TypeApp, typeApp []TypeApp) []TypeApp { - newTypeApp := []TypeApp{} - for _, type_ := range typeApp { - newTypeApp = append(newTypeApp, type_.instanciate(mapSubst)) - } - return newTypeApp -} - -func EmptyGlobalContext() bool { - typeSchemesMap.lock.Lock() - schemeLen := len(typeSchemesMap.tsMap) - typeSchemesMap.lock.Unlock() - return schemeLen == 1 -} - -func CountMeta(types []TypeApp) int { - metas := 0 - for _, type_ := range types { - if tv, isTv := type_.(TypeVar); isTv && tv.Instantiated() { - metas += 1 - } - } - return metas -} - -/* Copies a list of TypeApp */ -func CopyTypeAppList(ta []TypeApp) []TypeApp { - res := make([]TypeApp, len(ta)) - for i := range ta { - res[i] = ta[i].Copy() - } - return res -} diff --git a/src/AST/printers.go b/src/AST/printers.go new file mode 100644 index 00000000..c48c4b3f --- /dev/null +++ b/src/AST/printers.go @@ -0,0 +1,101 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file stores the different printers we have in Goeland. + **/ + +package AST + +import ( + "github.com/GoelandProver/Goeland/Lib" + "strings" +) + +func RemoveSuperfluousParenthesesAction(connectives PrinterConnective) PrinterAction { + return PrinterAction{ + genericAction: func(s string) string { + if len(s) == 0 { + return s + } + + complexChildStart := connectives.StrConn(SurComplexChildStart) + complexChildEnd := connectives.StrConn(SurComplexChildEnd) + if s[:len(complexChildStart)] == complexChildStart && + s[len(s)-len(complexChildEnd):] == complexChildEnd { + tentative_str := s[len(complexChildStart) : len(s)-len(complexChildEnd)] + is_open := 0 + for i, char := range tentative_str { + if len(complexChildStart) <= i && tentative_str[i-len(complexChildStart):i] == complexChildStart { + is_open += 1 + } + if len(complexChildEnd) <= i && tentative_str[i-len(complexChildEnd):i] == complexChildEnd { + is_open -= 1 + } + if char == ' ' && is_open == 0 { + return s + } + } + return tentative_str + } + + return s + }, + actionOnId: func(i Id) string { return i.name }, + actionOnBoundVar: func(s string, index int) string { return s }, + actionOnMeta: func(s string, index int) string { return s }, + actionOnType: func(s string) string { return s }, + actionOnTypedVar: func(p Lib.Pair[string, Ty]) string { return p.Fst }, + actionOnFunctional: func(id Id, tys Lib.List[string], args Lib.List[string]) string { + return connectives.DefaultOnFunctionalArgs(id, tys, args) + }, + } +} + +func SanitizerAction(connectives PrinterConnective, forbidden_chars []string) PrinterAction { + return PrinterAction{ + genericAction: func(s string) string { + for _, c := range forbidden_chars { + s = strings.ReplaceAll(s, c, "_") + } + return s + }, + actionOnId: func(i Id) string { return i.name }, + actionOnBoundVar: func(s string, index int) string { return s }, + actionOnMeta: func(s string, index int) string { return s }, + actionOnType: func(s string) string { return s }, + actionOnTypedVar: func(p Lib.Pair[string, Ty]) string { return p.Fst }, + actionOnFunctional: func(id Id, tys Lib.List[string], args Lib.List[string]) string { + return connectives.DefaultOnFunctionalArgs(id, tys, args) + }, + } +} diff --git a/src/AST/quantifiedtype.go b/src/AST/quantifiedtype.go deleted file mode 100644 index 2394c58e..00000000 --- a/src/AST/quantifiedtype.go +++ /dev/null @@ -1,159 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares one of the basic types used for typing the prover : - * QuantifiedType, the Pi operator. - **/ - -package AST - -import ( - "fmt" - "strings" - - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * Quantified TypeScheme. - * It has a list of type vars and an associated scheme. - **/ -type QuantifiedType struct { - vars Lib.ComparableList[TypeVar] - scheme TypeScheme -} - -/* TypeScheme interface */ -func (qt QuantifiedType) isScheme() {} -func (qt QuantifiedType) toMappedString(subst map[string]string) string { - return "Π " + strings.Join(convert(qt.vars, typeTToString[TypeVar]), ", ") + ": Type. " + qt.scheme.toMappedString(subst) -} - -func (qt QuantifiedType) Equals(oth interface{}) bool { - return Glob.Is[QuantifiedType](oth) && qt.scheme.Equals(Glob.To[QuantifiedType](oth).scheme) -} - -func (qt QuantifiedType) QuantifiedVarsLen() int { return len(qt.vars) } -func (qt QuantifiedType) QuantifiedVars() Lib.ComparableList[TypeVar] { return qt.vars } -func (qt QuantifiedType) Size() int { return qt.scheme.Size() } - -func (qt QuantifiedType) ToString() string { - return qt.toMappedString(utilMapReverseCreation(qt.vars)) -} - -func (qt QuantifiedType) GetPrimitives() []TypeApp { - vars := make(map[TypeVar]TypeApp) - for i, var_ := range qt.vars { - vars[MkTypeVar(fmt.Sprintf("*_%d", i))] = var_ - } - primitives := []TypeApp{} - for _, th := range qt.scheme.GetPrimitives() { - if Glob.Is[TypeVar](th) { - if var_, found := vars[th.(TypeVar)]; found { - primitives = append(primitives, var_) - } - } else if Glob.Is[ParameterizedType](th) { - primitives = append(primitives, th.instanciate(vars)) - } else { - primitives = append(primitives, th) - } - } - return primitives -} - -func (qt QuantifiedType) Instanciate(types []TypeApp) TypeScheme { - substMap := make(map[TypeVar]TypeApp) - for i := range qt.vars { - substMap[MkTypeVar(fmt.Sprintf("*_%d", i))] = types[i] - } - - tv := []TypeVar{} - for _, var_ := range types { - if Glob.Is[TypeVar](var_) { - tv = append(tv, Glob.To[TypeVar](var_)) - } else if Glob.Is[ParameterizedType](var_) { - prim := Glob.To[ParameterizedType](var_).GetParameters() - for _, p := range prim { - if Glob.Is[TypeVar](p) { - tv = append(tv, Glob.To[TypeVar](p)) - } - } - } else if Glob.Is[TypeScheme](var_) { - prim := Glob.To[TypeScheme](var_).GetPrimitives() - for _, p := range prim { - if Glob.Is[TypeVar](p) { - tv = append(tv, Glob.To[TypeVar](p)) - } - } - } - } - - if Glob.Is[TypeApp](qt.scheme) { - if len(tv) > 0 { - return MkQuantifiedType(tv, Glob.To[TypeScheme](Glob.To[TypeApp](qt.scheme).instanciate(substMap))) - } - return Glob.To[TypeScheme](Glob.To[TypeApp](qt.scheme).instanciate(substMap)) - } else if Glob.Is[TypeArrow](qt.scheme) { - if len(tv) > 0 { - return MkQuantifiedType(tv, Glob.To[TypeArrow](qt.scheme).instanciate(substMap)) - } - return Glob.To[TypeArrow](qt.scheme).instanciate(substMap) - } else { - if len(tv) > 0 { - return MkQuantifiedType(tv, Glob.To[TypeScheme](Glob.To[ParameterizedType](qt.scheme).instanciate(substMap))) - } - return Glob.To[TypeScheme](Glob.To[ParameterizedType](qt.scheme).instanciate(substMap)) - } -} - -/* Makes a QuantifiedType from TypeVars and a TypeScheme. */ -func MkQuantifiedType(vars []TypeVar, typeScheme TypeScheme) QuantifiedType { - // Modify the typeScheme to make it modulo alpha-conversion - - // 1 - Corresponding map creation - metaTypeMap := utilMapCreation(vars) - - // 2 - Substitute all TypeVar with the meta type - switch ts := typeScheme.(type) { - case TypeApp: - typeScheme = ts.substitute(metaTypeMap) - case TypeArrow: - typeScheme = ts.substitute(metaTypeMap) - default: - //Paradoxal - Glob.Anomaly("MkQuantifiedType", "Reached an unreachable case.") - } - - return QuantifiedType{vars: vars, scheme: typeScheme} -} diff --git a/src/AST/quantifiers.go b/src/AST/quantifiers.go index 3f9ca9f0..9c0afbb2 100644 --- a/src/AST/quantifiers.go +++ b/src/AST/quantifiers.go @@ -38,52 +38,40 @@ package AST import ( "fmt" - "strings" - "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) type quantifier struct { - *MappedString metas Lib.Cache[Lib.Set[Meta], quantifier] index int - varList []Var + varList Lib.List[TypedVar] subForm Form - symbol FormulaType + symbol Connective } -func makeQuantifier(i int, vars []Var, subForm Form, metas Lib.Set[Meta], symbol FormulaType) quantifier { - fms := &MappedString{} - qua := quantifier{ - fms, +func makeQuantifier(i int, vars Lib.List[TypedVar], subForm Form, metas Lib.Set[Meta], symbol Connective) quantifier { + return quantifier{ Lib.MkCache(metas, quantifier.forceGetMetas), i, vars, subForm, symbol, } - fms.MappableString = &qua - - return qua } func (q quantifier) GetIndex() int { return q.index } -func (q quantifier) GetVarList() []Var { - return copyVarList(q.varList) +func (q quantifier) GetVarList() Lib.List[TypedVar] { + return Lib.ListCpy(q.varList) } func (q quantifier) GetForm() Form { return q.subForm.Copy() } -func (q quantifier) GetType() TypeScheme { - return DefaultPropType(0) -} - func (q quantifier) forceGetMetas() Lib.Set[Meta] { return q.subForm.GetMetas() } @@ -93,66 +81,26 @@ func (q quantifier) GetMetas() Lib.Set[Meta] { } func (q quantifier) ToString() string { - return q.MappedString.ToString() + return printer.Str(fmt.Sprintf( + "%s %s%s%s", + printer.StrConn(q.symbol), + printer.SurroundQuantified( + Lib.ListMap(q.varList, func(t TypedVar) Lib.Pair[string, Ty] { + return Lib.MkPair(t.name, t.ty) + }).ToString(printer.StrTyVar, printer.StrConn(SepTyVars), ""), + ), + printer.StrConn(SepVarsForm), + printer.Str(q.subForm.ToString()), + )) } -func (q quantifier) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return " ", "" -} - -var varSeparator = " " - -func ChangeVarSeparator(sep string) string { - old := varSeparator - varSeparator = sep - return old -} - -func (q quantifier) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - type VarType struct { - vars []Var - type_ TypeApp - } - - varsType := []VarType{} - for _, v := range q.GetVarList() { - found := false - for _, vt := range varsType { - if vt.type_.Equals(v.GetTypeApp()) { - vt.vars = append(vt.vars, v) - found = true - } - } - if !found { - varsType = append(varsType, VarType{[]Var{v}, v.GetTypeApp()}) - } - } - - varStrings := []string{} - - for _, vt := range varsType { - str := mapping[QuantVarOpen] - str += ListToMappedString(q.GetVarList(), varSeparator, "", mapping, false) - if displayTypes || Glob.IsRocqOutput() { - str += " : " + vt.type_.ToString() - } - varStrings = append(varStrings, str+mapping[QuantVarClose]) - } - - return "(" + mapping[q.symbol] + " " + strings.Join(varStrings, " ") + mapping[QuantVarSep] + " (%s))" -} - -func (q quantifier) GetChildrenForMappedString() []MappableString { - return q.GetChildFormulas().ToMappableStringSlice() -} - -func (q quantifier) GetChildFormulas() *FormList { - return NewFormList(q.GetForm()) +func (q quantifier) GetChildFormulas() Lib.List[Form] { + return Lib.MkListV(q.GetForm()) } func (q quantifier) Equals(other any) bool { if typed, ok := other.(quantifier); ok { - return AreEqualsVarList(q.varList, typed.varList) && q.subForm.Equals(typed.subForm) + return Lib.ListEquals(q.varList, typed.varList) && q.subForm.Equals(typed.subForm) } return false @@ -165,7 +113,7 @@ func (q quantifier) GetSubTerms() Lib.List[Term] { func (q quantifier) copy() quantifier { nq := makeQuantifier( q.GetIndex(), - copyVarList(q.GetVarList()), + Lib.ListCpy(q.varList), q.GetForm(), q.metas.Raw().Copy(), q.symbol, @@ -178,41 +126,60 @@ func (q quantifier) copy() quantifier { return nq } -func (q quantifier) replaceTypeByMeta(varList []TypeVar, index int) quantifier { +func (q quantifier) replaceTermByTerm(old Term, new Term) (quantifier, bool) { + f, res := q.GetForm().ReplaceTermByTerm(old, new) return makeQuantifier( q.GetIndex(), q.GetVarList(), - q.GetForm().ReplaceTypeByMeta(varList, index), + f, q.metas.Raw().Copy(), q.symbol, - ) + ), res } -func (q quantifier) replaceTermByTerm(old Term, new Term) (quantifier, bool) { - f, res := q.GetForm().ReplaceTermByTerm(old, new) +func (q quantifier) replaceTyVar(old TyGenVar, new Ty) quantifier { + f := q.GetForm().SubstTy(old, new) return makeQuantifier( q.GetIndex(), - q.GetVarList(), + Lib.ListMap( + q.GetVarList(), + func(p TypedVar) TypedVar { return p.SubstTy(old, new) }, + ), f, q.metas.Raw().Copy(), q.symbol, - ), res + ) } func (q quantifier) renameVariables() quantifier { - newVarList := []Var{} - newForm := q.GetForm() + newVarList := Lib.NewList[TypedVar]() + newForm := q.GetForm().RenameVariables() - for _, v := range q.GetVarList() { + newTyBv := Lib.NewList[Lib.Pair[TyBound, Ty]]() + for _, v := range q.GetVarList().GetSlice() { newVar := MakerNewVar(v.GetName()) - newVar = MakerVar(fmt.Sprintf("%s%d", newVar.GetName(), newVar.GetIndex()), v.typeHint) - newVarList = append(newVarList, newVar) - newForm, _ = newForm.RenameVariables().ReplaceTermByTerm(v, newVar) + newVar = MakerVar(fmt.Sprintf("%s%d", newVar.GetName(), newVar.GetIndex())) + newVarList.Append(MkTypedVar(newVar.name, newVar.index, v.ty)) + f, replaced := newForm.ReplaceTermByTerm(v.ToBoundVar(), newVar) + if !replaced { + newBv := MkTyBV(newVar.name, newVar.index) + f = f.SubstTy(v.ToTyBoundVar(), newBv) + newTyBv.Append(Lib.MkPair(v.ToTyBoundVar(), newBv)) + } + newForm = f } return makeQuantifier( q.GetIndex(), - newVarList, + Lib.ListMap( + newVarList, + func(p TypedVar) TypedVar { + for _, pair := range newTyBv.GetSlice() { + p = p.SubstTy(pair.Fst, pair.Snd) + } + return p + }, + ), newForm, q.metas.Raw().Copy(), q.symbol, diff --git a/src/AST/term_list.go b/src/AST/term-list.go similarity index 93% rename from src/AST/term_list.go rename to src/AST/term-list.go index 98d73cf1..ab4d8823 100644 --- a/src/AST/term_list.go +++ b/src/AST/term-list.go @@ -117,10 +117,6 @@ func EqualsWithoutOrder(tl, other Lib.List[Term]) bool { return Lib.ListEquals(tlSorted.List(), otherSorted.List()) } -func AreEqualsTypeVarList(tv1, tv2 []TypeVar) bool { - return Lib.ComparableList[TypeVar](tv1).Equals(tv2) -} - /* check if two lists of var are equals */ func AreEqualsVarList(tl1, tl2 []Var) bool { if len(tl1) != len(tl2) { @@ -142,11 +138,3 @@ func copyVarList(tl []Var) []Var { } return res } - -func copyTypeVarList(tv []TypeVar) []TypeVar { - res := []TypeVar{} - for _, t := range tv { - res = append(res, t.Copy().(TypeVar)) - } - return res -} diff --git a/src/AST/term.go b/src/AST/term.go index 4ebc116a..bfe5f5f3 100644 --- a/src/AST/term.go +++ b/src/AST/term.go @@ -37,13 +37,13 @@ package AST import ( - "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) /* Term */ type Term interface { - MappableString + Lib.Comparable + Lib.Stringable Lib.Copyable[Term] GetIndex() int GetName() string @@ -54,146 +54,32 @@ type Term interface { GetMetaList() Lib.List[Meta] // Metas appearing in the term ORDERED GetSubTerms() Lib.List[Term] ReplaceSubTermBy(original_term, new_term Term) Term + SubstTy(old TyGenVar, new Ty) Term Less(any) bool } -type TypedTerm interface { - GetTypeHint() TypeScheme - GetTypeApp() TypeApp -} - /*** Makers ***/ func MakeId(i int, s string) Id { - fms := &MappedString{} - id := Id{fms, i, s} - fms.MappableString = &id - return id + return Id{i, s} } func MakeQuotedId(i int, s string) Id { - fms := &MappedString{} - id := Id{fms, i, "" + s + "'"} - fms.MappableString = &id - return id + return Id{i, "" + s + "'"} } -func MakeVar(i int, s string, t ...TypeApp) Var { - fms := &MappedString{} - newVar := Var{fms, i, s, getType(t)} - fms.MappableString = &newVar - return newVar -} - -func MakeMeta(index, occurence int, s string, f int, t ...TypeApp) Meta { - fms := &MappedString{} - meta := Meta{fms, index, occurence, s, f, getType(t)} - fms.MappableString = &meta - return meta -} - -func MakeFun(p Id, args Lib.List[Term], typeVars []TypeApp, t TypeScheme, metas Lib.Set[Meta]) Fun { - fms := &MappedString{} - fun := Fun{fms, p, args, typeVars, t, Lib.MkCache(metas, Fun.forceGetMetas)} - fms.MappableString = fun - return fun -} - -/*** Functions ***/ - -func TypeAppArrToTerm(typeApps []TypeApp) Lib.List[Term] { - terms := Lib.MkList[Term](len(typeApps)) - - for i, typeApp := range typeApps { - terms.Upd(i, TypeAppToTerm(typeApp)) - } - - return terms +func MakeVar(i int, s string) Var { + return Var{i, s} } -/* Creates a Term from a TypeApp to unify it properly */ -func TypeAppToTerm(typeApp TypeApp) Term { - var term Term - switch nt := typeApp.(type) { - case TypeVar: - if nt.IsMeta() { - term = typeVarToMeta(nt) - } else { - Glob.PrintError("TERM", "A TypeVar should be only converted to terms if it has been instantiated.") - term = nil - } - case TypeHint: - term = MakerFun( - MakerId(nt.ToString()), - Lib.NewList[Term](), - []TypeApp{}, - MkTypeHint("$tType"), - ) - case TypeCross: - underlyingTypes := nt.GetAllUnderlyingTypes() - args := Lib.MkList[Term](len(underlyingTypes)) - - for i, type_ := range nt.GetAllUnderlyingTypes() { - args.Upd(i, TypeAppToTerm(type_)) - } - - term = MakeFun( - MakerId("$$tCross"), - args, - []TypeApp{}, - MkTypeHint("$tType"), - Lib.EmptySet[Meta](), - ) - case ParameterizedType: - parameters := nt.GetParameters() - args := Lib.MkList[Term](len(parameters)) - - for i, type_ := range nt.GetParameters() { - args.Upd(i, TypeAppToTerm(type_)) - } - - term = MakeFun( - MakerId(nt.ToString()), - args, - []TypeApp{}, - MkTypeHint("$tType"), - Lib.EmptySet[Meta](), - ) - } - return term +func MakeMeta(index, occurence int, s string, f int, ty Ty) Meta { + return Meta{index, occurence, s, f, ty} } -func typeVarToMeta(typeVar TypeVar) Meta { - var meta Meta - index, formula, occurence := typeVar.MetaInfos() - if !typeVar.Instantiated() { - meta = MakerMeta(typeVar.ToString(), formula, MkTypeHint("$tType")) - typeVar.Instantiate(meta.index) - } else { - meta = MakeMeta(index, occurence, typeVar.ToString(), formula, MkTypeHint("$tType")) - } - return meta +func MakeFun(p Id, ty_args Lib.List[Ty], args Lib.List[Term], metas Lib.Set[Meta]) Fun { + return Fun{p, ty_args, args, Lib.MkCache(metas, Fun.forceGetMetas)} } -func replaceTermListTypesByMeta(tl Lib.List[Term], varList []TypeVar, index int) Lib.List[Term] { - res := Lib.MkList[Term](tl.Len()) - - for i, term := range tl.GetSlice() { - if Glob.Is[Fun](term) { - t := Glob.To[Fun](term) - res.Upd(i, MakeFun( - t.GetID(), - replaceTermListTypesByMeta(t.GetArgs(), varList, index), - instanciateTypeAppList(t.GetTypeVars(), varList, index), - t.GetTypeHint(), - t.metas.Raw(), - )) - } else { - res.Upd(i, term) - } - } - - return res -} +/*** Functions **/ func TermEquals(x, y Term) bool { return x.Equals(y) diff --git a/src/AST/termsDef.go b/src/AST/termsDef.go index 8b240000..83994bb6 100644 --- a/src/AST/termsDef.go +++ b/src/AST/termsDef.go @@ -37,10 +37,7 @@ package AST import ( - "fmt" "strings" - "unicode" - "unicode/utf8" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" @@ -50,7 +47,6 @@ import ( // Predicates / functions symbols type Id struct { - *MappedString index int name string } @@ -63,39 +59,7 @@ func (i Id) Copy() Term { return MakeId(i.GetIndex(), i.GetName() func (Id) ToMeta() Meta { return MakeEmptyMeta() } func (Id) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } func (Id) GetMetaList() Lib.List[Meta] { return Lib.NewList[Meta]() } - -var ToStringId = func(i Id) string { - return fmt.Sprintf("%s_%d", i.GetName(), i.GetIndex()) -} - -func (i Id) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "%s" -} - -func (i Id) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return "", ToStringId(i) -} - -func NoIdToString(i Id) string { - return fmt.Sprintf("%s", i.GetName()) -} - -func QuotedToString(i Id) string { - if i.GetName() == "Goeland_I" || strings.Contains(i.GetName(), "Sko_") { - return fmt.Sprintf("%s", i.GetName()) - } else { - r, _ := utf8.DecodeRuneInString(i.GetName()) - if unicode.IsUpper(r) { - return fmt.Sprintf("'%s'", i.GetName()) - } else { - return fmt.Sprintf("%s", i.GetName()) - } - } -} - -func (i Id) GetChildrenForMappedString() []MappableString { - return []MappableString{} -} +func (i Id) ToString() string { return printer.StrId(i) } func (i Id) Equals(t any) bool { if typed, ok := t.(Id); ok { @@ -111,6 +75,8 @@ func (i Id) ReplaceSubTermBy(original_term, new_term Term) Term { return i } +func (i Id) SubstTy(TyGenVar, Ty) Term { return i } + func (i Id) GetSubTerms() Lib.List[Term] { return Lib.MkListV[Term](i) } @@ -145,107 +111,54 @@ func (i Id) Less(u any) bool { // n-ary functions type Fun struct { - *MappedString - p Id - args Lib.List[Term] - typeVars []TypeApp - typeHint TypeScheme - metas Lib.Cache[Lib.Set[Meta], Fun] -} - -func (f Fun) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return f.ToMappedStringSurroundWithId(f.GetID().ToMappedString(mapping, displayTypes), mapping, displayTypes) -} - -func (f Fun) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - return ", ", mapping[PredEmpty] -} - -func (f Fun) ToMappedStringSurroundWithId(idString string, mapping MapString, displayTypes bool) string { - if len(f.typeVars) == 0 && f.GetArgs().Len() == 0 { - return idString + "%s" - } - args := []string{} - - if len(f.typeVars) > 0 { - if tv := Glob.ListToString(f.typeVars, ", ", mapping[PredEmpty]); tv != "" { - args = append(args, tv) - } - } - args = append(args, "%s") - - str := idString + "(" + strings.Join(args, mapping[PredTypeVarSep]) + ")" - if displayTypes { - str += " : " + f.typeHint.ToString() - } - - return str -} - -func ToFlatternStringSurrountWithId(f Fun, idString string, mapping MapString, displayTypes bool) string { - - if len(f.typeVars) == 0 && f.GetArgs().Len() == 0 { - return idString + "%s" - } - args := []string{} - - if len(f.typeVars) > 0 { - if tv := Glob.ListToString(f.typeVars, "_", mapping[PredEmpty]); tv != "" { - args = append(args, tv) - } - } - args = append(args, "%s") - - str := idString + "_" + strings.Join(args, mapping[PredTypeVarSep]) - if displayTypes { - str += " : " + f.typeHint.ToString() - } - - return str + p Id + tys Lib.List[Ty] + args Lib.List[Term] + metas Lib.Cache[Lib.Set[Meta], Fun] } -func (f Fun) GetChildrenForMappedString() []MappableString { - mappableList := Lib.ListMap(f.GetArgs(), Glob.To[MappableString]) - return mappableList.GetSlice() +func (f Fun) ToString() string { + return printer.StrFunctional( + f.p, + Lib.ListMap(f.tys, Ty.ToString), + Lib.ListMap(f.args, Term.ToString), + ) } func (f Fun) GetID() Id { return f.p.Copy().(Id) } func (f Fun) GetP() Id { return f.p.Copy().(Id) } +func (f Fun) GetTyArgs() Lib.List[Ty] { return f.tys } func (f Fun) GetArgs() Lib.List[Term] { return f.args } -func (f *Fun) SetArgs(tl Lib.List[Term]) { f.args = tl } -func (f *Fun) SetTypeScheme(ts TypeScheme) { f.typeHint = ts } +func (f *Fun) SetArgs(tl Lib.List[Term]) { f.args = tl } -func (f Fun) GetTypeVars() []TypeApp { return f.typeVars } -func (f Fun) GetTypeApp() TypeApp { return nil } -func (f Fun) GetTypeHint() TypeScheme { return f.typeHint } -func (f Fun) GetIndex() int { return f.GetID().GetIndex() } -func (f Fun) GetName() string { return f.GetID().GetName() } -func (f Fun) IsMeta() bool { return false } -func (f Fun) IsFun() bool { return true } -func (Fun) ToMeta() Meta { return MakeEmptyMeta() } +func (f Fun) GetIndex() int { return f.GetID().GetIndex() } +func (f Fun) GetName() string { return f.GetID().GetName() } +func (f Fun) IsMeta() bool { return false } +func (f Fun) IsFun() bool { return true } +func (Fun) ToMeta() Meta { return MakeEmptyMeta() } func (f Fun) Equals(t any) bool { switch typed := t.(type) { case Fun: return typed.GetID().Equals(f.GetID()) && - Lib.ListEquals(typed.GetArgs(), f.GetArgs()) && - f.typeHint.Equals(typed.typeHint) + Lib.ListEquals(typed.GetTyArgs(), f.GetTyArgs()) && + Lib.ListEquals(typed.GetArgs(), f.GetArgs()) case *Fun: return typed.GetID().Equals(f.GetID()) && - Lib.ListEquals(typed.GetArgs(), f.GetArgs()) && - f.typeHint.Equals(typed.typeHint) + Lib.ListEquals(typed.GetTyArgs(), f.GetTyArgs()) && + Lib.ListEquals(typed.GetArgs(), f.GetArgs()) default: return false } } func (f Fun) Copy() Term { - return MakeFun(f.GetP(), f.GetArgs(), CopyTypeAppList(f.GetTypeVars()), f.GetTypeHint(), f.metas.Raw()) + return MakeFun(f.GetP(), Lib.ListCpy(f.GetTyArgs()), Lib.ListCpy(f.GetArgs()), f.metas.Raw()) } func (f Fun) PointerCopy() *Fun { - nf := MakeFun(f.GetP(), f.GetArgs(), CopyTypeAppList(f.GetTypeVars()), f.GetTypeHint(), f.metas.Raw()) + nf := MakeFun(f.GetP(), f.GetTyArgs(), f.GetArgs(), f.metas.Raw()) return &nf } @@ -283,7 +196,7 @@ func (f Fun) ReplaceSubTermBy(oldTerm, newTerm Term) Term { return newTerm.Copy() } else { tl, res := replaceFirstOccurrenceTermList(f.GetArgs(), oldTerm, newTerm) - nf := MakeFun(f.GetID(), tl, f.GetTypeVars(), f.GetTypeHint(), f.metas.Raw()) + nf := MakeFun(f.GetID(), f.GetTyArgs(), tl, f.metas.Raw()) if !res && !f.metas.NeedsUpd() { nf.metas.AvoidUpd() } @@ -291,12 +204,29 @@ func (f Fun) ReplaceSubTermBy(oldTerm, newTerm Term) Term { } } +func (f Fun) SubstTy(old TyGenVar, new Ty) Term { + typed_args := Lib.ListMap( + f.tys, + func(t Ty) Ty { return t.SubstTy(old, new) }, + ) + args := Lib.ListMap( + f.args, + func(t Term) Term { return t.SubstTy(old, new) }, + ) + return MakeFun( + f.GetID(), + typed_args, + args, + f.metas.Raw(), + ) +} + func (f Fun) ReplaceAllSubTerm(oldTerm, newTerm Term) Term { if f.Equals(oldTerm) { return newTerm.Copy() } else { tl, res := ReplaceOccurrence(f.GetArgs(), oldTerm, newTerm) - nf := MakeFun(f.GetID(), tl, f.GetTypeVars(), f.GetTypeHint(), f.metas.Raw()) + nf := MakeFun(f.GetID(), f.GetTyArgs(), tl, f.metas.Raw()) if !res && !f.metas.NeedsUpd() { nf.metas.AvoidUpd() } @@ -329,19 +259,16 @@ func (f Fun) Less(u any) bool { // Bound variables type Var struct { - *MappedString - index int - name string - typeHint TypeApp + index int + name string } -func (v Var) GetTypeApp() TypeApp { return v.typeHint } -func (v Var) GetTypeHint() TypeScheme { return v.typeHint.(TypeScheme) } +func (v Var) ToString() string { return printer.StrBound(v.name, v.index) } func (v Var) GetIndex() int { return v.index } func (v Var) GetName() string { return v.name } func (v Var) IsMeta() bool { return false } func (v Var) IsFun() bool { return false } -func (v Var) Copy() Term { return MakeVar(v.GetIndex(), v.GetName(), v.typeHint) } +func (v Var) Copy() Term { return MakeVar(v.GetIndex(), v.GetName()) } func (Var) ToMeta() Meta { return MakeEmptyMeta() } func (Var) GetMetas() Lib.Set[Meta] { return Lib.EmptySet[Meta]() } func (Var) GetMetaList() Lib.List[Meta] { return Lib.NewList[Meta]() } @@ -364,28 +291,7 @@ func (v Var) ReplaceSubTermBy(original_term, new_term Term) Term { return v } -func (v Var) ToMappedString(map_ MapString, type_ bool) string { - if type_ { - return fmt.Sprintf("%s_%d : %s", v.GetName(), v.GetIndex(), v.typeHint.ToString()) - } - return v.GetName() -} - -func (v Var) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "%s" -} - -func (v Var) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - if displayTypes { - return "", fmt.Sprintf("%s_%d : %s", v.GetName(), v.GetIndex(), v.typeHint.ToString()) - } else { - return "", v.GetName() - } -} - -func (v Var) GetChildrenForMappedString() []MappableString { - return []MappableString{} -} +func (v Var) SubstTy(TyGenVar, Ty) Term { return v } func (v Var) Less(u any) bool { switch t := u.(type) { @@ -401,18 +307,16 @@ func (v Var) Less(u any) bool { // Meta/Free variables type Meta struct { - *MappedString index int occurence int name string formula int - typeHint TypeApp + ty Ty } -func (m Meta) GetFormula() int { return m.formula } +func (m Meta) ToString() string { return printer.StrMeta(m.name, m.index) } +func (m Meta) GetFormula() int { return m.formula } -func (m Meta) GetTypeApp() TypeApp { return m.typeHint } -func (m Meta) GetTypeHint() TypeScheme { return m.typeHint.(TypeScheme) } func (m Meta) GetName() string { return m.name } func (m Meta) GetIndex() int { return m.index } func (m Meta) GetOccurence() int { return m.occurence } @@ -421,22 +325,7 @@ func (m Meta) IsFun() bool { return false } func (m Meta) ToMeta() Meta { return m } func (m Meta) GetMetas() Lib.Set[Meta] { return Lib.Singleton(m) } func (m Meta) GetMetaList() Lib.List[Meta] { return Lib.MkListV(m) } - -func (m Meta) ToMappedStringSurround(mapping MapString, displayTypes bool) string { - return "%s" -} - -func (m Meta) ToMappedStringChild(mapping MapString, displayTypes bool) (separator, emptyValue string) { - if displayTypes { - return "", fmt.Sprintf("%s_%d : %s", m.GetName(), m.GetIndex(), m.GetTypeHint().ToString()) - } else { - return "", fmt.Sprintf("%s_%d", m.GetName(), m.GetIndex()) - } -} - -func (m Meta) GetChildrenForMappedString() []MappableString { - return []MappableString{} -} +func (m Meta) GetTy() Ty { return m.ty } func (m Meta) Equals(t any) bool { if typed, ok := t.(Meta); ok { @@ -446,7 +335,7 @@ func (m Meta) Equals(t any) bool { } func (m Meta) Copy() Term { - return MakeMeta(m.GetIndex(), m.GetOccurence(), m.GetName(), m.GetFormula(), m.GetTypeApp()) + return MakeMeta(m.GetIndex(), m.GetOccurence(), m.GetName(), m.GetFormula(), m.GetTy()) } func (m Meta) ReplaceSubTermBy(original_term, new_term Term) Term { @@ -456,6 +345,8 @@ func (m Meta) ReplaceSubTermBy(original_term, new_term Term) Term { return m } +func (m Meta) SubstTy(TyGenVar, Ty) Term { return m } + func (m Meta) GetSubTerms() Lib.List[Term] { return Lib.MkListV[Term](m) } @@ -471,7 +362,7 @@ func (m Meta) Less(u any) bool { } func MakeEmptyMeta() Meta { - return MakeMeta(-1, -1, "-1", -1, nil, DefaultType()) + return MakeMeta(-1, -1, "-1", -1, TIndividual()) } func MetaEquals(x, y Meta) bool { diff --git a/src/AST/tptp-native-types.go b/src/AST/tptp-native-types.go new file mode 100644 index 00000000..320cf3b7 --- /dev/null +++ b/src/AST/tptp-native-types.go @@ -0,0 +1,100 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file declares TPTP native types and types scheme : + * - int, rat, real for primitives + * - a bunch of type schemes + **/ + +package AST + +import ( + "github.com/GoelandProver/Goeland/Lib" +) + +var tType Ty + +var tInt Ty +var tRat Ty +var tReal Ty + +var tIndividual Ty +var tProp Ty + +func initTPTPNativeTypes() { + tType = MkTyConst("$tType") + + tInt = MkTyConst("$int") + tRat = MkTyConst("$rat") + tReal = MkTyConst("$real") + + tIndividual = MkTyConst("$i") + tProp = MkTyConst("$o") + + count_meta = 0 +} + +func TType() Ty { + return tType +} + +func TInt() Ty { + return tInt +} + +func TRat() Ty { + return tRat +} + +func TReal() Ty { + return tReal +} + +func TIndividual() Ty { + return tIndividual +} + +func TProp() Ty { + return tProp +} + +func IsTType(ty Ty) bool { + return ty.Equals(tType) +} + +func DefinedTPTPTypes() Lib.List[TyConstr] { + return Lib.ListMap( + Lib.MkListV(tType, tInt, tRat, tReal, tIndividual, tProp), + func(ty Ty) TyConstr { return ty.(TyConstr) }, + ) +} diff --git a/src/AST/ty-syntax.go b/src/AST/ty-syntax.go new file mode 100644 index 00000000..f24bc75b --- /dev/null +++ b/src/AST/ty-syntax.go @@ -0,0 +1,510 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file declares the syntax of the TFF1 type system. + * Variables are internal to polymorphic schemes and are treated with pseudo De Bruijn indices. + **/ + +package AST + +import ( + "fmt" + "sync" + + "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" +) + +var meta_mut sync.Mutex +var count_meta int + +type TyGenVar interface { + isGenVar() +} + +type Ty interface { + Lib.Stringable + Lib.Comparable + Lib.Copyable[Ty] + isTy() + SubstTy(TyGenVar, Ty) Ty +} + +// Internal, shouldn't get out so no upper case +type tyVar struct { + repr string +} + +func (tyVar) isTy() {} +func (v tyVar) ToString() string { + return printer.StrBound(v.repr, 0) +} +func (v tyVar) Equals(oth any) bool { + if ov, ok := oth.(tyVar); ok { + return v.repr == ov.repr + } + return false +} +func (v tyVar) Copy() Ty { return tyVar{v.repr} } + +func (v tyVar) SubstTy(TyGenVar, Ty) Ty { return v } + +type TyBound struct { + name string + index int +} + +func (TyBound) isTy() {} +func (TyBound) isGenVar() {} +func (b TyBound) ToString() string { + return printer.StrBound(b.name, b.index) +} +func (b TyBound) Equals(oth any) bool { + if bv, ok := oth.(TyBound); ok { + return b.name == bv.name + } + return false +} +func (b TyBound) Copy() Ty { return TyBound{b.name, b.index} } +func (b TyBound) GetName() string { return b.name } + +func (b TyBound) SubstTy(old TyGenVar, new Ty) Ty { + if b.Equals(old) { + return new + } + return b +} + +type TyMeta struct { + name string + index int + formula int // for compatibility with term metas +} + +func (TyMeta) isTy() {} +func (TyMeta) isGenVar() {} +func (m TyMeta) ToString() string { + return printer.StrMeta(m.name, m.index) +} +func (m TyMeta) Equals(oth any) bool { + if om, ok := oth.(TyMeta); ok { + return m.name == om.name && m.index == om.index + } + return false +} +func (m TyMeta) Copy() Ty { return TyMeta{m.name, m.index, m.formula} } + +func (m TyMeta) SubstTy(v TyGenVar, new Ty) Ty { + if m.Equals(v) { + return new + } + return m +} + +func (m TyMeta) ToTermMeta() Meta { return MakeMeta(m.index, -1, m.name, m.formula, tType) } + +func TyMetaFromMeta(m Meta) TyMeta { + return TyMeta{ + m.name, + m.index, + m.formula, + } +} + +// Type constructors, e.g., list, option, ... +// Include constants, e.g., $i, $o, ... +type TyConstr struct { + symbol string + args Lib.List[Ty] +} + +func (TyConstr) isTy() {} + +func (c TyConstr) ToString() string { + if c.args.Empty() { + return printer.StrTy(c.symbol) + } + return fmt.Sprintf("%s%s", + printer.StrTy(c.symbol), + printer.SurroundArgs(Lib.ListToString(c.args, printer.StrConn(SepArgs), "")), + ) +} + +func (c TyConstr) Equals(oth any) bool { + if oc, ok := oth.(TyConstr); ok { + return c.symbol == oc.symbol && + Lib.ListEquals(c.args, oc.args) + } + return false +} + +func (c TyConstr) Copy() Ty { + return TyConstr{c.symbol, Lib.ListCpy(c.args)} +} + +func (c TyConstr) Symbol() string { + return c.symbol +} + +func (c TyConstr) Args() Lib.List[Ty] { + return c.args +} + +func (c TyConstr) SubstTy(old TyGenVar, new Ty) Ty { + return TyConstr{ + c.symbol, + Lib.ListMap(c.args, func(t Ty) Ty { return t.SubstTy(old, new) }), + } +} + +type TyProd struct { + args Lib.List[Ty] +} + +func (TyProd) isTy() {} + +func (p TyProd) ToString() string { + return p.args.ToString( + func(ty Ty) string { return printer.Str(printer.SurroundChild(ty.ToString())) }, + printer.StrConn(ConnProd), "", + ) +} + +func (p TyProd) GetTys() Lib.List[Ty] { + return p.args +} + +func (p TyProd) Equals(oth any) bool { + if op, ok := oth.(TyProd); ok { + return Lib.ListEquals(p.args, op.args) + } + return false +} + +func (p TyProd) Copy() Ty { + return TyProd{Lib.ListCpy(p.args)} +} + +func (p TyProd) SubstTy(old TyGenVar, new Ty) Ty { + return TyProd{ + Lib.ListMap(p.args, func(t Ty) Ty { return t.SubstTy(old, new) }), + } +} + +type TyFunc struct { + in, out Ty +} + +func (TyFunc) isTy() {} +func (f TyFunc) ToString() string { + return fmt.Sprintf("%s %s %s", + printer.Str(printer.SurroundChild(f.in.ToString())), + printer.StrConn(ConnMap), + printer.Str(printer.SurroundChild(f.out.ToString())), + ) +} +func (f TyFunc) Equals(oth any) bool { + if of, ok := oth.(TyFunc); ok { + return f.in.Equals(of.in) && f.out.Equals(of.out) + } + return false +} + +func (f TyFunc) Copy() Ty { + return TyFunc{f.in.Copy(), f.out.Copy()} +} + +func (f TyFunc) SubstTy(old TyGenVar, new Ty) Ty { + return TyFunc{f.in.SubstTy(old, new), f.out.SubstTy(old, new)} +} + +type TyPi struct { + vars Lib.List[string] + ty Ty +} + +func (TyPi) isTy() {} +func (p TyPi) ToString() string { + return fmt.Sprintf( + "%s %s%s%s", + printer.StrConn(ConnPi), + printer.SurroundQuantified( + p.vars.ToString(PrinterIdentity, printer.StrConn(SepTyVars), ""), + ), + printer.StrConn(SepVarsForm), + printer.Str(p.ty.ToString()), + ) +} +func (p TyPi) Equals(oth any) bool { + if op, ok := oth.(TyPi); ok { + cmp := func(x, y string) bool { return x == y } + return p.vars.Equals(cmp, p.vars, op.vars) && + p.ty.Equals(op.ty) + } + return false +} + +func (p TyPi) Copy() Ty { + return TyPi{p.vars.Copy(func(x string) string { return x }), p.ty.Copy()} +} + +func (p TyPi) SubstTy(old TyGenVar, new Ty) Ty { + return TyPi{p.vars, p.ty.SubstTy(old, new)} +} + +func (p TyPi) VarsLen() int { + return p.vars.Len() +} + +// Makers + +func MkTyVar(repr string) Ty { + return tyVar{repr} +} + +func MkTyBV(name string, index int) Ty { + return TyBound{name, index} +} + +func MkTyMeta(name string, formula int) Ty { + meta_mut.Lock() + meta := TyMeta{name, count_meta, formula} + count_meta += 1 + meta_mut.Unlock() + return meta +} + +func MkTyConstr(symbol string, args Lib.List[Ty]) Ty { + return TyConstr{symbol, args} +} + +func MkTyConst(symbol string) Ty { + return TyConstr{symbol, Lib.NewList[Ty]()} +} + +func MkTyProd(args Lib.List[Ty]) Ty { + return TyProd{args} +} + +func MkTyFunc(in, out Ty) Ty { + return TyFunc{in, out} +} + +func MkTyPi(vars Lib.List[string], ty Ty) Ty { + return TyPi{vars, ty} +} + +// FIXME: the Maker logic should be factorized somewhere +func MakerTyBV(name string) Ty { + lock_term.Lock() + i, ok := idVar[name] + lock_term.Unlock() + if ok { + return MkTyBV(name, i) + } else { + lock_term.Lock() + idVar[name] = cpt_term + vr := MkTyBV(name, cpt_term) + cpt_term += 1 + lock_term.Unlock() + return vr + } +} + +func InstantiateTy(ty Ty, instance Lib.List[Ty]) Ty { + fatal := func(expected int) { + Glob.Fatal( + "Ty.Instantiate", + fmt.Sprintf( + "On instantiation of %s: given instance %s does not have the right number of arguments (expected %d)", + ty.ToString(), + Lib.ListToString(instance, ", ", "(empty instance)"), + expected, + ), + ) + } + + switch rty := ty.(type) { + case TyConstr, TyFunc: + if !instance.Empty() { + fatal(0) + } + + return ty + case TyPi: + if instance.Len() != rty.vars.Len() { + fatal(rty.vars.Len()) + } + + instanceMap := make(map[string]Ty) + for i, ity := range instance.GetSlice() { + instanceMap[rty.vars.At(i)] = ity + } + return instantiateTyRec(rty.ty, ty, instanceMap) + } + Glob.Anomaly( + "Ty.Instantiate", + fmt.Sprintf("Tried to instantiate %s which is not a Pi-type", ty.ToString()), + ) + return nil +} + +// source type is here for logging +func instantiateTyRec(ty, source Ty, instance map[string]Ty) Ty { + aux := func(ty Ty) Ty { + return instantiateTyRec(ty, source, instance) + } + + switch rty := ty.(type) { + case tyVar: + if val, ok := instance[rty.repr]; ok { + return val + } + Glob.Anomaly( + "Ty.Instantiate", + fmt.Sprintf("Under type %s: type variable %s has no instance", source.ToString(), rty.repr), + ) + + case TyConstr: + return MkTyConstr( + rty.symbol, + Lib.ListMap(rty.args, aux), + ) + + case TyProd: + return MkTyProd(Lib.ListMap(rty.args, aux)) + + case TyFunc: + return MkTyFunc(aux(rty.in), aux(rty.out)) + } + + Glob.Anomaly( + "Ty.Instantiate", + fmt.Sprintf( + "In %s, trying to instantiate %s which is illegal", + source.ToString(), + ty.ToString(), + ), + ) + return nil +} + +func GetArgsTy(ty Ty) Lib.List[Ty] { + switch rty := ty.(type) { + case TyConstr: + return Lib.NewList[Ty]() + case TyFunc: + switch nty := rty.in.(type) { + case TyBound, TyConstr: + return Lib.MkListV(rty.in) + case TyProd: + return nty.args + } + } + Glob.Anomaly( + "Ty.GetArgs", + fmt.Sprintf("Tried to extract types of arguments of a non-functional type %s", ty.ToString()), + ) + return Lib.NewList[Ty]() +} + +func GetOutTy(ty Ty) Ty { + switch rty := ty.(type) { + case TyConstr: + return tType + case TyFunc: + return rty.out + } + + Glob.Anomaly( + "Ty.GetOutTy", + fmt.Sprintf("Tried to extract out type of a non-functional type %s", ty.ToString()), + ) + return nil +} + +func TyToTerm(ty Ty) Term { + switch nty := ty.(type) { + case TyMeta: + return nty.ToTermMeta() + case TyConstr: + return MakerFun( + MakerId(nty.symbol), + Lib.NewList[Ty](), + Lib.ListMap(nty.args, TyToTerm), + ) + } + + Glob.Anomaly( + "AST.Ty", + fmt.Sprintf("Trying to convert the non-atomic (or bound var) type %s to a term", ty.ToString()), + ) + return nil +} + +func TermToTy(trm Term) Ty { + switch t := trm.(type) { + case Meta: + return TyMetaFromMeta(t) + case Fun: + return MkTyConstr( + t.GetID().name, + Lib.ListMap(t.args, TermToTy), + ) + } + + Glob.Anomaly( + "AST.Ty", + fmt.Sprintf("Trying to convert the non-atomic (or bound var) term %s to a type", trm.ToString()), + ) + return nil +} + +func mkDefaultFunctionalType(number_of_arguments int, out_type Ty) Ty { + if number_of_arguments == 0 { + return out_type + } + tys := Lib.MkList[Ty](number_of_arguments) + for i := 0; i < number_of_arguments; i++ { + tys.Upd(i, TIndividual()) + } + return MkTyFunc(MkTyProd(tys), out_type) +} + +func MkDefaultPredType(number_of_arguments int) Ty { + return mkDefaultFunctionalType(number_of_arguments, TProp()) +} + +func MkDefaultFunctionType(number_of_arguments int) Ty { + return mkDefaultFunctionalType(number_of_arguments, TIndividual()) +} diff --git a/src/AST/typearrow.go b/src/AST/typearrow.go deleted file mode 100644 index 6690f424..00000000 --- a/src/AST/typearrow.go +++ /dev/null @@ -1,159 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares one of the basic types used for typing the prover : - * TypeArrow, the -> operator. It's implemented as an input scheme (TypeApp) - * and output arguments (array of TypeScheme). - **/ - -package AST - -import ( - "fmt" - "strings" - - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * Type consisting of two TypeSchemes : the in-arguments parameter(s) and the out parameter. - * For example, if a function f takes to parameters of type int, and returns an int, it - * will be typed as f : (int * int) -> int - * TypeCross has higher precedence than TypeArrow. - **/ -type TypeArrow struct { - left TypeApp - right Lib.ComparableList[TypeApp] -} - -/* TypeScheme interface */ -// Unexported methods. -func (ta TypeArrow) isScheme() {} -func (ta TypeArrow) toMappedString(subst map[string]string) string { - mappedString := []string{Glob.To[TypeScheme](ta.left).toMappedString(subst)} - for _, typeScheme := range convert(ta.right, typeAppToTypeScheme) { - mappedString = append(mappedString, typeScheme.toMappedString(subst)) - } - return "(" + strings.Join(mappedString, " > ") + ")" -} - -/* TypeArrow methods */ -func (ta TypeArrow) substitute(mapSubst map[TypeVar]string) TypeScheme { - return MkTypeArrow(ta.left.substitute(mapSubst).(TypeApp), substTypeAppList(mapSubst, ta.right)...) -} -func (ta TypeArrow) instanciate(mapSubst map[TypeVar]TypeApp) TypeScheme { - return MkTypeArrow(ta.left.instanciate(mapSubst), instanciateList(mapSubst, ta.right)...) -} - -// Exported methods. -/** - * Returns a string of a TypeArrow: (type1 > type2 > ... > typeN). - **/ -func (ta TypeArrow) ToString() string { - list := []string{ta.left.ToString()} - list = append(list, convert(ta.right, typeTToString[TypeApp])...) - return "(" + strings.Join(list, " > ") + ")" -} - -func (ta TypeArrow) Equals(oth interface{}) bool { - if !Glob.Is[TypeArrow](oth) { - return false - } - - othTA := Glob.To[TypeArrow](oth) - return ((ta.left == nil && othTA.left == nil) || ta.left.Equals(othTA.left)) && ta.right.Equals(othTA.right) -} - -func (ta TypeArrow) Size() int { - return ta.left.Size() + sum(convert(ta.right, typeTToSize[TypeApp])) -} - -func (ta TypeArrow) GetPrimitives() []TypeApp { - typeApp := []TypeApp{} - typeApp = typeAppToUnderlyingType(typeApp, ta.left) - return append(typeApp, convert(ta.right, typeAppToUnderlyingType)...) -} - -/* Makes a TypeArrow from two TypeSchemes */ -func MkTypeArrow(left TypeApp, typeApps ...TypeApp) TypeArrow { - if len(typeApps) < 1 { - debug(Lib.MkLazy(func() string { return "There should be at least one out type in a TypeArrow." })) - return TypeArrow{} - } - ta := TypeArrow{left: left, right: make(Lib.ComparableList[TypeApp], len(typeApps))} - copy(ta.right, typeApps) - return ta -} - -/* Gets the out type of an arrow type scheme */ -func GetOutType(typeScheme TypeScheme) TypeApp { - switch t := typeScheme.(type) { - case TypeArrow: - // Returns the out type of the last arrow. - return GetOutType(Glob.To[TypeScheme](t.right[len(t.right)-1])) - case QuantifiedType: - vars := make(map[TypeVar]string) - for i, var_ := range t.vars { - vars[MkTypeVar(fmt.Sprintf("*_%d", i))] = var_.ToString() - } - - if Glob.Is[TypeArrow](t.scheme) { - return GetOutType(Glob.To[TypeArrow](t.scheme).substitute(vars)) - } else { - return GetOutType(Glob.To[TypeApp](t.scheme).substitute(vars)) - } - // typeScheme may be a TypeHint if it comes from a constant. - case TypeHint: - return t - // Everything else is a TypeApp anyways - default: - return t.(TypeApp) - } -} - -/* Gets the input type of an arrow type scheme */ -func GetInputType(typeScheme TypeScheme) Lib.ComparableList[TypeApp] { - switch t := typeScheme.(type) { - case QuantifiedType: - return GetInputType(t.scheme) - case TypeArrow: - typeArrow := Glob.To[TypeArrow](typeScheme) - list := Lib.ComparableList[TypeApp]{typeArrow.left} - list = append(list, typeArrow.right[:len(typeArrow.right)-1]...) - return list - case TypeApp: - return []TypeApp{t} - } - return nil -} diff --git a/src/AST/typecross.go b/src/AST/typecross.go deleted file mode 100644 index 73466cb1..00000000 --- a/src/AST/typecross.go +++ /dev/null @@ -1,129 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares one of the basic types used for typing the prover : - * TypeCross, a conjonction of types. It's a list of TypeApp. - * A TypeArrow can not be a child of a conjonction in first order (no currification occurs). - * Otherwise, the children would be of type TypeScheme. - **/ - -package AST - -import ( - "strings" - - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * A conjonction of types. - * The UID is calculated on creation. - * Please, use MkTypeCross() to make a new TypeCross. - * It's used, for example, for function or predicate arguments. - * For example, take the function + on natural numbers. It takes 2 integers as arguments : - * +: int*int > int - * This notation is the same as +: int > int > int (as > is an imply, - * not(int) v not(int) v int is equivalent to not(int ^ int) v int = int * int > int). - **/ -type TypeCross struct { - types Lib.ComparableList[TypeApp] -} - -/* TypeScheme interface */ -// Non-exported methods. -func (tc TypeCross) isScheme() {} -func (tc TypeCross) toMappedString(subst map[string]string) string { - mappedString := []string{} - for _, typeScheme := range convert(tc.types, typeAppToTypeScheme) { - mappedString = append(mappedString, typeScheme.toMappedString(subst)) - } - if Glob.IsLambdapiOutput() { - return strings.Join(mappedString, " → ") - } - return "(" + strings.Join(mappedString, " * ") + ")" -} - -// Exported methods. -func (tc TypeCross) ToString() string { - if Glob.IsLambdapiOutput() { - return strings.Join(convert(tc.types, typeTToString[TypeApp]), " → ") - } - return "(" + strings.Join(convert(tc.types, typeTToString[TypeApp]), " * ") + ")" -} -func (tc TypeCross) Size() int { return sum(convert(tc.types, typeTToSize[TypeApp])) } - -// GetAllUnderlyingTypes ? Or just tc.types ? I'm thinking the 2nd is better cause the first looses associativity ? Is it fine ? -func (tc TypeCross) GetPrimitives() []TypeApp { return tc.GetAllUnderlyingTypes() } - -func (tc TypeCross) Equals(oth interface{}) bool { - return Glob.Is[TypeCross](oth) && tc.types.Equals(Glob.To[TypeCross](oth).types) -} - -/* TypeApp interface */ -// Non-exported methods. -func (tc TypeCross) isTypeApp() {} -func (tc TypeCross) substitute(mapSubst map[TypeVar]string) TypeScheme { - return MkTypeCross(substTypeAppList(mapSubst, tc.types)...) -} -func (tc TypeCross) instanciate(mapSubst map[TypeVar]TypeApp) TypeApp { - return MkTypeCross(instanciateList(mapSubst, tc.types)...) -} - -// Exported methods. -/** - * Copies the TypeApp slice to avoid wrong modifications. - **/ -func (tc TypeCross) Copy() TypeApp { - return MkTypeCross(convert(tc.types, copyTypeApp)...) -} - -/** - * Returns all primitive types composing this cross type. - **/ -func (tc TypeCross) GetAllUnderlyingTypes() []TypeApp { - return convert(tc.types, typeAppToUnderlyingType) -} - -/** - * Makes a TypeCross from any number of TypeApp. - **/ -func MkTypeCross(typeSchemes ...TypeApp) TypeCross { - if len(typeSchemes) < 2 { - debug(Lib.MkLazy(func() string { return "There should be at least two underlying types in a TypeCross." })) - return TypeCross{} - } - tc := TypeCross{types: make([]TypeApp, len(typeSchemes))} - copy(tc.types, typeSchemes) - return tc -} diff --git a/src/AST/typed-vars.go b/src/AST/typed-vars.go new file mode 100644 index 00000000..05254f77 --- /dev/null +++ b/src/AST/typed-vars.go @@ -0,0 +1,107 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** +* This file implements an interface for bound variables. +**/ + +package AST + +import ( + "github.com/GoelandProver/Goeland/Lib" +) + +type TypedVar struct { + name string + index int + ty Ty +} + +func (v TypedVar) Copy() TypedVar { + return TypedVar{v.name, v.index, v.ty.Copy()} +} + +func (v TypedVar) Equals(oth any) bool { + if ov, ok := oth.(TypedVar); ok { + return v.name == ov.name && v.index == ov.index && + v.ty.Equals(ov.ty) + } + return false +} + +func (v TypedVar) ToString() string { + return printer.StrTyVar(Lib.MkPair(v.name, v.ty)) +} + +func (v TypedVar) GetName() string { + return v.name +} + +func (v TypedVar) GetIndex() int { + return v.index +} + +func (v TypedVar) GetTy() Ty { + return v.ty +} + +func (v TypedVar) ToBoundVar() Var { + return MakeVar(v.index, v.name) +} + +func (v TypedVar) ToTyBoundVar() TyBound { + return MkTyBV(v.name, v.index).(TyBound) +} + +func (v TypedVar) SubstTy(old TyGenVar, new Ty) TypedVar { + return TypedVar{v.name, v.index, v.ty.SubstTy(old, new)} +} + +func MkTypedVar(name string, index int, ty Ty) TypedVar { + return TypedVar{name, index, ty} +} + +func MakerTypedVar(name string, ty Ty) TypedVar { + lock_term.Lock() + i, ok := idVar[name] + lock_term.Unlock() + if ok { + return MkTypedVar(name, i, ty) + } else { + lock_term.Lock() + idVar[name] = cpt_term + vr := MkTypedVar(name, cpt_term, ty) + cpt_term += 1 + lock_term.Unlock() + return vr + } +} diff --git a/src/AST/typehint.go b/src/AST/typehint.go deleted file mode 100644 index 9732181f..00000000 --- a/src/AST/typehint.go +++ /dev/null @@ -1,120 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares the basic types used for typing the prover : - * TypeHint, a primitive type that is used as the basis of the inductive relation - **/ - -package AST - -import ( - "sync" - - "github.com/GoelandProver/Goeland/Glob" -) - -/** - * Primitive type composed of an unique identifier, used to identify it from - * other types, and a name, used for printing options. - **/ -type TypeHint struct { - uid uint64 /* Real ID */ - name string /* Name */ -} - -/* TypeScheme interface */ -// Non-exported methods -func (th TypeHint) isScheme() {} -func (th TypeHint) toMappedString(subst map[string]string) string { return th.ToString() } - -// Exported methods -func (th TypeHint) ToString() string { return th.name } -func (th TypeHint) Size() int { return 1 } -func (th TypeHint) GetPrimitives() []TypeApp { return []TypeApp{th} } - -func (th TypeHint) Equals(oth interface{}) bool { - return Glob.Is[TypeHint](oth) && Glob.To[TypeHint](oth).uid == th.uid -} - -/* TypeApp interface */ -// Non-exported methods -func (th TypeHint) isTypeApp() {} -func (th TypeHint) substitute(mapSubst map[TypeVar]string) TypeScheme { return th } -func (th TypeHint) instanciate(map[TypeVar]TypeApp) TypeApp { return th } - -// Exported methods -func (th TypeHint) Copy() TypeApp { return MkTypeHint(th.name) } - -/* Current unused unique identifier. Comes with a lock. */ -var tCounter struct { - count uint64 - lock sync.Mutex -} - -/* Map of all the unique identifiers of the different types based on their name. */ -var tMap struct { - uidsMap map[string]TypeHint - lock sync.Mutex -} - -/** - * Makes a TypeHint. - * If the name of the type already exists in the map, returns it. - * Else, creates a new TypeHint with a new unique identifier and updates the map recording - * the types. - **/ -func MkTypeHint(typeName string) TypeHint { - // 1 - search if the type is already declared. Returns it if it's found. - tMap.lock.Lock() - if tHint, found := tMap.uidsMap[typeName]; found { - tMap.lock.Unlock() - return tHint - } - tMap.lock.Unlock() - - // 2 - creation of a new type. - tCounter.lock.Lock() - tHint := TypeHint{ - uid: tCounter.count, - name: typeName, - } - tCounter.count += 1 - tCounter.lock.Unlock() - - // 3 - update of the map. - tMap.lock.Lock() - tMap.uidsMap[typeName] = tHint - tMap.lock.Unlock() - - return tHint -} diff --git a/src/AST/typevar.go b/src/AST/typevar.go deleted file mode 100644 index 3051df64..00000000 --- a/src/AST/typevar.go +++ /dev/null @@ -1,126 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file declares one of the basic types used for typing the prover : - * TypeVar, a variable of type. - **/ - -package AST - -import ( - "github.com/GoelandProver/Goeland/Glob" -) - -const ( - BAD_INDEX = -1 -) - -/** - * A quantified variable of type. - * It can serve in arguments of a function or predicate. - **/ -type TypeVar struct { - name string - metaInfo struct { - formulaIndex int - index int - occurence int - } -} - -/* TypeScheme interface */ -// Non-exported methods. -func (tv TypeVar) isScheme() {} -func (tv TypeVar) toMappedString(subst map[string]string) string { - if substString, inMap := subst[tv.name]; inMap { - return substString - } - return tv.name -} - -// Exported methods. -func (tv TypeVar) ToString() string { return tv.name } -func (tv TypeVar) Size() int { return 1 } -func (tv TypeVar) GetPrimitives() []TypeApp { return []TypeApp{tv} } - -func (tv TypeVar) Equals(oth interface{}) bool { - if tv.metaInfo.formulaIndex != BAD_INDEX && tv.metaInfo.index != BAD_INDEX { - return true - } - if !Glob.Is[TypeVar](oth) { - return false - } - typeVar := Glob.To[TypeVar](oth) - return typeVar.name == tv.name && typeVar.metaInfo == tv.metaInfo -} - -/* TypeApp interface */ -func (tv TypeVar) isTypeApp() {} - -func (tv TypeVar) substitute(mapSubst map[TypeVar]string) TypeScheme { - newTv := tv.Copy().(TypeVar) - newTv.name = mapSubst[tv] - return newTv -} - -func (tv TypeVar) instanciate(mapSubst map[TypeVar]TypeApp) TypeApp { - if typeApp, found := mapSubst[tv]; found { - return typeApp - } else { - return tv - } -} - -func (tv TypeVar) Copy() TypeApp { - newTv := MkTypeVar(tv.name) - newTv.metaInfo = tv.metaInfo - return newTv -} - -/* TypeVar should be converted to Meta when becoming a term */ -func (tv *TypeVar) ShouldBeMeta(formula int) { tv.metaInfo.formulaIndex = formula } -func (tv *TypeVar) Instantiate(index int) { tv.metaInfo.index = index } -func (tv TypeVar) IsMeta() bool { return tv.metaInfo.formulaIndex != BAD_INDEX } -func (tv TypeVar) Instantiated() bool { return tv.metaInfo.index != BAD_INDEX } -func (tv TypeVar) MetaInfos() (int, int, int) { - return tv.metaInfo.formulaIndex, tv.metaInfo.index, tv.metaInfo.occurence -} - -/* Makes a TypeVar from a name */ -func MkTypeVar(name string) TypeVar { - return TypeVar{name, struct { - formulaIndex int - index int - occurence int - }{BAD_INDEX, BAD_INDEX, BAD_INDEX}} -} diff --git a/src/AST/typing_utils.go b/src/AST/typing_utils.go deleted file mode 100644 index 14b00541..00000000 --- a/src/AST/typing_utils.go +++ /dev/null @@ -1,118 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -/** - * This file stores various utils functions for typing. - **/ - -package AST - -import ( - "github.com/GoelandProver/Goeland/Glob" -) - -type Type interface { - Size() int - ToString() string -} - -/** - * Converts a TypeApp to a TypeScheme. - * If the TypeApp is not a TypeScheme, it doesn't do anything. - **/ -func typeAppToTypeScheme(ls []TypeScheme, in TypeApp) []TypeScheme { - if typeScheme := Glob.To[TypeScheme](in); Glob.Is[TypeScheme](in) { - return append(ls, typeScheme) - } - return ls -} - -/** - * Adds input TypeScheme argument String to the list. - * Should be used on call to convert function. - **/ -func typeTToString[T Type](ls []string, in T) []string { - return append(ls, in.ToString()) -} - -/** - * Adds the size of the TypeScheme argument to the list. - * Should be used on call to convert function. - **/ -func typeTToSize[T Type](ls []int, in T) []int { - return append(ls, in.Size()) -} - -/** - * Copies in to the list. - * Use in convert function as a lambda. - **/ -func copyTypeApp(ls []TypeApp, in TypeApp) []TypeApp { - return append(ls, in.Copy()) -} - -/** - * Adds underlying types of the TypeApp argument to the list. - * Should be used on call to convert function. - **/ -func typeAppToUnderlyingType(ls []TypeApp, in TypeApp) []TypeApp { - if tc, isTc := in.(TypeCross); isTc { - return append(ls, tc.GetAllUnderlyingTypes()...) - } else { - return append(ls, in) - } -} - -/** - * Factorizes the loop needed to populate a list of elements with a new type. - * It needs : - * - the original list - * - a transformation function, taking as input the transformed list and the current element. - * If the current element doesn't fit the model of the transformation, you can just return - * the list. Else, append the transformed element to the list and return it. - **/ -func convert[T any, U any](list []T, transform func([]U, T) []U) []U { - transformedList := []U{} - for _, element := range list { - transformedList = transform(transformedList, element) - } - return transformedList -} - -/** Sums a list. **/ -func sum(list []int) int { - s := 0 - for _, element := range list { - s += element - } - return s -} diff --git a/src/Core/FormListDS.go b/src/Core/FormListDS.go index cc31e8b0..d3dcb7ca 100644 --- a/src/Core/FormListDS.go +++ b/src/Core/FormListDS.go @@ -38,30 +38,34 @@ import ( ) type FormListDS struct { - fl *AST.FormList + fl Lib.List[AST.Form] } -func (f FormListDS) GetFL() *AST.FormList { - return f.fl.Copy() +func (f FormListDS) GetFL() Lib.List[AST.Form] { + return Lib.ListCpy(f.fl) } /* Data struct */ /* Take a list of formula and return a FormList (Datastructure type) */ -func (f FormListDS) MakeDataStruct(lf *AST.FormList, is_pos bool) Unif.DataStructure { +func (f FormListDS) MakeDataStruct(lf Lib.List[AST.Form], is_pos bool) Unif.DataStructure { return (new(FormListDS)).InsertFormulaListToDataStructure(lf) } /* Insert a list of formula into the given Datastructure (here, FormList) */ -func (f FormListDS) InsertFormulaListToDataStructure(lf *AST.FormList) Unif.DataStructure { - for _, v := range lf.Slice() { +func (f FormListDS) InsertFormulaListToDataStructure(lf Lib.List[AST.Form]) Unif.DataStructure { + for _, v := range lf.GetSlice() { switch nf := v.(type) { case AST.Pred: - f.fl.AppendIfNotContains(nf) + if !Lib.ListMem(nf.Copy(), f.fl) { + f.fl.Append(nf) + } case AST.Not: switch nf.GetForm().(type) { case AST.Pred: - f.fl.AppendIfNotContains(nf.GetForm()) + if !Lib.ListMem(nf.Copy(), f.fl) { + f.fl.Append(nf) + } } } } @@ -69,24 +73,24 @@ func (f FormListDS) InsertFormulaListToDataStructure(lf *AST.FormList) Unif.Data } func (f FormListDS) Print() { - for _, f := range f.GetFL().Slice() { + for _, f := range f.GetFL().GetSlice() { debug(Lib.MkLazy(func() string { return f.ToString() })) } } func (f FormListDS) Copy() Unif.DataStructure { - return FormListDS{f.GetFL().Copy()} + return FormListDS{Lib.ListCpy(f.GetFL())} } func (fl FormListDS) IsEmpty() bool { - return fl.GetFL().IsEmpty() + return fl.GetFL().Empty() } -func (fl FormListDS) Unify(f AST.Form) (bool, []Unif.MatchingSubstitutions) { - for _, element := range fl.GetFL().Slice() { +func (fl FormListDS) Unify(f AST.Form) (bool, []Unif.MixedSubstitutions) { + for _, element := range fl.GetFL().GetSlice() { if element.Equals(f) { - return true, []Unif.MatchingSubstitutions{} + return true, []Unif.MixedSubstitutions{} } } - return false, []Unif.MatchingSubstitutions{} + return false, []Unif.MixedSubstitutions{} } diff --git a/src/Core/Sko/inner-skolemization.go b/src/Core/Sko/inner-skolemization.go index 4d3d9ac8..3db9f882 100644 --- a/src/Core/Sko/inner-skolemization.go +++ b/src/Core/Sko/inner-skolemization.go @@ -47,36 +47,35 @@ import ( type InnerSkolemization struct { existingSymbols Lib.Set[AST.Id] - mu sync.Mutex + mu *sync.Mutex } func MkInnerSkolemization() InnerSkolemization { return InnerSkolemization{ existingSymbols: Lib.EmptySet[AST.Id](), - mu: sync.Mutex{}, + mu: &sync.Mutex{}, } } func (sko InnerSkolemization) Skolemize( _, form AST.Form, - x AST.Var, + x AST.TypedVar, _ Lib.Set[AST.Meta], ) (Skolemization, AST.Form) { sko.mu.Lock() - symbol := genFreshSymbol(&sko.existingSymbols, sko.mu, x) + symbol := genFreshSymbol(&sko.existingSymbols, x) sko.mu.Unlock() internalMetas := form.GetMetas().Elements() skolemFunc := AST.MakerFun( symbol, + Lib.NewList[AST.Ty](), Lib.ListMap(internalMetas, Glob.To[AST.Term]), - []AST.TypeApp{}, - mkSkoFuncType(internalMetas, x.GetTypeApp()), ) skolemizedForm, _ := form.ReplaceTermByTerm( - Glob.To[AST.Term](x), + x.ToBoundVar(), Glob.To[AST.Term](skolemFunc), ) diff --git a/src/Core/Sko/interface.go b/src/Core/Sko/interface.go index a79ba10e..8ef14586 100644 --- a/src/Core/Sko/interface.go +++ b/src/Core/Sko/interface.go @@ -34,10 +34,8 @@ package Sko import ( "fmt" - "sync" "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) @@ -54,49 +52,19 @@ type Skolemization interface { Skolemize( AST.Form, AST.Form, - AST.Var, + AST.TypedVar, Lib.Set[AST.Meta], ) (Skolemization, AST.Form) } -func mkSkoFuncType( - relevantMetas Lib.List[AST.Meta], - varType AST.TypeApp, -) AST.TypeScheme { - var resultingScheme AST.TypeScheme - - switch relevantMetas.Len() { - case 0: - if typ, ok := varType.(AST.TypeScheme); ok { - resultingScheme = typ - } else { - Glob.Anomaly("Skolemization", "Variable has an illegal type") - } - case 1: - metaType := relevantMetas.At(0).GetTypeApp() - resultingScheme = AST.MkTypeArrow(metaType, varType) - default: - argTypes := Lib.ListMap( - relevantMetas, - func(x AST.Meta) AST.TypeApp { return x.GetTypeApp() }, - ) - resultingScheme = AST.MkTypeArrow( - AST.MkTypeCross(argTypes.GetSlice()...), - varType, - ) - } - - return resultingScheme -} - /* If every Skolem symbol is created using this function, then it will generate * a fresh symbol for sure. Otherwise, nothing is guaranteed. */ -func genFreshSymbol(existingSymbols *Lib.Set[AST.Id], mu sync.Mutex, x AST.Var) AST.Id { +func genFreshSymbol(existingSymbols *Lib.Set[AST.Id], x AST.TypedVar) AST.Id { symbol := AST.MakerNewId( - fmt.Sprintf("skolem@%v", x.GetName()), + fmt.Sprintf("skolem@%v@%d", x.GetName(), existingSymbols.Cardinal()), ) - existingSymbols.Add(symbol) + *existingSymbols = existingSymbols.Add(symbol) return symbol } diff --git a/src/Core/Sko/outer-skolemization.go b/src/Core/Sko/outer-skolemization.go index 14c7bfa9..1cfa7fa8 100644 --- a/src/Core/Sko/outer-skolemization.go +++ b/src/Core/Sko/outer-skolemization.go @@ -47,36 +47,35 @@ import ( type OuterSkolemization struct { existingSymbols Lib.Set[AST.Id] - mu sync.Mutex + mu *sync.Mutex } func MkOuterSkolemization() OuterSkolemization { return OuterSkolemization{ existingSymbols: Lib.EmptySet[AST.Id](), - mu: sync.Mutex{}, + mu: &sync.Mutex{}, } } func (sko OuterSkolemization) Skolemize( _, form AST.Form, - x AST.Var, + x AST.TypedVar, fvs Lib.Set[AST.Meta], ) (Skolemization, AST.Form) { sko.mu.Lock() - symbol := genFreshSymbol(&sko.existingSymbols, sko.mu, x) + symbol := genFreshSymbol(&sko.existingSymbols, x) sko.mu.Unlock() metas := fvs.Elements() skolemFunc := AST.MakerFun( symbol, + Lib.NewList[AST.Ty](), Lib.ListMap(metas, Glob.To[AST.Term]), - []AST.TypeApp{}, - mkSkoFuncType(metas, x.GetTypeApp()), ) skolemizedForm, _ := form.ReplaceTermByTerm( - Glob.To[AST.Term](x), + x.ToBoundVar(), Glob.To[AST.Term](skolemFunc), ) diff --git a/src/Core/Sko/preinner-skolemization.go b/src/Core/Sko/preinner-skolemization.go index ae155d71..b81cd965 100644 --- a/src/Core/Sko/preinner-skolemization.go +++ b/src/Core/Sko/preinner-skolemization.go @@ -49,20 +49,20 @@ import ( type PreInnerSkolemization struct { existingSymbols Lib.Set[AST.Id] linkedSymbols Lib.List[Glob.Pair[AST.Form, AST.Id]] - mu sync.Mutex + mu *sync.Mutex } func MkPreInnerSkolemization() PreInnerSkolemization { return PreInnerSkolemization{ existingSymbols: Lib.EmptySet[AST.Id](), linkedSymbols: Lib.NewList[Glob.Pair[AST.Form, AST.Id]](), - mu: sync.Mutex{}, + mu: &sync.Mutex{}, } } func (sko PreInnerSkolemization) Skolemize( delta, form AST.Form, - x AST.Var, + x AST.TypedVar, _ Lib.Set[AST.Meta], ) (Skolemization, AST.Form) { realDelta := alphaConvert(delta, 0, make(map[int]AST.Var)) @@ -75,7 +75,7 @@ func (sko PreInnerSkolemization) Skolemize( ); ok { symbol = val.Snd } else { - symbol = genFreshSymbol(&sko.existingSymbols, sko.mu, x) + symbol = genFreshSymbol(&sko.existingSymbols, x) sko.linkedSymbols.Append(Glob.MakePair(realDelta, symbol)) } sko.mu.Unlock() @@ -84,13 +84,12 @@ func (sko PreInnerSkolemization) Skolemize( skolemFunc := AST.MakerFun( symbol, + Lib.NewList[AST.Ty](), Lib.ListMap(internalMetas, Glob.To[AST.Term]), - []AST.TypeApp{}, - mkSkoFuncType(internalMetas, x.GetTypeApp()), ) skolemizedForm, _ := form.ReplaceTermByTerm( - Glob.To[AST.Term](x), + x.ToBoundVar(), Glob.To[AST.Term](skolemFunc), ) @@ -117,9 +116,8 @@ func alphaConvert( return AST.MakePred( f.GetIndex(), f.GetID(), + f.GetTyArgs(), mappedTerms, - f.GetTypeVars(), - f.GetType(), ) case AST.Not: return AST.MakeNot( @@ -141,9 +139,9 @@ func alphaConvert( case AST.And: return AST.MakeAnd( f.GetIndex(), - AST.NewFormList( + Lib.MkListV( Glob.MapTo( - f.FormList.Slice(), + f.GetChildFormulas().GetSlice(), func(_ int, f AST.Form) AST.Form { return alphaConvert(f, k, substitution) })...), @@ -151,8 +149,8 @@ func alphaConvert( case AST.Or: return AST.MakeOr( f.GetIndex(), - AST.NewFormList(Glob.MapTo( - f.FormList.Slice(), + Lib.MkListV(Glob.MapTo( + f.GetChildFormulas().GetSlice(), func(_ int, f AST.Form) AST.Form { return alphaConvert(f, k, substitution) })...), @@ -164,21 +162,25 @@ func alphaConvert( k, substitution, vl := makeConvertedVarList(k, substitution, f.GetVarList()) return AST.MakeEx(f.GetIndex(), vl, alphaConvert(f.GetForm(), k, substitution)) } + Glob.Anomaly( + "preinner", + fmt.Sprintf("On alpha-conversion of %s: form does not correspond to any known ones", form.ToString()), + ) return form } func makeConvertedVarList( k int, substitution map[int]AST.Var, - vl []AST.Var, -) (int, map[int]AST.Var, []AST.Var) { - newVarList := []AST.Var{} - for i, v := range vl { - nv := AST.MakeVar(k+i, fresh(k+i), v.GetTypeApp()) - newVarList = append(newVarList, nv) - substitution[v.GetIndex()] = nv + vl Lib.List[AST.TypedVar], +) (int, map[int]AST.Var, Lib.List[AST.TypedVar]) { + newVarList := Lib.MkList[AST.TypedVar](vl.Len()) + for i, v := range vl.GetSlice() { + nv := AST.MkTypedVar(fresh(k+i), k+i, v.GetTy()) + newVarList.Upd(i, nv) + substitution[v.GetIndex()] = nv.ToBoundVar() } - return k + len(vl), substitution, newVarList + return k + vl.Len(), substitution, newVarList } func alphaConvertTerm(t AST.Term, substitution map[int]AST.Var) AST.Term { @@ -196,9 +198,8 @@ func alphaConvertTerm(t AST.Term, substitution map[int]AST.Var) AST.Term { }) return AST.MakerFun( nt.GetID(), + nt.GetTyArgs(), mappedTerms, - nt.GetTypeVars(), - nt.GetTypeHint(), ) } return t diff --git a/src/Core/form_and_terms.go b/src/Core/form_and_terms.go index fc05cc52..0a9e3234 100644 --- a/src/Core/form_and_terms.go +++ b/src/Core/form_and_terms.go @@ -38,7 +38,6 @@ package Core import ( "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) @@ -81,7 +80,7 @@ func (fat FormAndTerms) Equals(fat2 FormAndTerms) bool { } func (fat FormAndTerms) ToString() string { - return fat.GetForm().ToMappedString(AST.DefaultMapString, Glob.GetTypeProof()) + return fat.GetForm().ToString() } func (fat FormAndTerms) SubstituteBy( diff --git a/src/Core/form_and_terms_list.go b/src/Core/form_and_terms_list.go index 077726e4..f10b0d98 100644 --- a/src/Core/form_and_terms_list.go +++ b/src/Core/form_and_terms_list.go @@ -110,9 +110,9 @@ func (fl FormAndTermsList) Copy() FormAndTermsList { } /* Create a FaT List from a FormList */ -func MakeFTListFromFormList(l *AST.FormList) FormAndTermsList { +func MakeFTListFromFormList(l Lib.List[AST.Form]) FormAndTermsList { res := MakeEmptyFormAndTermsList() - for _, f := range l.Slice() { + for _, f := range l.GetSlice() { res = append(res, MakeFormAndTerm(f.Copy(), Lib.MkList[AST.Term](0))) } return res @@ -183,10 +183,10 @@ func (l1 FormAndTermsList) Merge(l2 FormAndTermsList) FormAndTermsList { return res } -func (fl FormAndTermsList) ExtractForms() *AST.FormList { - res := AST.NewFormList() +func (fl FormAndTermsList) ExtractForms() Lib.List[AST.Form] { + res := Lib.NewList[AST.Form]() for _, f := range fl { - res.AppendIfNotContains(f.GetForm()) + res = Lib.ListAdd(res, f.GetForm()) } return res } diff --git a/src/Core/global_unifier.go b/src/Core/global_unifier.go index 3657dca0..089d6e42 100644 --- a/src/Core/global_unifier.go +++ b/src/Core/global_unifier.go @@ -41,7 +41,7 @@ import ( "github.com/GoelandProver/Goeland/Unif" ) -type substitutions = Unif.Substitutions +type substitutions = Lib.List[Unif.MixedSubstitution] /* - The unifier type is a type that keeps the substitutions that close the whole subtree. @@ -86,7 +86,7 @@ func (u *Unifier) AddSubstitutions(cleanedSubst, actualSubst substitutions) { } found := false for i, p := range u.localUnifiers { - if p.Fst.Equals(cleanedSubst) { + if Lib.ListEquals(p.Fst, cleanedSubst) { u.localUnifiers[i].Snd = append(u.localUnifiers[i].Snd, actualSubst) found = true } @@ -102,8 +102,8 @@ func (u *Unifier) PruneUncompatibleSubstitutions(subst substitutions) { } res := make([]Glob.Pair[substitutions, []substitutions], 0) for _, p := range u.localUnifiers { - compat, _ := Unif.MergeSubstitutions(subst, p.Fst) - if !compat.Equals(Unif.Failure()) { + _, succeeded := Unif.MergeMixedSubstitutions(subst, p.Fst) + if succeeded { res = append(res, p) } } @@ -115,29 +115,34 @@ func (u Unifier) IsEmpty() bool { } func (u Unifier) ToString() string { - substsToString := func(index int, element Unif.Substitution) string { - return fmt.Sprintf("(%s -> %s)", element.Key().ToString(), element.Value().ToString()) - } str := "object Unifier{" for _, unifier := range u.localUnifiers { - str += "[ " + strings.Join(Glob.MapTo(unifier.Fst, substsToString), ", ") + " ] --> [ " + strings.Join(Glob.MapTo(unifier.Snd, func(_ int, el substitutions) string { - return strings.Join(Glob.MapTo(el, substsToString), " ; ") - }), " ---- ") + " ], " + str += fmt.Sprintf( + "[ %s ] --> [ %s ]", + Lib.ListToString(unifier.Fst, ", ", ""), + strings.Join(Glob.MapTo( + unifier.Snd, + func(_ int, el substitutions) string { + return Lib.ListToString(el, ", ", "") + }), + " ; ", + ), + ) } str += "}" return str } /** Returns a global unifier: MGU of all the unifiers found */ -func (u Unifier) GetUnifier() Unif.Substitutions { +func (u Unifier) GetUnifier() substitutions { if !Glob.GetProof() || len(u.localUnifiers) == 0 { - return Unif.MakeEmptySubstitution() + return Lib.NewList[Unif.MixedSubstitution]() } debug(Lib.MkLazy(func() string { return u.ToString() })) if len(u.localUnifiers) > 0 && len(u.localUnifiers[0].Snd) > 0 { return u.localUnifiers[0].Snd[0] } - return Unif.MakeEmptySubstitution() + return Lib.NewList[Unif.MixedSubstitution]() } func (u Unifier) Copy() Unifier { @@ -148,9 +153,9 @@ func (u Unifier) Copy() Unifier { for i, unif := range u.localUnifiers { copy := []substitutions{} for _, subst := range unif.Snd { - copy = append(copy, subst.Copy()) + copy = append(copy, Lib.ListCpy(subst)) } - newLocalUnifier[i] = Glob.MakePair(unif.Fst.Copy(), copy) + newLocalUnifier[i] = Glob.MakePair(Lib.ListCpy(unif.Fst), copy) } return Unifier{ localUnifiers: newLocalUnifier, @@ -178,12 +183,12 @@ func (u *Unifier) Merge(other Unifier) { for _, locUnif := range u.localUnifiers { for _, unifier := range other.localUnifiers { newUnifs := []substitutions{} - res, _ := Unif.MergeSubstitutions(unifier.Fst.Copy(), locUnif.Fst.Copy()) - if !res.Equals(Unif.Failure()) { + res, succeeded := Unif.MergeMixedSubstitutions(unifier.Fst, locUnif.Fst) + if succeeded { for _, subst := range locUnif.Snd { for _, s := range unifier.Snd { - merge, _ := Unif.MergeSubstitutions(subst.Copy(), s.Copy()) - if !merge.Equals(Unif.Failure()) { + merge, success := Unif.MergeMixedSubstitutions(subst, s) + if success { newUnifs = append(newUnifs, merge) } } @@ -199,9 +204,18 @@ func (u *Unifier) Merge(other Unifier) { func (u *Unifier) PruneMetasInSubsts(metas Lib.Set[AST.Meta]) { for i, unif := range u.localUnifiers { for _, meta := range metas.Elements().GetSlice() { - _, index := unif.Fst.Get(meta) - if index != -1 { - u.localUnifiers[i].Fst.Remove(index) + index := Lib.MkNone[int]() + for j, subst := range unif.Fst.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + if s.Val.Key().Equals(meta) { + index = Lib.MkSome(j) + } + } + } + switch id := index.(type) { + case Lib.Some[int]: + u.localUnifiers[i].Fst.RemoveAt(id.Val) } } } @@ -214,7 +228,7 @@ func (u *Unifier) PruneMetasInSubsts(metas Lib.Set[AST.Meta]) { func appendNewUnifiersIfNeeded(unifiers []Glob.Pair[substitutions, []substitutions], res substitutions, newUnifs []substitutions) []Glob.Pair[substitutions, []substitutions] { for i, unif := range unifiers { - if unif.Fst.Equals(res) { + if Lib.ListEquals(unif.Fst, res) { unifiers[i].Snd = append(unifiers[i].Snd, newUnifs...) return unifiers } diff --git a/src/Core/instanciation.go b/src/Core/instanciation.go index 44721858..4b1373b3 100644 --- a/src/Core/instanciation.go +++ b/src/Core/instanciation.go @@ -49,7 +49,7 @@ const ( * Instantiates once the formula fnt. */ func Instantiate(fnt FormAndTerms, index int) (FormAndTerms, Lib.Set[AST.Meta]) { - var meta AST.Meta + var meta Lib.Option[AST.Meta] terms := fnt.GetTerms() switch f := fnt.GetForm().(type) { @@ -61,31 +61,47 @@ func Instantiate(fnt FormAndTerms, index int) (FormAndTerms, Lib.Set[AST.Meta]) fnt, meta = RealInstantiate(f.GetVarList(), index, is_all, f.GetForm(), terms) } - return fnt, Lib.Singleton(meta) + switch m := meta.(type) { + case Lib.Some[AST.Meta]: + return fnt, Lib.Singleton(m.Val) + case Lib.None[AST.Meta]: + return fnt, Lib.EmptySet[AST.Meta]() + } + + Glob.Anomaly("instantiation", "returned bad option type") + return fnt, Lib.EmptySet[AST.Meta]() } func RealInstantiate( - varList []AST.Var, + varList Lib.List[AST.TypedVar], index, status int, subForm AST.Form, terms Lib.List[AST.Term], -) (FormAndTerms, AST.Meta) { - v := varList[0] - meta := AST.MakerMeta(strings.ToUpper(v.GetName()), index, v.GetTypeHint().(AST.TypeApp)) - subForm = subForm.SubstituteVarByMeta(v, meta) +) (FormAndTerms, Lib.Option[AST.Meta]) { + v := varList.At(0) + var m Lib.Option[AST.Meta] - terms = terms.Copy(AST.Term.Copy) - terms.Add( - AST.TermEquals, - Glob.To[AST.Term](meta), - ) + if AST.IsTType(v.GetTy()) { + meta := AST.MkTyMeta(strings.ToUpper(v.GetName()), index) + subForm = subForm.SubstTy(v.ToTyBoundVar(), meta) + m = Lib.MkNone[AST.Meta]() + } else { + meta := AST.MakerMeta(strings.ToUpper(v.GetName()), index, v.GetTy()) + subForm = subForm.SubstituteVarByMeta(v.ToBoundVar(), meta) + terms = terms.Copy(AST.Term.Copy) + terms.Add( + AST.TermEquals, + Glob.To[AST.Term](meta), + ) + m = Lib.MkSome(meta) + } - if len(varList) > 1 { + if varList.Len() > 1 { if status == is_exists { - ex := AST.MakerEx(varList[1:], subForm) + ex := AST.MakerEx(varList.Slice(1, varList.Len()), subForm) subForm = AST.MakerNot(ex) } else { - subForm = AST.MakerAll(varList[1:], subForm) + subForm = AST.MakerAll(varList.Slice(1, varList.Len()), subForm) } } else { if status == is_exists { @@ -93,5 +109,5 @@ func RealInstantiate( } } - return MakeFormAndTerm(subForm, terms), meta + return MakeFormAndTerm(subForm, terms), m } diff --git a/src/Core/int_subst_and_form.go b/src/Core/int_subst_and_form.go index 8af75b7e..7bf53832 100644 --- a/src/Core/int_subst_and_form.go +++ b/src/Core/int_subst_and_form.go @@ -39,6 +39,7 @@ package Core import ( "strconv" + "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Unif" ) @@ -80,12 +81,12 @@ func (s IntSubstAndForm) Copy() IntSubstAndForm { func (s IntSubstAndForm) ToString() string { res := "{ " + strconv.Itoa(s.GetId_rewrite()) + " - " - if !s.GetSaf().GetSubst().IsEmpty() { - res += s.GetSaf().GetSubst().ToString() + if !s.GetSaf().GetSubst().Empty() { + res += Lib.ListToString(s.GetSaf().GetSubst(), ", ", "[]") } res += " - " - if !s.GetSaf().GetForm().IsEmpty() { - res += s.GetSaf().GetForm().ToString() + if !s.GetSaf().GetForm().Empty() { + res += Lib.ListToString(s.GetSaf().GetForm(), ", ", "[]") } res += " }" @@ -127,8 +128,8 @@ func CopyIntSubstAndFormList(sl []IntSubstAndForm) []IntSubstAndForm { } /* Get a subst list from SubstAndForm lsit */ -func GetSubstListFromIntSubstAndFormList(l []IntSubstAndForm) []Unif.Substitutions { - res := []Unif.Substitutions{} +func GetSubstListFromIntSubstAndFormList(l []IntSubstAndForm) []Lib.List[Unif.MixedSubstitution] { + res := []Lib.List[Unif.MixedSubstitution]{} for _, saf := range l { res = append(res, saf.GetSaf().GetSubst()) } diff --git a/src/Core/rules_type.go b/src/Core/rules_type.go index f4e9935f..08a399ea 100644 --- a/src/Core/rules_type.go +++ b/src/Core/rules_type.go @@ -37,7 +37,6 @@ package Core import ( "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" ) /******************/ @@ -86,8 +85,6 @@ func ShowKindOfRule(f AST.Form) KindOfRule { res = Gamma case AST.All: res = Delta - case AST.AllType: - Glob.Anomaly("Kind of rule", "not forall(type) found when it shouldn't happen.") } case AST.And: res = Alpha @@ -95,7 +92,7 @@ func ShowKindOfRule(f AST.Form) KindOfRule { res = Beta case AST.Ex: res = Delta - case AST.All, AST.AllType: + case AST.All: res = Gamma } return res diff --git a/src/Core/skolemisation.go b/src/Core/skolemisation.go index b18593a4..e8947805 100644 --- a/src/Core/skolemisation.go +++ b/src/Core/skolemisation.go @@ -32,6 +32,7 @@ package Core import ( + "fmt" "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Core/Sko" "github.com/GoelandProver/Goeland/Glob" @@ -93,7 +94,7 @@ func Skolemize(form AST.Form, branchMetas Lib.Set[AST.Meta]) AST.Form { return realSkolemize( form, f.GetForm(), - f.GetVarList()[0], + f.GetVarList().At(0), f.GetVarList(), branchMetas, isNegAll, @@ -105,7 +106,7 @@ func Skolemize(form AST.Form, branchMetas Lib.Set[AST.Meta]) AST.Form { return realSkolemize( form, nf.GetForm(), - nf.GetVarList()[0], + nf.GetVarList().At(0), nf.GetVarList(), branchMetas, isExists, @@ -119,27 +120,35 @@ func Skolemize(form AST.Form, branchMetas Lib.Set[AST.Meta]) AST.Form { func realSkolemize( initialForm, deltaForm AST.Form, - x AST.Var, - allVars []AST.Var, + x AST.TypedVar, + allVars Lib.List[AST.TypedVar], metas Lib.Set[AST.Meta], typ int, ) AST.Form { - sko, res := selectedSkolemization.Skolemize( - initialForm, - deltaForm, - x, - metas, - ) - selectedSkolemization = sko + var res AST.Form + + if AST.IsTType(x.GetTy()) { + id := AST.MakerId("skoTy") + id = AST.MakerId(fmt.Sprintf("skoTy@%d", id.GetIndex())) + res = deltaForm.SubstTy(x.ToTyBoundVar(), AST.MkTyConst(id.ToString())) + } else { + selectedSkolemization, res = selectedSkolemization.Skolemize( + initialForm, + deltaForm, + x, + metas, + ) + } + switch typ { case isNegAll: - if len(allVars) > 1 { - res = AST.MakerAll(allVars[1:], res) + if allVars.Len() > 1 { + res = AST.MakerAll(allVars.Slice(1, allVars.Len()), res) } res = AST.MakerNot(res) case isExists: - if len(allVars) > 1 { - res = AST.MakerEx(allVars[1:], res) + if allVars.Len() > 1 { + res = AST.MakerEx(allVars.Slice(1, allVars.Len()), res) } default: Glob.Anomaly("Skolemization", "impossible reconstruction case") diff --git a/src/Core/statement.go b/src/Core/statement.go index 29fcb21f..5598b747 100644 --- a/src/Core/statement.go +++ b/src/Core/statement.go @@ -50,7 +50,7 @@ func InitDebugger() { type TFFAtomTyping struct { Literal AST.Id - Ts AST.TypeScheme + Ty AST.Ty } // TPTP inputs are a list of statements @@ -137,7 +137,7 @@ func (statement Statement) ToString() string { str := statement.role.ToString() + " " + statement.name + " " switch ty := statement.atomTyping.(type) { case Lib.Some[TFFAtomTyping]: - return str + ty.Val.Literal.GetName() + ": " + ty.Val.Ts.ToString() + return str + ty.Val.Literal.GetName() + ": " + ty.Val.Ty.ToString() case Lib.None[TFFAtomTyping]: return str + "[None]" } diff --git a/src/Core/subst_and_form.go b/src/Core/subst_and_form.go index 92629c59..53388662 100644 --- a/src/Core/subst_and_form.go +++ b/src/Core/subst_and_form.go @@ -42,32 +42,34 @@ import ( "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Unif" ) /* Stock the substitution and the corresponding list of formulas */ type SubstAndForm struct { - s Unif.Substitutions - f *AST.FormList + s Lib.List[Unif.MixedSubstitution] + f Lib.List[AST.Form] } -func (s SubstAndForm) GetSubst() Unif.Substitutions { - return s.s.Copy() +func (s SubstAndForm) GetSubst() Lib.List[Unif.MixedSubstitution] { + return Lib.ListCpy(s.s) } -func (s SubstAndForm) GetForm() *AST.FormList { - return s.f.Copy() +func (s SubstAndForm) GetForm() Lib.List[AST.Form] { + return Lib.ListCpy(s.f) } -func (s *SubstAndForm) SetSubst(subst Unif.Substitutions) { - s.s = subst.Copy() +func (s *SubstAndForm) SetSubst(subst Lib.List[Unif.MixedSubstitution]) { + s.s = Lib.ListCpy(subst) } -func (s *SubstAndForm) SetForm(form *AST.FormList) { - s.f = form.Copy() +func (s *SubstAndForm) SetForm(form Lib.List[AST.Form]) { + s.f = Lib.ListCpy(form) } func (saf SubstAndForm) IsEmpty() bool { - return saf.s.IsEmpty() && saf.f.IsEmpty() + return saf.s.Empty() && saf.f.Empty() } func (s1 SubstAndForm) Equals(s2 SubstAndForm) bool { - return s1.GetSubst().Equals(s2.GetSubst()) && s1.GetForm().Equals(s2.GetForm()) + return Lib.ListEquals(s1.GetSubst(), s2.GetSubst()) && + Lib.ListEquals(s1.GetForm(), s2.GetForm()) } func (s SubstAndForm) Copy() SubstAndForm { if s.IsEmpty() { @@ -78,46 +80,40 @@ func (s SubstAndForm) Copy() SubstAndForm { } func (s SubstAndForm) ToString() string { res := "{ " - if !s.GetSubst().IsEmpty() { - res += s.GetSubst().ToString() + if !s.GetSubst().Empty() { + res += Lib.ListToString(s.GetSubst(), ", ", "[]") } res += " - " - if !s.GetForm().IsEmpty() { - res += s.GetForm().ToString() + if !s.GetForm().Empty() { + res += Lib.ListToString(s.GetForm(), ", ", "[]") } res += " }" return res } -func MakeSubstAndForm(subst Unif.Substitutions, form *AST.FormList) SubstAndForm { - return SubstAndForm{subst.Copy(), form.Copy()} +func MakeSubstAndForm(subst Lib.List[Unif.MixedSubstitution], form Lib.List[AST.Form]) SubstAndForm { + return SubstAndForm{Lib.ListCpy(subst), Lib.ListCpy(form)} } func MakeEmptySubstAndForm() SubstAndForm { - return SubstAndForm{Unif.MakeEmptySubstitution(), AST.NewFormList()} + return SubstAndForm{Lib.NewList[Unif.MixedSubstitution](), Lib.NewList[AST.Form]()} } -func (s SubstAndForm) AddFormulas(fl *AST.FormList) SubstAndForm { - formList := s.GetForm().Copy() - formList.AppendIfNotContains(fl.Copy().Slice()...) +func (s SubstAndForm) AddFormulas(fl Lib.List[AST.Form]) SubstAndForm { + formList := s.GetForm() + formList = Lib.ListAdd(formList, Lib.ListCpy(fl).GetSlice()...) return MakeSubstAndForm(s.GetSubst(), formList) } /* Remove empty substitution from a substitution list */ -func RemoveEmptySubstFromSubstList(sl []Unif.Substitutions) []Unif.Substitutions { - res := []Unif.Substitutions{} - for _, s := range sl { - if !(s.IsEmpty()) { - res = append(res, s) - } - } - return res +func RemoveEmptySubstFromSubstList(sl Lib.List[Lib.List[Unif.MixedSubstitution]]) Lib.List[Lib.List[Unif.MixedSubstitution]] { + return sl.Filter(func(l Lib.List[Unif.MixedSubstitution]) bool { return !l.Empty() }) } /* Remove empty substitution from a substitution list */ func RemoveEmptySubstFromSubstAndFormList(sl []SubstAndForm) []SubstAndForm { res := []SubstAndForm{} for _, s := range sl { - if !(s.GetSubst().IsEmpty()) { + if !(s.GetSubst().Empty()) { res = append(res, s) } } @@ -125,10 +121,10 @@ func RemoveEmptySubstFromSubstAndFormList(sl []SubstAndForm) []SubstAndForm { } /* Get a subst list from SubstAndForm lsit */ -func GetSubstListFromSubstAndFormList(l []SubstAndForm) []Unif.Substitutions { - res := []Unif.Substitutions{} +func GetSubstListFromSubstAndFormList(l []SubstAndForm) Lib.List[Lib.List[Unif.MixedSubstitution]] { + res := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() for _, saf := range l { - res = append(res, saf.GetSubst()) + res.Append(saf.GetSubst()) } return res } @@ -195,15 +191,15 @@ func MergeSubstAndForm(s1, s2 SubstAndForm) (error, SubstAndForm) { return nil, s1 } - new_subst, _ := Unif.MergeSubstitutions(s1.GetSubst().Copy(), s2.GetSubst().Copy()) + new_subst, succeeded := Unif.MergeMixedSubstitutions(s1.GetSubst(), s2.GetSubst()) - if new_subst.Equals(Unif.Failure()) { + if !succeeded { Glob.PrintError("MSAF", fmt.Sprintf("Error : MergeSubstitutions returns failure between : %v and %v \n", s1.ToString(), s2.ToString())) return errors.New("Couldn't merge two substitutions"), MakeEmptySubstAndForm() } - newFormList := s1.GetForm().Copy() - newFormList.AppendIfNotContains(s2.GetForm().Slice()...) + newFormList := s1.GetForm() + newFormList = Lib.ListAdd(newFormList, s2.GetForm().GetSlice()...) return nil, MakeSubstAndForm(new_subst, newFormList) } diff --git a/src/Core/subst_and_form_and_terms.go b/src/Core/subst_and_form_and_terms.go index 0b72fe73..fcabb51b 100644 --- a/src/Core/subst_and_form_and_terms.go +++ b/src/Core/subst_and_form_and_terms.go @@ -37,32 +37,33 @@ package Core import ( + "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Unif" ) /* Stock the substitution and the corresponding list of formulas */ type SubstAndFormAndTerms struct { - s Unif.Substitutions + s Lib.List[Unif.MixedSubstitution] f FormAndTermsList } -func (s SubstAndFormAndTerms) GetSubst() Unif.Substitutions { - return s.s.Copy() +func (s SubstAndFormAndTerms) GetSubst() Lib.List[Unif.MixedSubstitution] { + return Lib.ListCpy(s.s) } func (s SubstAndFormAndTerms) GetForm() FormAndTermsList { return s.f.Copy() } -func (s *SubstAndFormAndTerms) SetSubst(subst Unif.Substitutions) { - s.s = subst.Copy() +func (s *SubstAndFormAndTerms) SetSubst(subst Lib.List[Unif.MixedSubstitution]) { + s.s = Lib.ListCpy(subst) } func (s *SubstAndFormAndTerms) SetForm(form FormAndTermsList) { s.f = form.Copy() } func (saf SubstAndFormAndTerms) IsEmpty() bool { - return saf.s.IsEmpty() && saf.f.IsEmpty() + return saf.s.Empty() && saf.f.IsEmpty() } func (s1 SubstAndFormAndTerms) Equals(s2 SubstAndFormAndTerms) bool { - return s1.GetSubst().Equals(s2.GetSubst()) && s1.GetForm().Equals(s2.GetForm()) + return Lib.ListEquals(s1.GetSubst(), s2.GetSubst()) && s1.GetForm().Equals(s2.GetForm()) } func (s SubstAndFormAndTerms) Copy() SubstAndFormAndTerms { if s.IsEmpty() { @@ -80,8 +81,8 @@ func (s SubstAndFormAndTerms) ToSubstAndForm() SubstAndForm { } func (s SubstAndFormAndTerms) ToString() string { res := "{ " - if !s.GetSubst().IsEmpty() { - res += s.GetSubst().ToString() + if !s.GetSubst().Empty() { + res += Lib.ListToString(s.GetSubst(), ", ", "[]") } res += " - " if !s.GetForm().IsEmpty() { @@ -92,11 +93,11 @@ func (s SubstAndFormAndTerms) ToString() string { return res } -func MakeSubstAndFormAndTerms(subst Unif.Substitutions, form FormAndTermsList) SubstAndFormAndTerms { - return SubstAndFormAndTerms{subst.Copy(), form.Copy()} +func MakeSubstAndFormAndTerms(subst Lib.List[Unif.MixedSubstitution], form FormAndTermsList) SubstAndFormAndTerms { + return SubstAndFormAndTerms{Lib.ListCpy(subst), form.Copy()} } func MakeEmptySubstAndFormAndTerms() SubstAndFormAndTerms { - return SubstAndFormAndTerms{Unif.MakeEmptySubstitution(), FormAndTermsList{}} + return SubstAndFormAndTerms{Lib.NewList[Unif.MixedSubstitution](), FormAndTermsList{}} } /* Check if a substitution is inside a list of SubstAndForm */ diff --git a/src/Core/substitutions_search.go b/src/Core/substitutions_search.go index 51403ed8..b241d6c5 100644 --- a/src/Core/substitutions_search.go +++ b/src/Core/substitutions_search.go @@ -46,18 +46,21 @@ import ( ) /* Return the list of metavariable from a substitution */ -func GetMetaFromSubst(subs Unif.Substitutions) Lib.Set[AST.Meta] { +func GetMetaFromSubst(subs Lib.List[Unif.MixedSubstitution]) Lib.Set[AST.Meta] { res := Lib.EmptySet[AST.Meta]() - for _, singleSubs := range subs { - meta, term := singleSubs.Get() - res = res.Add(meta) + for _, singleSubs := range subs.GetSlice() { + switch s := singleSubs.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + meta, term := s.Val.Get() + res = res.Add(meta) - switch typedTerm := term.(type) { - case AST.Meta: - res = res.Add(typedTerm) - case AST.Fun: - res = res.Union(AST.GetMetasOfList(typedTerm.GetArgs())) + switch typedTerm := term.(type) { + case AST.Meta: + res = res.Add(typedTerm) + case AST.Fun: + res = res.Union(AST.GetMetasOfList(typedTerm.GetArgs())) + } } } @@ -65,7 +68,10 @@ func GetMetaFromSubst(subs Unif.Substitutions) Lib.Set[AST.Meta] { } /* Remove substitution without mm */ -func RemoveElementWithoutMM(subs Unif.Substitutions, mm Lib.Set[AST.Meta]) Unif.Substitutions { +func RemoveElementWithoutMM( + subs Lib.List[Unif.MixedSubstitution], + mm Lib.Set[AST.Meta], +) Lib.List[Unif.MixedSubstitution] { debug(Lib.MkLazy(func() string { return fmt.Sprintf( "MM : %v", @@ -74,8 +80,8 @@ func RemoveElementWithoutMM(subs Unif.Substitutions, mm Lib.Set[AST.Meta]) Unif. })) res := Unif.Substitutions{} + subst_to_reorganize := Unif.Substitutions{} - subsToReorganize := Unif.Substitutions{} relevantMetas := mm.Copy() hasChanged := true @@ -87,50 +93,59 @@ func RemoveElementWithoutMM(subs Unif.Substitutions, mm Lib.Set[AST.Meta]) Unif. Lib.ListToString(relevantMetas.Elements(), ",", "[]"), ) })) - for _, singleSubs := range subs { - meta, term := singleSubs.Get() - - switch typedTerm := term.(type) { - case AST.Meta: - switch { - case relevantMetas.Contains(meta) && - relevantMetas.Contains(typedTerm): - res.Set(meta, typedTerm) - - case relevantMetas.Contains(meta) && - relevantMetas.Contains(typedTerm): - subsToReorganize.Set(meta, typedTerm) - } + for _, singleSubs := range subs.GetSlice() { + switch single_subst := singleSubs.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + meta, term := single_subst.Val.Get() + + switch typedTerm := term.(type) { + case AST.Meta: + switch { + case relevantMetas.Contains(meta) && + relevantMetas.Contains(typedTerm): + res.Set(meta, typedTerm) + + case relevantMetas.Contains(meta) && + relevantMetas.Contains(typedTerm): + subst_to_reorganize.Set(meta, typedTerm) + } - default: - if relevantMetas.Contains(meta) { - res.Set(meta, term) - for _, candidateMeta := range term.GetMetas().Elements().GetSlice() { - if !relevantMetas.Contains(candidateMeta) { - hasChanged = true + default: + if relevantMetas.Contains(meta) { + res.Set(meta, term) + for _, candidateMeta := range term.GetMetas().Elements().GetSlice() { + if !relevantMetas.Contains(candidateMeta) { + hasChanged = true + } } + relevantMetas = relevantMetas.Union(term.GetMetas()) } - relevantMetas = relevantMetas.Union(term.GetMetas()) } } } } debug( - Lib.MkLazy(func() string { return fmt.Sprintf("Subst intermédiaire res : %v", res.ToString()) }), + Lib.MkLazy(func() string { + return fmt.Sprintf( + "Intermediary subst res : %s", + res.ToString(), + ) + }), ) debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Subst intermédiaire subst_to_reorganize : %v", - subsToReorganize.ToString()) + "Intermediary subst subst_to_reorganize : %s", + subst_to_reorganize.ToString(), + ) }), ) - subsToReorganize = ReorganizeSubstitution(subsToReorganize) - Unif.EliminateMeta(&subsToReorganize) - Unif.Eliminate(&subsToReorganize) - ms, _ := Unif.MergeSubstitutions(res, subsToReorganize) + subst_to_reorganize = ReorganizeSubstitution(subst_to_reorganize) + Unif.EliminateMeta(&subst_to_reorganize) + Unif.Eliminate(&subst_to_reorganize) + ms, _ := Unif.MergeSubstitutions(res, subst_to_reorganize) debug( Lib.MkLazy(func() string { return fmt.Sprintf("Finale subst : %v", ms.ToString()) }), @@ -140,13 +155,25 @@ func RemoveElementWithoutMM(subs Unif.Substitutions, mm Lib.Set[AST.Meta]) Unif. Glob.PrintError("REWM", "MergeSubstitutions returns failure") } - return ms + result := Lib.NewList[Unif.MixedSubstitution]() + for _, unif := range ms { + result.Append(Unif.MkMixedFromSubst(unif)) + } + + for _, s := range subs.GetSlice() { + switch subst := s.TySubstitution().(type) { + case Lib.Some[Unif.TySubstitution]: + result.Append(Unif.MkMixedFromTy(subst.Val)) + } + } + return result } -/* * -* Take a substitution wich conatins elements like (meta_mother, meta_current), returning only relevante substitution like (meta_mother, meta_mother) -* (X, X2) (Y, X2) -> (X, Y) +/** + * Take a substitution wich conatins elements like (meta_mother, meta_current), returning only + * relevant substitutions like (meta_mother, meta_mother) + * e.g., (X, X2) (Y, X2) -> (X, Y) **/ func ReorganizeSubstitution(subs Unif.Substitutions) Unif.Substitutions { res := Unif.Substitutions{} @@ -172,16 +199,22 @@ func ReorganizeSubstitution(subs Unif.Substitutions) Unif.Substitutions { } /* Check if a substitution contains a metavirbale which is inside a given list of metavariable (check for the key, not the value) */ -func ContainsMetaMother(s Unif.Substitutions, mm Lib.Set[AST.Meta]) bool { - for _, subst := range s { - k, v := subst.Get() - if mm.Contains(k) { +func ContainsMetaMother(s Lib.List[Unif.MixedSubstitution], mm Lib.Set[AST.Meta]) bool { + for _, subst := range s.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.None[Unif.Substitution]: + // In this case, [s] is a TySubstitution and hence it always contains a meta from the top level return true - } else { - switch vtype := v.(type) { - case AST.Meta: - if mm.Contains(vtype) { - return true + case Lib.Some[Unif.Substitution]: + k, v := s.Val.Get() + if mm.Contains(k) { + return true + } else { + switch vtype := v.(type) { + case AST.Meta: + if mm.Contains(vtype) { + return true + } } } } @@ -209,26 +242,16 @@ func ApplySubstitutionOnTerm(old_symbol AST.Meta, new_symbol, t AST.Term) AST.Te case AST.Fun: res = AST.MakerFun( nf.GetP(), + nf.GetTyArgs(), ApplySubstitutionOnTermList(old_symbol, new_symbol, nf.GetArgs()), - nf.GetTypeVars(), - nf.GetTypeHint(), ) } return res } -func applySubstitutionOnType(old_type, new_type, t AST.TypeApp) AST.TypeApp { - if tv, isTv := t.(AST.TypeVar); isTv { - if tv.Instantiated() && tv.Equals(old_type) { - return new_type - } - } - return t -} - /* Apply substitutions on a list of terms */ func ApplySubstitutionsOnTermList( - s Unif.Substitutions, + s Lib.List[Unif.MixedSubstitution], tl Lib.List[AST.Term], ) Lib.List[AST.Term] { res := Lib.MkList[AST.Term](tl.Len()) @@ -241,17 +264,23 @@ func ApplySubstitutionsOnTermList( return res } -func ApplySubstitutionsOnTerm(s Unif.Substitutions, t AST.Term) AST.Term { - if t != nil { - term_res := t.Copy() - for _, subst := range s { - old_symbol, new_symbol := subst.Get() - term_res = ApplySubstitutionOnTerm(old_symbol, new_symbol, term_res) +func ApplySubstitutionsOnTerm(substs Lib.List[Unif.MixedSubstitution], t AST.Term) AST.Term { + if t == nil { + return t + } + + for _, subst := range substs.GetSlice() { + switch s := subst.GetMixed().(type) { + case Lib.Left[Unif.TySubstitution, Unif.Substitution]: + meta, ty := s.Val.Get() + t = t.SubstTy(meta, ty) + case Lib.Right[Unif.TySubstitution, Unif.Substitution]: + meta, term := s.Val.Get() + t = t.ReplaceSubTermBy(meta, term) } - return term_res - } else { - return nil } + + return t } /* Apply substElement on a term list */ @@ -269,96 +298,45 @@ func ApplySubstitutionOnTermList( return res } -func applySubstitutionOnTypeList(old_symbol AST.Meta, new_symbol AST.Term, tl []AST.TypeApp) []AST.TypeApp { - res := make([]AST.TypeApp, len(tl)) - for i, t := range tl { - res[i] = applySubstitutionOnType(old_symbol.GetTypeApp(), new_symbol.(AST.TypedTerm).GetTypeApp(), t) +/* Apply substitutions on Formula */ +func ApplySubstitutionsOnFormula(s Lib.List[Unif.MixedSubstitution], f AST.Form) AST.Form { + // FIXME: check that line, it shouldn't happen + if f == nil { + return f } - return res -} - -/* Apply a substitution on a formula */ -func ApplySubstitutionOnFormula(old_symbol AST.Meta, new_symbol AST.Term, f AST.Form) AST.Form { - var res AST.Form - switch nf := f.(type) { - case AST.Pred: - res = AST.MakePred( - nf.GetIndex(), - nf.GetID(), - ApplySubstitutionOnTermList(old_symbol, new_symbol, nf.GetArgs()), - applySubstitutionOnTypeList(old_symbol, new_symbol, nf.GetTypeVars()), - nf.GetType(), - ) - case AST.Not: - res = AST.MakeNot(f.GetIndex(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetForm())) - case AST.And: - res_tmp := AST.NewFormList() - for _, val := range nf.FormList.Slice() { - res_tmp.Append(ApplySubstitutionOnFormula(old_symbol, new_symbol, val)) - } - res = AST.MakeAnd(f.GetIndex(), res_tmp) - case AST.Or: - res_tmp := AST.NewFormList() - for _, val := range nf.FormList.Slice() { - res_tmp.Append(ApplySubstitutionOnFormula(old_symbol, new_symbol, val)) + for _, subst := range s.GetSlice() { + switch s := subst.GetMixed().(type) { + case Lib.Left[Unif.TySubstitution, Unif.Substitution]: + meta, ty := s.Val.Get() + f = f.SubstTy(meta, ty) + case Lib.Right[Unif.TySubstitution, Unif.Substitution]: + meta, term := s.Val.Get() + f = f.ReplaceMetaByTerm(meta, term) } - res = AST.MakeOr(f.GetIndex(), res_tmp) - case AST.Imp: - res = AST.MakeImp(f.GetIndex(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetF1()), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetF2())) - case AST.Equ: - res = AST.MakeEqu(f.GetIndex(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetF1()), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetF2())) - case AST.Ex: - res = AST.MakeEx(f.GetIndex(), nf.GetVarList(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetForm())) - case AST.All: - res = AST.MakeAll(f.GetIndex(), nf.GetVarList(), ApplySubstitutionOnFormula(old_symbol, new_symbol, nf.GetForm())) - default: - res = f } - return res -} - -/* Apply substitutions on Formula */ -func ApplySubstitutionsOnFormula(s Unif.Substitutions, f AST.Form) AST.Form { - if f != nil { - form_res := f.Copy() - for _, subst := range s { - old_symbol, new_symbol := subst.Get() - form_res = ApplySubstitutionOnFormula(old_symbol, new_symbol, form_res) - } - return form_res - } else { - return nil - } + return f } /* For each element of the substitution, apply it on the entire formula list */ -func ApplySubstitutionsOnFormulaList(s Unif.Substitutions, lf *AST.FormList) *AST.FormList { - lf_res := AST.NewFormList() - for _, f := range lf.Slice() { +func ApplySubstitutionsOnFormulaList(s Lib.List[Unif.MixedSubstitution], lf Lib.List[AST.Form]) Lib.List[AST.Form] { + lf_res := Lib.NewList[AST.Form]() + for _, f := range lf.GetSlice() { new_form := ApplySubstitutionsOnFormula(s, f) - lf_res.AppendIfNotContains(new_form) + lf_res = Lib.ListAdd(lf_res, new_form) } return lf_res } /* Apply substitutions on FormAndTerm */ -func ApplySubstitutionsOnFormAndTerms(s Unif.Substitutions, fat FormAndTerms) FormAndTerms { - // if fat != FormAndTerms{} { - form_res := fat.GetForm() - tl_res := fat.GetTerms() - for _, subst := range s { - old_symbol, new_symbol := subst.Get() - form_res = ApplySubstitutionOnFormula(old_symbol, new_symbol, form_res) - //tl_res = ApplySubstitutionOnTermList(old_symbol, new_symbol, tl_res) - } - return MakeFormAndTerm(form_res, tl_res) +func ApplySubstitutionsOnFormAndTerms(s Lib.List[Unif.MixedSubstitution], fat FormAndTerms) FormAndTerms { + return MakeFormAndTerm(ApplySubstitutionsOnFormula(s, fat.GetForm()), fat.GetTerms()) } /* For each element of the substitution, apply it on the entire formAndTerms list */ -func ApplySubstitutionsOnFormAndTermsList(s Unif.Substitutions, lf FormAndTermsList) FormAndTermsList { +func ApplySubstitutionsOnFormAndTermsList(s Lib.List[Unif.MixedSubstitution], lf FormAndTermsList) FormAndTermsList { lf_res := MakeEmptyFormAndTermsList() for _, f := range lf { new_form := ApplySubstitutionsOnFormAndTerms(s, f) @@ -369,7 +347,7 @@ func ApplySubstitutionsOnFormAndTermsList(s Unif.Substitutions, lf FormAndTermsL } /* Apply a substitution on a metaGenerator list */ -func ApplySubstitutionOnMetaGenList(s Unif.Substitutions, lf []MetaGen) []MetaGen { +func ApplySubstitutionOnMetaGenList(s Lib.List[Unif.MixedSubstitution], lf []MetaGen) []MetaGen { lf_res := []MetaGen{} for _, f := range lf { new_form := ApplySubstitutionOnMetaGen(s, f) @@ -381,35 +359,35 @@ func ApplySubstitutionOnMetaGenList(s Unif.Substitutions, lf []MetaGen) []MetaGe } /* Apply a substitution on a metaGen form */ -func ApplySubstitutionOnMetaGen(s Unif.Substitutions, mg MetaGen) MetaGen { - form_res := mg.GetForm().GetForm() - terms_res := mg.GetForm().Terms - for _, subst := range s { - old_symbol, new_symbol := subst.Get() - form_res = ApplySubstitutionOnFormula(old_symbol, new_symbol, form_res) - terms_res = ApplySubstitutionOnTermList(old_symbol, new_symbol, terms_res) - } - return MakeMetaGen(MakeFormAndTerm(form_res, terms_res), mg.GetCounter()) +func ApplySubstitutionOnMetaGen(s Lib.List[Unif.MixedSubstitution], mg MetaGen) MetaGen { + return MakeMetaGen(MakeFormAndTerm( + ApplySubstitutionsOnFormula(s, mg.GetForm().GetForm()), + ApplySubstitutionsOnTermList(s, mg.f.GetTerms())), mg.GetCounter()) } /* Dispatch a list of substitution : containing mm or not */ -func DispatchSubst(subsList []Unif.Substitutions, mm Lib.Set[AST.Meta]) ([]Unif.Substitutions, []Unif.Substitutions, []Unif.Substitutions) { - var subsWithMM []Unif.Substitutions - var subsWithMMUncleared []Unif.Substitutions - var subsWithoutMM []Unif.Substitutions - - for _, subs := range subsList { +func DispatchSubst( + subsList Lib.List[Lib.List[Unif.MixedSubstitution]], + mm Lib.Set[AST.Meta], +) (Lib.List[Lib.List[Unif.MixedSubstitution]], + Lib.List[Lib.List[Unif.MixedSubstitution]], + Lib.List[Lib.List[Unif.MixedSubstitution]]) { + subsWithMM := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() + subsWithMMUncleared := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() + subsWithoutMM := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() + + for _, subs := range subsList.GetSlice() { removedSubs := subs if Glob.IsDestructive() { removedSubs = RemoveElementWithoutMM(subs, mm) } - if !removedSubs.IsEmpty() { - subsWithMM = Unif.AppendIfNotContainsSubst(subsWithMM, removedSubs) - subsWithMMUncleared = Unif.AppendIfNotContainsSubst(subsWithMMUncleared, subs) + if !removedSubs.Empty() { + subsWithMM.Add(Lib.ListEquals, removedSubs) + subsWithMMUncleared.Add(Lib.ListEquals, subs) } else { - subsWithoutMM = Unif.AppendIfNotContainsSubst(subsWithoutMM, subs) + subsWithoutMM.Add(Lib.ListEquals, subs) } } diff --git a/src/Engine/pretyper.go b/src/Engine/pretyper.go index 1b077b51..16386a83 100644 --- a/src/Engine/pretyper.go +++ b/src/Engine/pretyper.go @@ -38,6 +38,7 @@ package Engine import ( "fmt" + "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" @@ -50,10 +51,15 @@ var defaultType = Parser.MkTypeConst("$i").(Parser.PType) func pretype(con Context, terms []Parser.PTerm) []Lib.Pair[Parser.PTerm, Parser.PType] { tys := []Lib.Pair[Parser.PTerm, Parser.PType]{} for _, term := range terms { + debug(Lib.MkLazy(func() string { return fmt.Sprintf("pretyping %s", term.ToString()) })) lookupName := "" + args := []Parser.PTerm{} + defined_type := Lib.MkNone[Parser.PType]() switch t := term.(type) { case Parser.PFun: lookupName = t.Symbol() + args = t.Args() + defined_type = t.DefinedType() case Parser.PVar: lookupName = t.Name() } @@ -62,27 +68,44 @@ func pretype(con Context, terms []Parser.PTerm) []Lib.Pair[Parser.PTerm, Parser. switch ty := lookupInContext(con, lookupName).(type) { case Lib.Some[Parser.PType]: - tys = append(tys, Lib.MkPair(term, ty.Val)) + real_ty := instantiateType(ty.Val, lookupName, args) + debug_low_level(Lib.MkLazy(func() string { + return fmt.Sprintf("Term in context with type %s", real_ty.ToString()) + })) + + tys = append(tys, Lib.MkPair(term, real_ty)) typed = true + case Lib.None[Parser.PType]: + debug_low_level(Lib.MkLazy(func() string { return "Term not in context, is it defined?" })) + switch oty := defined_type.(type) { + case Lib.Some[Parser.PTypeFun]: + debug_low_level(Lib.MkLazy(func() string { + return fmt.Sprintf("%s has defined type %s", lookupName, oty.Val.ToString()) + })) + tys = append(tys, Lib.MkPair(term, Parser.PType(oty.Val))) + typed = true + } } if !typed { + debug_low_level(Lib.MkLazy(func() string { return "Term is not a defined term, assigning default type" })) tys = append(tys, Lib.MkPair(term, defaultType)) } + } return tys } func lookupInContext(con Context, name string) Lib.Option[Parser.PType] { - for _, p := range con { - if p.Fst == name { - return Lib.MkSome(p.Snd) + for i := len(con) - 1; i >= 0; i-- { + if con[i].Fst == name { + return Lib.MkSome(con[i].Snd) } } return Lib.MkNone[Parser.PType]() } -func isTType(pty Parser.PType) bool { +func isTyConstr(pty Parser.PType) bool { switch ty := pty.(type) { case Parser.PTypeFun: return ty.Symbol() == "$tType" @@ -96,7 +119,7 @@ func splitTypes( actualTys := Lib.NewList[Parser.PType]() others := Lib.NewList[Parser.PTerm]() for _, ty := range tys { - if isTType(ty.Snd) { + if isTyConstr(ty.Snd) { actualTys.Append(parserTermToType(ty.Fst)) } else { others.Append(ty.Fst) @@ -136,21 +159,86 @@ func parserTermToType(pterm Parser.PTerm) Parser.PType { return nil } -func splitTypeVars( - tys []Lib.Pair[string, Parser.PAtomicType], -) ([]AST.TypeVar, []AST.Var) { - tyvars := []AST.TypeVar{} - others := []AST.Var{} - for _, ty := range tys { - if isTType(ty.Snd.(Parser.PType)) { - tyvars = append(tyvars, AST.MkTypeVar(ty.Fst)) - } else { - varTy := ty.Snd.(Parser.PType) - others = append( - others, - AST.MakerVar(ty.Fst, elaborateType(varTy, varTy).(AST.TypeApp)), +func pretypeVars(vars []Lib.Pair[string, Parser.PAtomicType]) Lib.List[AST.TypedVar] { + res := Lib.MkList[AST.TypedVar](len(vars)) + for i, v := range vars { + ty := elaborateType(v.Snd.(Parser.PType), v.Snd.(Parser.PType), false) + res.Upd(i, AST.MakerTypedVar(v.Fst, ty)) + } + return res +} + +func instantiateType(ty Parser.PType, lookupName string, args []Parser.PTerm) Parser.PType { + switch nty := ty.(type) { + case Parser.PTypeVar, Parser.PTypeFun: + if len(args) > 0 { + Glob.Fatal( + elab_label, + fmt.Sprintf("Expected constant, got %s which is a function", lookupName), + ) + } + + return nty + + case Parser.PTypeBin: + if nty.Operator() != Parser.PTypeMap { + Glob.Fatal( + elab_label, + fmt.Sprintf("Expected map type, got %s", nty.ToString()), ) } + + return nty.Right() + + case Parser.PTypeQuant: + type_args := map[string]Parser.PType{} + for i, v := range nty.Vars() { + type_args[v.Fst] = parserTermToType(args[i]) + } + return instantiateRec(nty.Ty(), type_args) } - return tyvars, others + Glob.Fatal( + elab_label, + fmt.Sprintf("Expected functional type, got %s", ty.ToString()), + ) + return ty +} + +func instantiateRec(ty Parser.PType, instance map[string]Parser.PType) Parser.PType { + switch nty := ty.(type) { + case Parser.PTypeVar: + if val, ok := instance[nty.Name()]; ok { + return val + } + Glob.Fatal( + elab_label, + fmt.Sprintf("Type variable %s not found in the instance", ty.ToString()), + ) + return ty + + case Parser.PTypeFun: + args := []Parser.PAtomicType{} + for _, arg := range nty.Args() { + args = append(args, instantiateRec(arg.(Parser.PType), instance).(Parser.PAtomicType)) + } + + return Parser.MkPTypeFun(nty.Symbol(), args) + + case Parser.PTypeBin: + new_left := instantiateRec(nty.Left(), instance) + new_right := instantiateRec(nty.Right(), instance) + switch nty.Operator() { + case Parser.PTypeProd: + return Parser.MkTypeProd(new_left, new_right) + + case Parser.PTypeMap: + return new_right + } + } + + Glob.Anomaly( + elab_label, + fmt.Sprintf("Unexpected type on instantiation: %s", ty.ToString()), + ) + return ty } diff --git a/src/Engine/syntax-translation.go b/src/Engine/syntax-translation.go index 8efed527..62cd659a 100644 --- a/src/Engine/syntax-translation.go +++ b/src/Engine/syntax-translation.go @@ -38,54 +38,77 @@ package Engine import ( "fmt" + "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Core" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Parser" + "github.com/GoelandProver/Goeland/Typing" ) -type Context []Lib.Pair[string, Parser.PType] - var elab_label string = "Elab" var parsing_label string = "Parsing" -func ToInternalSyntax(parser_statements []Parser.PStatement) []Core.Statement { - statements := []Core.Statement{} - con := Context{} +var debug Glob.Debugger +var debug_low_level Glob.Debugger + +func InitDebugger() { + debug = Glob.CreateDebugger("elab") + debug_low_level = Glob.CreateDebugger("elab-low") +} + +func ToInternalSyntax(parser_statements []Parser.PStatement) (statements []Core.Statement, is_typed bool) { + is_typed = false + con := initialContext() for _, statement := range parser_statements { - newCon, stmt := elaborateParsingStatement(con, statement) + new_con, stmt, is_typed_stmt := elaborateParsingStatement(con, statement) statements = append(statements, stmt) - con = newCon + con = new_con + is_typed = is_typed || is_typed_stmt } - return statements + return statements, is_typed } func elaborateParsingStatement( con Context, statement Parser.PStatement, -) (Context, Core.Statement) { +) (Context, Core.Statement, bool) { statement_role := elaborateRole(statement.Role(), statement) + is_typed := false var core_statement Core.Statement switch f := statement.Form().(type) { case Lib.Some[Parser.PForm]: + debug(Lib.MkLazy(func() string { return fmt.Sprintf("Elaborating formula %s", f.Val.ToString()) })) + + new_con, form, is_typed_form := elaborateParsingForm(con, f.Val) core_statement = Core.MakeFormStatement( statement.Name(), statement_role, - elaborateParsingForm(con, f.Val), + form, ) + is_typed = is_typed || is_typed_form + con = new_con case Lib.None[Parser.PForm]: switch ty := statement.TypedConst().(type) { case Lib.Some[Lib.Pair[string, Parser.PType]]: + debug(Lib.MkLazy(func() string { + return fmt.Sprintf( + "Elaborating type statement %s: %s", + ty.Val.Fst, + ty.Val.Snd.ToString()) + })) + con = append(con, ty.Val) core_statement = Core.MakeTypingStatement( statement.Name(), statement_role, elaborateParsingType(ty.Val), ) + is_typed = true case Lib.None[Lib.Pair[string, Parser.PType]]: if statement.Role() != Parser.Include { @@ -96,7 +119,7 @@ func elaborateParsingStatement( } } } - return con, core_statement + return con, core_statement, is_typed } func elaborateRole(parsing_role Parser.PFormulaRole, stmt Parser.PStatement) Core.FormulaRole { @@ -123,13 +146,13 @@ func elaborateRole(parsing_role Parser.PFormulaRole, stmt Parser.PStatement) Cor return Core.Unknown } -func elaborateParsingForm(con Context, f Parser.PForm) AST.Form { +func elaborateParsingForm(con Context, f Parser.PForm) (Context, AST.Form, bool) { return elaborateForm(con, f, f) } // The [source_form] argument is here for error printing purposes. -func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { - aux := func(t Parser.PTerm) AST.Term { +func elaborateForm(con Context, f, source_form Parser.PForm) (Context, AST.Form, bool) { + aux := func(con Context, t Parser.PTerm) (Context, AST.Term, bool) { return elaborateParsingTerm(con, t) } @@ -138,29 +161,48 @@ func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { case Parser.PConst: switch pform.PConstant { case Parser.PTop: - return AST.MakerTop() + return con, AST.MakerTop(), false case Parser.PBot: - return AST.MakerBot() + return con, AST.MakerBot(), false } case Parser.PPred: typed_arguments := pretype(con, pform.Args()) - type_args, real_args := splitTypes(typed_arguments) - return AST.MakerPred( + typed_args, term_args := splitTypes(typed_arguments) + is_typed := false + + args := Lib.MkList[AST.Term](term_args.Len()) + for i, trm := range term_args.GetSlice() { + new_con, arg, b := aux(con, trm) + con = new_con + is_typed = is_typed || b + args.Upd(i, arg) + } + + // Special cases: defined types get elaborated to manage ad-hoc polymorphism + if isDefined(pform.Symbol()) { + tys := Lib.ListMap(Lib.MkListV(typed_arguments[typed_args.Len():]...), + func(p Lib.Pair[Parser.PTerm, Parser.PType]) Parser.PType { return p.Snd }) + typed_args = elaborateDefinedFunctionals(con, pform.Symbol(), tys, args) + } else { + is_typed = !typed_args.Empty() + } + + return con, AST.MakerPred( AST.MakerId(pform.Symbol()), - Lib.ListMap(real_args, aux), Lib.ListMap( - type_args, - func(pty Parser.PType) AST.TypeApp { - return elaborateType(pty, pty).(AST.TypeApp) - }, - ).GetSlice(), - ) + typed_args, + func(pty Parser.PType) AST.Ty { + return elaborateType(pty, pty, false) + }), + args, + ), is_typed case Parser.PUnary: switch pform.PUnaryOp { case Parser.PUnaryNeg: - return AST.MakerNot(elaborateForm(con, pform.PForm, source_form)) + new_con, nf, b := elaborateForm(con, pform.PForm, source_form) + return new_con, AST.MakerNot(nf), b } case Parser.PBin: @@ -170,19 +212,17 @@ func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { case Parser.PBinaryAnd: return maybeFlattenAnd(con, pform, source_form) case Parser.PBinaryImp: - return AST.MakerImp( - elaborateForm(con, pform.Left(), source_form), - elaborateForm(con, pform.Right(), source_form), - ) + con1, lft, b1 := elaborateForm(con, pform.Left(), source_form) + new_con, rgt, b2 := elaborateForm(con1, pform.Right(), source_form) + return new_con, AST.MakerImp(lft, rgt), b1 || b2 case Parser.PBinaryEqu: - return AST.MakerEqu( - elaborateForm(con, pform.Left(), source_form), - elaborateForm(con, pform.Right(), source_form), - ) + con1, lft, b1 := elaborateForm(con, pform.Left(), source_form) + new_con, rgt, b2 := elaborateForm(con1, pform.Right(), source_form) + return new_con, AST.MakerEqu(lft, rgt), b1 || b2 } case Parser.PQuant: - type_vars, vars := splitTypeVars(pform.Vars()) + vars := pretypeVars(pform.Vars()) switch pform.PQuantifier { case Parser.PQuantAll: actualVars := Lib.ListMap( @@ -191,16 +231,14 @@ func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { return Lib.MkPair(p.Fst, p.Snd.(Parser.PType)) }, ) - form := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) - if len(vars) != 0 { + new_con, form, b := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) + if !vars.Empty() { form = AST.MakerAll(vars, form) } - if len(type_vars) != 0 { - form = AST.MakerAllType(type_vars, form) - } - return form + return new_con, form, b + case Parser.PQuantEx: - if len(type_vars) != 0 { + if vars.Any(func(v AST.TypedVar) bool { return AST.IsTType(v.GetTy()) }) { Glob.Anomaly( elab_label, "Found existentially quantified types when parsing "+source_form.ToString(), @@ -212,34 +250,32 @@ func elaborateForm(con Context, f, source_form Parser.PForm) AST.Form { return Lib.MkPair(p.Fst, p.Snd.(Parser.PType)) }, ) - form := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) - if len(vars) != 0 { - return AST.MakerEx(vars, form) + new_con, form, b := elaborateForm(append(con, actualVars.GetSlice()...), pform.PForm, source_form) + if !vars.Empty() { + form = AST.MakerEx(vars, form) } - return form + return new_con, form, b } } Glob.Anomaly( elab_label, "Parsed formula "+source_form.ToString()+" does not correspond to any internal formula", ) - return nil + return con, nil, false } -func maybeFlattenOr(con Context, f Parser.PBin, source_form Parser.PForm) AST.Form { +func maybeFlattenOr(con Context, f Parser.PBin, source_form Parser.PForm) (Context, AST.Form, bool) { return maybeFlattenBin( con, f, source_form, - // FIXME: get rid of the pointer - func(ls *AST.FormList) AST.Form { return AST.MakerOr(ls) }, + func(ls Lib.List[AST.Form]) AST.Form { return AST.MakerOr(ls) }, Parser.PBinaryOr, ) } -func maybeFlattenAnd(con Context, f Parser.PBin, source_form Parser.PForm) AST.Form { +func maybeFlattenAnd(con Context, f Parser.PBin, source_form Parser.PForm) (Context, AST.Form, bool) { return maybeFlattenBin( con, f, source_form, - // FIXME: get rid of the pointer - func(ls *AST.FormList) AST.Form { return AST.MakerAnd(ls) }, + func(ls Lib.List[AST.Form]) AST.Form { return AST.MakerAnd(ls) }, Parser.PBinaryAnd, ) } @@ -248,25 +284,25 @@ func maybeFlattenBin( con Context, f Parser.PBin, source_form Parser.PForm, - maker Lib.Func[*AST.FormList, AST.Form], + maker Lib.Func[Lib.List[AST.Form], AST.Form], op Parser.PBinOp, -) AST.Form { +) (Context, AST.Form, bool) { if !Glob.Flatten() { - return maker( - AST.NewFormList( - elaborateForm(con, f.Left(), source_form), - elaborateForm(con, f.Right(), source_form), - )) + con1, lft, b1 := elaborateForm(con, f.Left(), source_form) + new_con, rgt, b2 := elaborateForm(con1, f.Right(), source_form) + return new_con, maker(Lib.MkListV(lft, rgt)), b1 || b2 } subforms := flatten(f, op) - forms := AST.NewFormList( - Lib.ListMap( - subforms, - func(f Parser.PForm) AST.Form { return elaborateForm(con, f, source_form) }, - ).GetSlice()..., - ) - return maker(forms) + is_typed := false + real_subforms := Lib.MkList[AST.Form](subforms.Len()) + for i, subform := range subforms.GetSlice() { + new_con, real_subform, b := elaborateForm(con, subform, source_form) + con = new_con + real_subforms.Upd(i, real_subform) + is_typed = is_typed || b + } + return con, maker(real_subforms), is_typed } func flatten(f Parser.PForm, op Parser.PBinOp) Lib.List[Parser.PForm] { @@ -281,181 +317,158 @@ func flatten(f Parser.PForm, op Parser.PBinOp) Lib.List[Parser.PForm] { return Lib.MkListV(f) } -func elaborateParsingTerm(con Context, t Parser.PTerm) AST.Term { +func elaborateParsingTerm(con Context, t Parser.PTerm) (Context, AST.Term, bool) { return elaborateTerm(con, t, t) } // The argument [source_term] is here for error printing purposes. -func elaborateTerm(con Context, t, source_term Parser.PTerm) AST.Term { - aux := func(t Parser.PTerm) AST.Term { +func elaborateTerm(con Context, t, source_term Parser.PTerm) (Context, AST.Term, bool) { + aux := func(con Context, t Parser.PTerm) (Context, AST.Term, bool) { return elaborateTerm(con, t, source_term) } - fail := func(ty AST.TypeScheme) { - Glob.Fatal( - parsing_label, - fmt.Sprintf( - "Non-atomic type found when pretyping %s: got %s", - t.ToString(), - ty.ToString(), - ), - ) - } - switch pterm := t.(type) { case Parser.PVar: - ty := lookupInContext(con, pterm.Name()) - switch t := ty.(type) { - case Lib.Some[Parser.PType]: - if isTType(t.Val) { - Glob.Anomaly( - elab_label, - fmt.Sprintf( - "Trying to transform the type variable %s into an internal term in %s", - pterm.Name(), - source_term.ToString(), - ), - ) - } - - ty := elaborateType(t.Val, t.Val) - if _, ok := ty.(AST.TypeApp); !ok { - fail(ty) - } - // FIXME: get some error function over here - return AST.MakerVar(pterm.Name(), elaborateType(t.Val, t.Val).(AST.TypeApp)) - } + return con, AST.MakerVar(pterm.Name()), false case Parser.PFun: typed_arguments := pretype(con, pterm.Args()) - type_args, real_args := splitTypes(typed_arguments) + typed_args, term_args := splitTypes(typed_arguments) + is_typed := false + + args := Lib.MkList[AST.Term](term_args.Len()) + for i, trm := range term_args.GetSlice() { + new_con, arg, b := aux(con, trm) + con = new_con + is_typed = is_typed || b + args.Upd(i, arg) + } + + // Special cases: defined types get elaborated to manage ad-hoc polymorphism + if isDefined(pterm.Symbol()) { + tys := Lib.ListMap(Lib.MkListV(typed_arguments[typed_args.Len():]...), + func(p Lib.Pair[Parser.PTerm, Parser.PType]) Parser.PType { return p.Snd }) + typed_args = elaborateDefinedFunctionals(con, pterm.Symbol(), tys, args) + } else { + is_typed = !typed_args.Empty() + } + fun := AST.MakerFun( AST.MakerId(pterm.Symbol()), - Lib.ListMap(real_args, aux), Lib.ListMap( - type_args, - func(pty Parser.PType) AST.TypeApp { - ty := elaborateType(pty, pty) - if _, ok := ty.(AST.TypeApp); !ok { - fail(ty) - } - return elaborateType(pty, pty).(AST.TypeApp) - }, - ).GetSlice(), + typed_args, + func(pty Parser.PType) AST.Ty { + return elaborateType(pty, pty, false) + }), + args, ) switch oty := pterm.DefinedType().(type) { case Lib.Some[Parser.PTypeFun]: - ty := elaborateType(oty.Val, oty.Val).(AST.TypeApp) - AST.SaveConstant(pterm.Symbol(), ty) + debug(Lib.MkLazy(func() string { return fmt.Sprintf("%s is a defined function", pterm.Symbol()) })) + debug_low_level(Lib.MkLazy(func() string { + return fmt.Sprintf("%s has defined type %s", pterm.Symbol(), oty.Val.ToString()) + })) + con = append(con, Lib.MkPair(pterm.Symbol(), Parser.PType(oty.Val))) + ty := elaborateType(oty.Val, oty.Val, false) + Typing.AddToGlobalEnv(pterm.Symbol(), ty) } - return fun + return con, fun, is_typed || !typed_args.Empty() } Glob.Anomaly( elab_label, "Parsed term "+source_term.ToString()+" does not correspond to any internal term", ) - return nil + return con, nil, false } func elaborateParsingType(pty Lib.Pair[string, Parser.PType]) Core.TFFAtomTyping { return Core.TFFAtomTyping{ Literal: AST.MakerId(pty.Fst), - Ts: elaborateType(pty.Snd, pty.Snd), + Ty: elaborateType(pty.Snd, pty.Snd, true), } } // The [source_type] argument is here for error printing. -func elaborateType(pty, source_type Parser.PType) AST.TypeScheme { - aux := func(pty Parser.PType) AST.TypeScheme { - return elaborateType(pty, source_type) +func elaborateType(pty, source_type Parser.PType, from_top_level bool) AST.Ty { + aux := func(pty Parser.PType) AST.Ty { + return elaborateType(pty, source_type, from_top_level) } switch ty := pty.(type) { case Parser.PTypeVar: - return AST.MkTypeVar(ty.Name()) - - case Parser.PTypeFun: - if len(ty.Args()) == 0 { - return AST.MkTypeHint(ty.Symbol()) + if from_top_level { + return AST.MkTyVar(ty.Name()) } else { - args := Lib.MkListV(ty.Args()...) - actualArgs := Lib.ListMap( - args, - func(atom Parser.PAtomicType) Parser.PType { return atom.(Parser.PType) }, - ) - elaboratedArgs := Lib.ListMap(actualArgs, aux) - convertedArgs := Lib.ListMap( - elaboratedArgs, - func(ty AST.TypeScheme) AST.TypeApp { return ty.(AST.TypeApp) }, - ) - // FIXME: this is __bad__ - params := []AST.TypeApp{} - for range convertedArgs.GetSlice() { - params = append(params, nil) - } - // FIXME: shouldn't this be internalized when making a new parameterized type - // instead of having to save it before? - AST.SaveParamereterizedType(ty.Symbol(), params) - return AST.MkParameterizedType( - ty.Symbol(), - convertedArgs.GetSlice(), - ) + return AST.MakerTyBV(ty.Name()) } + case Parser.PTypeFun: + args := Lib.MkListV(ty.Args()...) + actualArgs := Lib.ListMap( + args, + func(atom Parser.PAtomicType) Parser.PType { return atom.(Parser.PType) }, + ) + elaboratedArgs := Lib.ListMap(actualArgs, aux) + return AST.MkTyConstr(ty.Symbol(), elaboratedArgs) case Parser.PTypeBin: - new_left := elaborateType(ty.Left(), source_type) - new_right := elaborateType(ty.Right(), source_type) + fail_if_forbidden := func(ty Parser.PType) { + fatal := func() { + Glob.Fatal( + parsing_label, + fmt.Sprintf( + "Non-atomic type (%s) found under the type %s", + ty.ToString(), + source_type.ToString(), + ), + ) + } - fail := func(cse string) { - Glob.Fatal( - parsing_label, - fmt.Sprintf( - "Non-atomic type found under the %s type %s in %s", - cse, - ty.ToString(), - source_type.ToString(), - ), - ) + switch nty := ty.(type) { + case Parser.PTypeBin: + if nty.Operator() == Parser.PTypeMap { + fatal() + } + case Parser.PTypeQuant: + fatal() + } } + fail_if_forbidden(ty.Left()) + fail_if_forbidden(ty.Right()) + + new_left := elaborateType(ty.Left(), source_type, from_top_level) + new_right := elaborateType(ty.Right(), source_type, from_top_level) + switch ty.Operator() { case Parser.PTypeProd: - if !Glob.Is[AST.TypeApp](new_left) { - fail("map") - } - if !Glob.Is[AST.TypeApp](new_right) { - fail("map") - } - left_list := flattenProd(new_left.(AST.TypeApp)) - right_list := flattenProd(new_right.(AST.TypeApp)) - return AST.MkTypeCross(append(left_list, right_list...)...) + left_list := flattenProd(new_left) + right_list := flattenProd(new_right) + return AST.MkTyProd(Lib.MkListV(append(left_list, right_list...)...)) case Parser.PTypeMap: - if !Glob.Is[AST.TypeApp](new_left) { - fail("map") - } - if !Glob.Is[AST.TypeApp](new_right) { - fail("map") - } - return AST.MkTypeArrow( - elaborateType(ty.Left(), source_type).(AST.TypeApp), - elaborateType(ty.Right(), source_type).(AST.TypeApp), + return AST.MkTyFunc( + elaborateType(ty.Left(), source_type, from_top_level), + elaborateType(ty.Right(), source_type, from_top_level), ) } case Parser.PTypeQuant: switch ty.Quant() { case Parser.PTypeAll: - vars := Lib.MkListV(ty.Vars()...) - actualVars := Lib.ListMap( - vars, - func(p Lib.Pair[string, Parser.PAtomicType]) AST.TypeVar { - return AST.MkTypeVar(p.Fst) - }, - ) - return AST.MkQuantifiedType( - actualVars.GetSlice(), - elaborateType(ty.Ty(), source_type), - ) + var_names := Lib.MkList[string](len(ty.Vars())) + for i, v := range ty.Vars() { + var_names.Upd(i, v.Fst) + } + + underlying_type := elaborateType(ty.Ty(), source_type, from_top_level) + + if Glob.Is[AST.TyPi](underlying_type) { + Glob.Anomaly( + elab_label, + fmt.Sprintf("Found nested Pi-type in %s", source_type.ToString()), + ) + } + + return AST.MkTyPi(var_names, underlying_type) } } @@ -466,14 +479,111 @@ func elaborateType(pty, source_type Parser.PType) AST.TypeScheme { return nil } -func flattenProd(ty AST.TypeApp) []AST.TypeApp { +func flattenProd(ty AST.Ty) []AST.Ty { switch nty := ty.(type) { - case AST.TypeCross: - res := []AST.TypeApp{} - for _, uty := range nty.GetAllUnderlyingTypes() { + case AST.TyProd: + res := []AST.Ty{} + for _, uty := range nty.GetTys().GetSlice() { res = append(res, flattenProd(uty)...) } return res } - return []AST.TypeApp{ty} + return []AST.Ty{ty} +} + +func elaborateDefinedFunctionals( + con Context, + name string, + ty_arguments Lib.List[Parser.PType], + arguments Lib.List[AST.Term], +) Lib.List[Parser.PType] { + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Elaborating defined functional %s(%s)", name, Lib.ListToString(arguments, ", ", "")) + })) + + // Invariant: call from isDefined, defined_length should be defined as well + if arguments.Len() != defined_length[name] { + Glob.Fatal( + elab_label, + fmt.Sprintf("%s expects %d arguments, got %d", name, defined_length[name], arguments.Len()), + ) + } + + ty_args := Lib.NewList[Parser.PType]() + tys := Lib.NewList[Parser.PType]() + for i, arg := range arguments.GetSlice() { + var ty Lib.Option[Parser.PType] + ty_args := Lib.NewList[Parser.PTerm]() + switch term := arg.(type) { + case AST.Fun: + ty = lookupInContext(con, term.GetName()) + for _, ty := range term.GetTyArgs().GetSlice() { + switch t := ty.(type) { + case AST.TyConstr: + ty_args.Append(Parser.MkFunConst(t.Symbol())) + case AST.TyBound: + ty_args.Append(Parser.MkVar(t.GetName())) + default: + Glob.Anomaly(elab_label, "Found non-constant type parameter in defined type") + } + } + case AST.Var: + ty = lookupInContext(con, term.GetName()) + default: + Glob.Anomaly(elab_label, "Parsed argument is neither a function nor a variable") + } + + switch rty := ty.(type) { + case Lib.Some[Parser.PType]: + tys.Append(instantiateType(rty.Val, arg.GetName(), ty_args.GetSlice())) + case Lib.None[Parser.PType]: + // This is not a defined, let's use the inferred type + tys.Append(ty_arguments.At(i)) + } + } + + // Take the first allowed argument and hope for the best (leave the rest for the typechecker) + elab_ty := Lib.MkNone[Parser.PType]() + for _, ty := range tys.GetSlice() { + if isAllowed(name, ty) { + elab_ty = Lib.MkSome(ty) + break + } + } + + switch ety := elab_ty.(type) { + case Lib.Some[Parser.PType]: + ty_args.Append(ety.Val) + case Lib.None[Parser.PType]: + switch allowed := allowed_elab[name].(type) { + case Lib.Some[Lib.List[Parser.PType]]: + Glob.Fatal( + elab_label, + fmt.Sprintf( + "%s expects arguments in {%s}, but found none with the right type", + name, Lib.ListToString(allowed.Val, ", ", ""), + )) + case Lib.None[Lib.List[Parser.PType]]: + Glob.Anomaly( + elab_label, + fmt.Sprintf("allowed_elab[%s] is None but term is not allowed", name), + ) + } + } + + // Special case: quotient of two integers + if name == "$quotient" { + if tys.At(0).Equals(Parser.MkTypeConst("$int")) { + ty_args.Append(Parser.MkTypeConst("$rat").(Parser.PType)) + } else { + ty_args.Append(ty_args.At(0)) + } + } + + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Defined functional elaborated to %s(%s ; %s)", + name, Lib.ListToString(ty_args, ", ", ""), Lib.ListToString(arguments, ", ", "")) + })) + + return ty_args } diff --git a/src/Engine/tptp-defined-types.go b/src/Engine/tptp-defined-types.go new file mode 100644 index 00000000..041f8c0d --- /dev/null +++ b/src/Engine/tptp-defined-types.go @@ -0,0 +1,155 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file returns an initial context (one augmented with TPTP defined types) +**/ + +package Engine + +import ( + "fmt" + "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Parser" +) + +type Context []Lib.Pair[string, Parser.PType] + +var defined Lib.Set[Lib.String] +var defined_length map[string]int +var allowed_elab map[string]Lib.Option[Lib.List[Parser.PType]] // None: no restriction + +func initialContext() Context { + defined = Lib.EmptySet[Lib.String]() + defined_length = make(map[string]int) + allowed_elab = make(map[string]Lib.Option[Lib.List[Parser.PType]]) + + tType := Parser.MkTypeConst("$tType").(Parser.PType) + tInt := Parser.MkTypeConst("$int").(Parser.PType) + tRat := Parser.MkTypeConst("$rat").(Parser.PType) + tReal := Parser.MkTypeConst("$real").(Parser.PType) + tProp := Parser.MkTypeConst("$o").(Parser.PType) + + con := []Lib.Pair[string, Parser.PType]{ + Lib.MkPair("$tType", tType), + Lib.MkPair("$int", tType), + Lib.MkPair("$rat", tType), + Lib.MkPair("$real", tType), + Lib.MkPair("$i", tType), + Lib.MkPair("$o", tType), + } + + mkDefined := func(name string, length int, allowed Lib.Option[Lib.List[Parser.PType]], ty Parser.PType) { + defined = defined.Add(Lib.MkString(name)) + defined_length[name] = length + allowed_elab[name] = allowed + con = append(con, Lib.MkPair(name, ty)) + } + + tNumber := Parser.MkPTypeVar("number") + binPoly := func(out Parser.PType) Parser.PType { + return Parser.MkTypeAll( + []Lib.Pair[string, Parser.PAtomicType]{Lib.MkPair("number", tType.(Parser.PAtomicType))}, + Parser.MkTypeMap( + Parser.MkTypeProd(tNumber, tNumber), + out, + ), + ) + } + unPoly := func(out Parser.PType) Parser.PType { + return Parser.MkTypeAll( + []Lib.Pair[string, Parser.PAtomicType]{Lib.MkPair("number", tType.(Parser.PAtomicType))}, + Parser.MkTypeMap(tNumber, out), + ) + } + + mkDefined("$less", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tProp)) + mkDefined("$lesseq", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tProp)) + mkDefined("$greater", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tProp)) + mkDefined("$greatereq", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tProp)) + + mkDefined("$sum", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$difference", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$product", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$quotient_e", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$quotient_t", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$quotient_f", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$remainder_e", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$remainder_t", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$remainder_f", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), binPoly(tNumber)) + mkDefined("$quotient", 2, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), Parser.MkTypeAll( + []Lib.Pair[string, Parser.PAtomicType]{ + Lib.MkPair("number", tType.(Parser.PAtomicType)), + Lib.MkPair("rat_or_real", tType.(Parser.PAtomicType)), + }, + Parser.MkTypeMap( + Parser.MkTypeProd(tNumber, tNumber), + Parser.MkPTypeVar("rat_or_real"), + ))) + + mkDefined("$uminus", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tNumber)) + mkDefined("$floor", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tNumber)) + mkDefined("$ceiling", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tNumber)) + mkDefined("$truncate", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tNumber)) + mkDefined("$round", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tNumber)) + + mkDefined("$is_int", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tProp)) + mkDefined("$is_rat", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tProp)) + + mkDefined("$to_int", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tInt)) + mkDefined("$to_rat", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tRat)) + mkDefined("$to_real", 1, Lib.MkSome(Lib.MkListV(tInt, tRat, tReal)), unPoly(tReal)) + + mkDefined(Parser.PEqSymbol, 2, Lib.MkNone[Parser.PType](), binPoly(tProp)) + + debug_low_level(Lib.MkLazy(func() string { + str := "Defined symbols:" + for _, s := range defined.Elements().GetSlice() { + str += fmt.Sprintf("\n- %s with %d arguments", s, defined_length[string(s)]) + } + return str + })) + + return con +} + +func isDefined(name string) bool { + return defined.Contains(Lib.MkString(name)) +} + +func isAllowed(name string, ty Parser.PType) bool { + switch allowed := allowed_elab[name].(type) { + case Lib.Some[Lib.List[Parser.PType]]: + return Lib.ListMem(ty, allowed.Val) + } + return true +} diff --git a/src/Lib/either.go b/src/Lib/either.go new file mode 100644 index 00000000..531524c3 --- /dev/null +++ b/src/Lib/either.go @@ -0,0 +1,103 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +package Lib + +import ( + "fmt" +) + +/* This file implements the Either type (sum type). */ + +type Either[A, B any] interface { + isEither() +} + +type Left[A, B any] struct { + Val A +} + +type Right[A, B any] struct { + Val B +} + +func (Left[A, B]) isEither() {} +func (Right[A, B]) isEither() {} + +func MkLeft[A, B any](x A) Either[A, B] { + return Left[A, B]{Val: x} +} + +func MkRight[A, B any](y B) Either[A, B] { + return Right[A, B]{Val: y} +} + +func EitherToString[A, B Stringable](u Either[A, B], left, right string) string { + switch x := u.(type) { + case Left[A, B]: + return fmt.Sprintf("%s(%s)", left, x.Val.ToString()) + case Right[A, B]: + return fmt.Sprintf("%s(%s)", right, x.Val.ToString()) + } + return "" +} + +func EitherEquals[A, B Comparable](u, v Either[A, B]) bool { + switch x := u.(type) { + case Left[A, B]: + switch y := v.(type) { + case Left[A, B]: + return x.Val.Equals(y.Val) + case Right[A, B]: + return false + } + case Right[A, B]: + switch y := v.(type) { + case Left[A, B]: + return false + case Right[A, B]: + return x.Val.Equals(y.Val) + } + } + + return false +} + +func EitherCpy[A Copyable[A], B Copyable[B]](u Either[A, B]) Either[A, B] { + switch x := u.(type) { + case Left[A, B]: + return MkLeft[A, B](x.Val.Copy()) + case Right[A, B]: + return MkRight[A, B](x.Val.Copy()) + } + return u +} diff --git a/src/Lib/int.go b/src/Lib/int.go index 68e24475..a7e4ef5b 100644 --- a/src/Lib/int.go +++ b/src/Lib/int.go @@ -37,24 +37,22 @@ package Lib -type Int struct { - value int -} +type Int int func (s Int) Equals(oth any) bool { if str, ok := oth.(Int); ok { - return s.value == str.value + return s == str } return false } func (s Int) Less(oth any) bool { if str, ok := oth.(Int); ok { - return s.value < str.value + return s < str } return false } func MkInt(s int) Int { - return Int{s} + return Int(s) } diff --git a/src/Lib/list.go b/src/Lib/list.go index 514fec51..14a483e8 100644 --- a/src/Lib/list.go +++ b/src/Lib/list.go @@ -88,13 +88,17 @@ func (l List[T]) At(i int) T { return l.values[i] } -func ListEquals[T Comparable](ls0, ls1 List[T]) bool { +func (l List[T]) Slice(st, ed int) List[T] { + return List[T]{values: l.values[st:ed]} +} + +func (l List[T]) Equals(cmp Func2[T, T, bool], ls0, ls1 List[T]) bool { if ls0.Len() != ls1.Len() { return false } for i := range ls0.values { - if !ls0.At(i).Equals(ls1.At(i)) { + if !cmp(ls0.At(i), ls1.At(i)) { return false } } @@ -102,6 +106,11 @@ func ListEquals[T Comparable](ls0, ls1 List[T]) bool { return true } +func ListEquals[T Comparable](ls0, ls1 List[T]) bool { + cmp := func(x, y T) bool { return x.Equals(y) } + return ls0.Equals(cmp, ls0, ls1) +} + func (l List[T]) ToString( strFunc Func[T, string], sep, emptyValue string, @@ -184,6 +193,53 @@ func (l List[T]) Empty() bool { return l.Len() == 0 } +func (l List[T]) IndexOf(x T, cmp Func2[T, T, bool]) Option[int] { + for i, el := range l.values { + if cmp(x, el) { + return MkSome(i) + } + } + return MkNone[int]() +} + +func ListIndexOf[T Comparable](x T, l List[T]) Option[int] { + cmp := func(x, y T) bool { return x.Equals(y) } + return l.IndexOf(x, cmp) +} + +func (l List[T]) RemoveAt(index int) List[T] { + new_list := NewList[T]() + for i, el := range l.values { + if i != index { + new_list.Append(el) + } + } + return new_list +} + +func (l List[T]) Clear() { + l.values = nil +} + +func (l List[T]) Any(pred Func[T, bool]) bool { + for _, el := range l.values { + if pred(el) { + return true + } + } + return false +} + +func (l List[T]) Filter(pred Func[T, bool]) List[T] { + res := NewList[T]() + for _, el := range l.values { + if pred(el) { + res.Append(el) + } + } + return res +} + func ToStrictlyOrderedList[T StrictlyOrdered](l List[T]) StrictlyOrderedList[T] { return StrictlyOrderedList[T]{values: l} } diff --git a/src/Lib/opt.go b/src/Lib/opt.go index e85b2a80..f78c6124 100644 --- a/src/Lib/opt.go +++ b/src/Lib/opt.go @@ -47,10 +47,10 @@ type None[A any] struct{} func (Some[A]) isOpt() {} func (None[A]) isOpt() {} -func OptBind[A, B any](u Option[A], f Func[A, B]) Option[B] { +func OptBind[A, B any](u Option[A], f Func[A, Option[B]]) Option[B] { switch x := u.(type) { case Some[A]: - return Some[B]{f(x.Val)} + return f(x.Val) case None[A]: return None[B]{} } diff --git a/src/Lib/par.go b/src/Lib/par.go new file mode 100644 index 00000000..21e1b5df --- /dev/null +++ b/src/Lib/par.go @@ -0,0 +1,86 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file provides a generic interface to launch goroutines on functions, + * collect their result and compute a final value. + * The computation of the final value is done incrementally at the answer of each child, + * consequently, the function taking care of reconciliating the output of two children + * should be associative, commutative, and have a neutral. + **/ + +package Lib + +import ( + "fmt" + "reflect" +) + +func GenericParallel[T any]( + calls []func(chan T), + reconciliation func(T, T) T, + neutral T, +) (T, error) { + channels := make([](chan T), len(calls)) + for i, call := range calls { + call_chan := make(chan T) + channels[i] = call_chan + go call(call_chan) + } + return genericSelect(channels, reconciliation, neutral) +} + +func genericSelect[T any]( + channels [](chan T), + reconciliation func(T, T) T, + neutral T, +) (T, error) { + remaining := len(channels) + res := neutral + cases := make([]reflect.SelectCase, len(channels)) + for i, channel := range channels { + cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(channel)} + } + + for remaining > 0 { + _, value, _ := reflect.Select(cases) + remaining-- + + if v, ok := value.Interface().(T); ok { + res = reconciliation(res, v) + } else { + return neutral, fmt.Errorf("Error in Lib.Par: channel has not answered a value of the right type.") + } + } + + return res, nil +} diff --git a/src/Lib/sets.go b/src/Lib/sets.go index 3be6ea17..be86e7d4 100644 --- a/src/Lib/sets.go +++ b/src/Lib/sets.go @@ -47,6 +47,7 @@ package Lib import ( _ "fmt" + "slices" ) // ----------------------------------------------------------------------------- @@ -302,12 +303,7 @@ func (s0 Set[T]) Diff(s1 Set[T]) Set[T] { } func (s0 Set[T]) Disjoint(s1 Set[T]) bool { - for _, x := range s1.Elements().GetSlice() { - if s0.Contains(x) { - return false - } - } - return true + return !slices.ContainsFunc(s1.Elements().GetSlice(), s0.Contains) } func (s Set[T]) Cardinal() int { @@ -322,6 +318,16 @@ func (s Set[T]) Copy() Set[T] { return mkSet(nodeCpy(s.root)) } +func (s Set[T]) Filter(pred Func[T, bool]) Set[T] { + res := EmptySet[T]() + for _, x := range s.Elements().GetSlice() { + if pred(x) { + res.Add(x) + } + } + return res +} + // ----------------------------------------------------------------------------- // Internal; do not call. diff --git a/src/Lib/string.go b/src/Lib/string.go index c84d5674..05c00449 100644 --- a/src/Lib/string.go +++ b/src/Lib/string.go @@ -37,24 +37,22 @@ package Lib -type String struct { - value string -} +type String string func (s String) Equals(oth any) bool { if str, ok := oth.(String); ok { - return s.value == str.value + return s == str } return false } func (s String) Less(oth any) bool { if str, ok := oth.(String); ok { - return s.value < str.value + return s < str } return false } func MkString(s string) String { - return String{s} + return String(s) } diff --git a/src/Mods/CertifUtils/context.go b/src/Mods/CertifUtils/context.go new file mode 100644 index 00000000..c5322cb7 --- /dev/null +++ b/src/Mods/CertifUtils/context.go @@ -0,0 +1,128 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ +package CertifUtils + +/** + * This file provides a function that returns the context of a proof (the symbols appearing in it). + **/ + +import ( + "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Typing" +) + +type OrderedConPair Lib.Pair[AST.Id, AST.Ty] + +func (p OrderedConPair) Equals(oth any) bool { + if op, is_op := oth.(OrderedConPair); is_op { + return p.Fst.Equals(op.Fst) && p.Snd.Equals(op.Snd) + } + return false +} + +func (p OrderedConPair) Less(oth any) bool { + if op, is_op := oth.(OrderedConPair); is_op { + return p.Fst.Less(op.Fst) + } + return false +} + +func GetContextFromFormula(root AST.Form) Lib.List[Lib.Pair[AST.Id, AST.Ty]] { + out_list := Lib.NewList[Lib.Pair[AST.Id, AST.Ty]]() + for _, p := range getContextFromFormula(root).Elements().GetSlice() { + out_list.Append(Lib.MkPair(p.Fst, p.Snd)) + } + return out_list +} + +func getContextFromFormula(root AST.Form) Lib.Set[OrderedConPair] { + aux := func(children Lib.List[AST.Form]) Lib.Set[OrderedConPair] { + res := Lib.EmptySet[OrderedConPair]() + for _, child := range children.GetSlice() { + res = res.Union(getContextFromFormula(child)) + } + return res + } + + switch nf := root.(type) { + case AST.Top, AST.Bot: + return Lib.EmptySet[OrderedConPair]() + case AST.All, AST.Ex, AST.And, AST.Or, AST.Imp, AST.Equ, AST.Not: + return aux(root.GetChildFormulas()) + case AST.Pred: + res := Lib.EmptySet[OrderedConPair]() + if !nf.GetID().Equals(AST.Id_eq) { + oty := Typing.QueryGlobalEnv(nf.GetID().GetName()) + var ty AST.Ty + switch rty := oty.(type) { + case Lib.Some[AST.Ty]: + ty = rty.Val + case Lib.None[AST.Ty]: + ty = AST.MkDefaultPredType(nf.GetArgs().Len()) + } + + res = res.Add(OrderedConPair(Lib.MkPair(nf.GetID(), ty))) + } + for _, term := range nf.GetArgs().GetSlice() { + res = res.Union(getContextFromTerm(term)) + } + return res + } + Glob.Anomaly("CertifUtils", "Reached an impossible case") + return Lib.EmptySet[OrderedConPair]() +} + +func getContextFromTerm(trm AST.Term) Lib.Set[OrderedConPair] { + fun, isFun := trm.(AST.Fun) + if !isFun { + return Lib.EmptySet[OrderedConPair]() + } + + oty := Typing.QueryGlobalEnv(fun.GetName()) + var ty AST.Ty + + switch rty := oty.(type) { + case Lib.Some[AST.Ty]: + ty = rty.Val + case Lib.None[AST.Ty]: + ty = AST.MkDefaultFunctionType(fun.GetArgs().Len()) + } + + res := Lib.Singleton(OrderedConPair(Lib.MkPair(fun.GetID(), ty))) + for _, term := range fun.GetArgs().GetSlice() { + res = res.Union(getContextFromTerm(term)) + } + + return res +} diff --git a/src/Mods/CertifUtils/sanitizer.go b/src/Mods/CertifUtils/sanitizer.go new file mode 100644 index 00000000..3549646a --- /dev/null +++ b/src/Mods/CertifUtils/sanitizer.go @@ -0,0 +1,49 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ +package CertifUtils + +/** + * This file provides a function that returns the context of a proof (the symbols appearing in it). + **/ + +import ( + "github.com/GoelandProver/Goeland/Glob" + "strings" +) + +func SanitizedTheoremName() string { + problemName := Glob.GetProblemName() + for _, s := range []string{".", "=", "+", "-"} { + problemName = strings.ReplaceAll(problemName, s, "_") + } + return problemName +} diff --git a/src/Mods/CertifUtils/utils.go b/src/Mods/CertifUtils/utils.go new file mode 100644 index 00000000..3a0726f5 --- /dev/null +++ b/src/Mods/CertifUtils/utils.go @@ -0,0 +1,50 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ +package CertifUtils + +/** + * This file provides utility functions for proof certification + **/ + +import ( + "github.com/GoelandProver/Goeland/AST" +) + +func IsPredEqual(f AST.Form) bool { + if not, isNot := f.(AST.Not); isNot { + f = not.GetForm() + } + if p, isPred := f.(AST.Pred); isPred { + return p.GetID().Equals(AST.Id_eq) + } + return false +} diff --git a/src/Mods/assisted/assistant.go b/src/Mods/assisted/assistant.go index 1064567e..5383d608 100644 --- a/src/Mods/assisted/assistant.go +++ b/src/Mods/assisted/assistant.go @@ -38,6 +38,7 @@ import ( "github.com/GoelandProver/Goeland/Core" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Search" "github.com/GoelandProver/Goeland/Unif" ) @@ -185,7 +186,8 @@ func selectStatus() int { func printFormListFromState(st *Search.State, id int) { fmt.Printf("\nState nº%d:\n", id) - printSubList("Applied subs", st.GetAppliedSubst().GetSubst()) + // FIXME: why is this all fmt.Printf? + fmt.Printf("Applied subs: %s", Lib.ListToString(st.GetAppliedSubst().GetSubst(), ", ", "(empty subst)")) printSubList("X - Atomic", st.GetAtomic()) printSubList("A - Alpha", st.GetAlpha()) printSubList("B - Beta", st.GetBeta()) @@ -211,15 +213,15 @@ func printSubList[T Glob.Stringable](title string, list []T) { func printGoelandChoice(st *Search.State) { found := false - allSubs := []Unif.Substitutions{} + allSubs := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() withSubs := true for _, form := range st.GetAtomic() { canClose, subs := Search.ApplyClosureRules(form.GetForm(), st) if canClose { found = true - if len(subs) > 0 && !subs[0].IsEmpty() { - allSubs = append(allSubs, subs...) + if !subs.Empty() && !subs.At(0).Empty() { + allSubs.Append(subs.GetSlice()...) } else { withSubs = false } @@ -229,7 +231,7 @@ func printGoelandChoice(st *Search.State) { if found { str := " └ Goéland would apply the Closure rule" if withSubs { - str += " with the following substitution: " + allSubs[0].ToString() + str += " with the following substitution: " + Lib.ListToString(allSubs.At(0), ", ", "(empty subst)") } else { str += " without any subsitutions" } @@ -358,14 +360,17 @@ func selectFormula(forms Core.FormAndTermsList) int { func selectSubstitution(substs []Core.SubstAndForm) int { fmt.Printf("Found closure rule with substitution that is used elsewhere.\n") fmt.Printf("Here is the list of possible substitutions :\n") - uniqueSubs := []Unif.Substitutions{} + uniqueSubs := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() for _, sub := range substs { - uniqueSubs = Unif.AppendIfNotContainsSubst(uniqueSubs, sub.GetSubst()) + uniqueSubs.Add( + Lib.ListEquals[Unif.MixedSubstitution], + sub.GetSubst(), + ) } - for i, elem := range uniqueSubs { - fmt.Printf("[%d] %v\n", i, elem.ToString()) + for i, elem := range uniqueSubs.GetSlice() { + fmt.Printf("[%d] %v\n", i, Lib.ListToString(elem, ", ", "(empty subst)")) } isSubstitutionValid := false @@ -373,8 +378,10 @@ func selectSubstitution(substs []Core.SubstAndForm) int { for !isSubstitutionValid { fmt.Printf("Select a substitution ~> ") fmt.Scanf("%d", &choice) - if choice < len(uniqueSubs) && choice >= 0 { - fmt.Printf("You selected the substitution %v.\n", uniqueSubs[choice].ToString()) + if choice < uniqueSubs.Len() && choice >= 0 { + fmt.Printf("You selected the substitution %v.\n", + Lib.ListToString(uniqueSubs.At(choice), ", ", "(empty subst)"), + ) isSubstitutionValid = true fmt.Println("-------------------------") } else { diff --git a/src/Mods/assisted/rules.go b/src/Mods/assisted/rules.go index 9e288dc6..cdce6820 100644 --- a/src/Mods/assisted/rules.go +++ b/src/Mods/assisted/rules.go @@ -81,7 +81,12 @@ func applyAtomicRule(state Search.State, fatherId uint64, c Search.Communication clos_res_after_apply_subst, subst_after_apply_subst := Search.ApplyClosureRules(f.GetForm(), &state) if clos_res_after_apply_subst { - boolSubsts, resSubsts := searchAlgo.ManageClosureRule(fatherId, &state, c, Unif.CopySubstList(subst_after_apply_subst), f.Copy(), nodeId, originalNodeId) + boolSubsts, resSubsts := searchAlgo.ManageClosureRule( + fatherId, + &state, + c, + subst_after_apply_subst.Copy(Lib.ListCpy[Unif.MixedSubstitution]), + f.Copy(), nodeId, originalNodeId) if !boolSubsts { finalBool = false } diff --git a/src/Mods/dmt/axiom_registration.go b/src/Mods/dmt/axiom_registration.go index 7cb3e963..9bcbc094 100644 --- a/src/Mods/dmt/axiom_registration.go +++ b/src/Mods/dmt/axiom_registration.go @@ -76,7 +76,7 @@ func instanciateForalls(axiom AST.Form) AST.Form { func addPosRewriteRule(axiom AST.Form, cons AST.Form) { simplifiedAxiom := AST.RemoveNeg(axiom) positiveTree = positiveTree.InsertFormulaListToDataStructure( - AST.NewFormList(simplifiedAxiom), + Lib.MkListV(simplifiedAxiom), ) addRewriteRule(simplifiedAxiom, cons, true) } @@ -84,7 +84,7 @@ func addPosRewriteRule(axiom AST.Form, cons AST.Form) { func addNegRewriteRule(axiom AST.Form, cons AST.Form) { simplifiedAxiom := AST.RemoveNeg(axiom) negativeTree = negativeTree.InsertFormulaListToDataStructure( - AST.NewFormList(simplifiedAxiom), + Lib.MkListV(simplifiedAxiom), ) addRewriteRule(simplifiedAxiom, cons, false) } diff --git a/src/Mods/dmt/dmt.go b/src/Mods/dmt/dmt.go index e4cf0351..b97fbebc 100644 --- a/src/Mods/dmt/dmt.go +++ b/src/Mods/dmt/dmt.go @@ -42,11 +42,12 @@ import ( "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Unif" ) -var positiveRewrite map[string]*AST.FormList /* Stores rewrites of atoms with positive occurrences */ -var negativeRewrite map[string]*AST.FormList /* Stores rewrites of atoms with negative occurrences */ +var positiveRewrite map[string]Lib.List[AST.Form] /* Stores rewrites of atoms with positive occurrences */ +var negativeRewrite map[string]Lib.List[AST.Form] /* Stores rewrites of atoms with negative occurrences */ var positiveTree Unif.DataStructure /* Matches atoms with positive occurrences */ var negativeTree Unif.DataStructure /* Matches atoms with negative occurrences */ @@ -57,7 +58,7 @@ var preskolemize bool var flagPolarized = flag.Bool("polarized", false, "Activate polarized DMT") var flagPresko = flag.Bool("presko", false, "Activate preskolemization on DMT") -var registeredAxioms *AST.FormList +var registeredAxioms Lib.List[AST.Form] /** * Base function needed to initialize any plugin of Goéland. @@ -79,12 +80,12 @@ func InitPluginTests(polarized, presko bool) { } func initPluginGlobalVariables() { - positiveRewrite = make(map[string]*AST.FormList) - negativeRewrite = make(map[string]*AST.FormList) + positiveRewrite = make(map[string]Lib.List[AST.Form]) + negativeRewrite = make(map[string]Lib.List[AST.Form]) positiveTree = Unif.NewNode() negativeTree = Unif.NewNode() - registeredAxioms = AST.NewFormList() + registeredAxioms = Lib.NewList[AST.Form]() } /** @@ -115,7 +116,6 @@ func parsePluginOptions() { Glob.PrintInfo("DMT", output) } - -func GetRegisteredAxioms() *AST.FormList { +func GetRegisteredAxioms() Lib.List[AST.Form] { return registeredAxioms } diff --git a/src/Mods/dmt/rewrite.go b/src/Mods/dmt/rewrite.go index 2fdbbac6..c72375f3 100644 --- a/src/Mods/dmt/rewrite.go +++ b/src/Mods/dmt/rewrite.go @@ -60,7 +60,11 @@ func rewriteGeneric(tree Unif.DataStructure, atomic AST.Form, form AST.Form, pol var err error = nil if isUnified, unif := tree.Unify(form); isUnified { - rewritten, err = getRewrittenFormulas(rewritten, unif, atomic, polarity) + unif_substs := []Unif.MatchingSubstitutions{} + for _, substs := range unif { + unif_substs = append(unif_substs, substs.MatchingSubstitutions()) + } + rewritten, err = getRewrittenFormulas(rewritten, unif_substs, atomic, polarity) } else { rewritten = rewriteFailure(atomic) } @@ -84,9 +88,11 @@ func getRewrittenFormulas(rewritten []Core.IntSubstAndForm, unif []Unif.Matching return rewritten, nil } -func addRewrittenFormulas(rewritten []Core.IntSubstAndForm, unif Unif.MatchingSubstitutions, atomic AST.Form, equivalence *AST.FormList) []Core.IntSubstAndForm { +func addRewrittenFormulas(rewritten []Core.IntSubstAndForm, unif Unif.MatchingSubstitutions, atomic AST.Form, equivalence Lib.List[AST.Form]) []Core.IntSubstAndForm { // Keep only useful substitutions - useful_subst := Core.RemoveElementWithoutMM(unif.GetSubst(), atomic.GetMetas()) + useful_subst := Unif.ToSubstitutions( + Core.RemoveElementWithoutMM(Unif.FromSubstitutions(unif.GetSubst()), atomic.GetMetas()), + ) meta_search := atomic.GetMetas() if !checkMetaAreFromSearch(meta_search, useful_subst) { Glob.PrintError("DMT", fmt.Sprintf("There is at least one meta in final subst which is not from search : %v - %v - %v", useful_subst.ToString(), atomic.ToString(), unif.GetForm().ToString())) @@ -97,7 +103,7 @@ func addRewrittenFormulas(rewritten []Core.IntSubstAndForm, unif Unif.MatchingSu ) // Add each candidate to the rewrite slice with precedence order (Top/Bot are prioritized). - for _, rewrittenCandidate := range equivalence.Slice() { + for _, rewrittenCandidate := range equivalence.GetSlice() { rewritten = addUnifToAtomics(rewritten, rewrittenCandidate, filteredUnif) } @@ -121,12 +127,19 @@ func getAtomAndPolarity(atom AST.Form) (AST.Form, bool) { func rewriteFailure(atomic AST.Form) []Core.IntSubstAndForm { return []Core.IntSubstAndForm{ - Core.MakeIntSubstAndForm(-1, Core.MakeSubstAndForm(Unif.Failure(), AST.NewFormList(atomic))), + Core.MakeIntSubstAndForm( + -1, + Core.MakeSubstAndForm(Lib.MkListV(Unif.MkMixedFromSubst(Unif.Failure()[0])), Lib.MkListV(atomic)), + ), } } func addUnifToAtomics(atomics []Core.IntSubstAndForm, candidate AST.Form, unif Unif.MatchingSubstitutions) []Core.IntSubstAndForm { - substAndForm := Core.MakeSubstAndForm(unif.GetSubst().Copy(), AST.NewFormList(candidate)) + mixed := Lib.NewList[Unif.MixedSubstitution]() + for _, subst := range unif.GetSubst() { + mixed.Append(Unif.MkMixedFromSubst(subst)) + } + substAndForm := Core.MakeSubstAndForm(mixed, Lib.MkListV(candidate)) if isBotOrTop(candidate) { atomics = Core.InsertFirstIntSubstAndFormList(atomics, Core.MakeIntSubstAndForm(unif.GetForm().GetIndex(), substAndForm)) } else { @@ -155,8 +168,8 @@ func sortUnifications(unifs []Unif.MatchingSubstitutions, polarity bool, atomic } // Priority of substitutions: Top/Bottom > others -func insert(sortedUnifs []Unif.MatchingSubstitutions, list *AST.FormList, unif Unif.MatchingSubstitutions) []Unif.MatchingSubstitutions { - if list.Contains(AST.MakerTop()) || list.Contains(AST.MakerBot()) { +func insert(sortedUnifs []Unif.MatchingSubstitutions, list Lib.List[AST.Form], unif Unif.MatchingSubstitutions) []Unif.MatchingSubstitutions { + if Lib.ListMem(AST.MakerTop().Copy(), list) || Lib.ListMem(AST.MakerBot().Copy(), list) { sortedUnifs = insertFirst(sortedUnifs, unif) } else { sortedUnifs = append(sortedUnifs, unif) @@ -213,21 +226,25 @@ func checkMetaAreFromSearch(metas Lib.Set[AST.Meta], subst Unif.Substitutions) b return true } -func getUnifiedEquivalence(atom AST.Form, subst Unif.Substitutions, polarity bool) (*AST.FormList, error) { +func getUnifiedEquivalence(atom AST.Form, subst Unif.Substitutions, polarity bool) (Lib.List[AST.Form], error) { equivalence := findEquivalence(atom, polarity) - if equivalence == nil { - return nil, fmt.Errorf("[DMT] Fatal error : no rewrite rule found when an unification has been found : %v", atom.ToString()) + if equivalence.Empty() { + return Lib.NewList[AST.Form](), + fmt.Errorf( + "[DMT] Fatal error : no rewrite rule found when an unification has been found : %v", + atom.ToString(), + ) } - res := AST.NewFormList() - for _, f := range equivalence.Slice() { - res.AppendIfNotContains(substitute(f, subst)) + res := Lib.NewList[AST.Form]() + for _, f := range equivalence.GetSlice() { + res = Lib.ListAdd(res, substitute(f, subst)) } return res, nil } -func findEquivalence(atom AST.Form, polarity bool) *AST.FormList { +func findEquivalence(atom AST.Form, polarity bool) Lib.List[AST.Form] { return selectFromPolarity(polarity, positiveRewrite, negativeRewrite)[atom.ToString()] } diff --git a/src/Mods/dmt/rewritten.go b/src/Mods/dmt/rewritten.go index d21c7e8d..a68b16f3 100644 --- a/src/Mods/dmt/rewritten.go +++ b/src/Mods/dmt/rewritten.go @@ -39,7 +39,6 @@ package dmt import ( "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Core" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Unif" @@ -48,7 +47,7 @@ import ( func substitute(form AST.Form, subst Unif.Substitutions) AST.Form { for _, s := range subst { old_symbol, new_symbol := s.Get() - form = Core.ApplySubstitutionOnFormula(old_symbol, new_symbol, form) + form = form.ReplaceMetaByTerm(old_symbol, new_symbol) } return form } diff --git a/src/Mods/dmt/utils.go b/src/Mods/dmt/utils.go index 50454f27..3b75bfc0 100644 --- a/src/Mods/dmt/utils.go +++ b/src/Mods/dmt/utils.go @@ -38,6 +38,7 @@ package dmt import ( "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Lib" ) func isEquality(pred AST.Pred) bool { @@ -59,8 +60,10 @@ func rewriteMapInsertion(polarity bool, key string, val AST.Form) { rewriteMap := selectFromPolarity(polarity, positiveRewrite, negativeRewrite) if _, ok := rewriteMap[key]; !ok { - rewriteMap[key] = AST.NewFormList() + rewriteMap[key] = Lib.NewList[AST.Form]() } - rewriteMap[key].Append(val) + ls := rewriteMap[key] + ls.Append(val) + rewriteMap[key] = ls } diff --git a/src/Mods/equality/bse/equality.go b/src/Mods/equality/bse/equality.go index ee12afae..d0c1b2f2 100644 --- a/src/Mods/equality/bse/equality.go +++ b/src/Mods/equality/bse/equality.go @@ -68,12 +68,22 @@ func TryEquality(atomics_for_dmt Core.FormAndTermsList, st Search.State, new_ato debug(Lib.MkLazy(func() string { return "EQ is applicable !" })) atomics_plus_dmt := append(st.GetAtomic(), atomics_for_dmt...) res_eq, subst_eq := EqualityReasoning(st.GetEqStruct(), st.GetTreePos(), st.GetTreeNeg(), atomics_plus_dmt.ExtractForms(), original_node_id) + + send_to_proof_search := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() + for _, substs := range subst_eq { + local_list := Lib.NewList[Unif.MixedSubstitution]() + for _, subst := range substs { + local_list.Append(Unif.MkMixedFromSubst(subst)) + } + send_to_proof_search.Append(local_list) + } + if res_eq { Search.UsedSearch.ManageClosureRule( father_id, &st, cha, - subst_eq, + send_to_proof_search, Core.MakeFormAndTerm( AST.EmptyPredEq, Lib.NewList[AST.Term](), @@ -94,7 +104,7 @@ func TryEquality(atomics_for_dmt Core.FormAndTermsList, st Search.State, new_ato * creates the problem * returns a bool for success and the corresponding substitution **/ -func EqualityReasoning(eqStruct eqStruct.EqualityStruct, tree_pos, tree_neg Unif.DataStructure, atomic *AST.FormList, originalNodeId int) (bool, []Unif.Substitutions) { +func EqualityReasoning(eqStruct eqStruct.EqualityStruct, tree_pos, tree_neg Unif.DataStructure, atomic Lib.List[AST.Form], originalNodeId int) (bool, []Unif.Substitutions) { debug(Lib.MkLazy(func() string { return "ER call" })) problem, equalities := buildEqualityProblemMultiList(atomic, tree_pos, tree_neg) if equalities { diff --git a/src/Mods/equality/bse/equality_problem.go b/src/Mods/equality/bse/equality_problem.go index b2e4ad91..e40d29da 100644 --- a/src/Mods/equality/bse/equality_problem.go +++ b/src/Mods/equality/bse/equality_problem.go @@ -85,7 +85,7 @@ func (ep EqualityProblem) AxiomsToTPTPString() string { } func (ep EqualityProblem) ToTPTPString() string { - return ep.GetS().ToMappedString(AST.DefaultMapString, false) + " = " + ep.GetT().ToMappedString(AST.DefaultMapString, false) + return ep.GetS().ToString() + " = " + ep.GetT().ToString() } /* Apply a substitution on an equality problem */ @@ -136,11 +136,11 @@ func makeEqualityProblem(E Equalities, s AST.Term, t AST.Term, c ConstraintStruc /* Take a list of equalities and build the corresponding code tree */ func makeDataStructFromEqualities(eq Equalities) Unif.DataStructure { - formList := AST.NewFormList() + formList := Lib.NewList[AST.Form]() for _, e := range eq { formList.Append(Unif.MakerTermForm(e.GetT1()), Unif.MakerTermForm(e.GetT2())) } - return Unif.NewNode().MakeDataStruct(formList.Copy(), true) + return Unif.NewNode().MakeDataStruct(Lib.ListCpy(formList), true) } /* Take a list of equalities and build the corresponding assocative map */ diff --git a/src/Mods/equality/bse/equality_problem_list.go b/src/Mods/equality/bse/equality_problem_list.go index f29243bc..fce98743 100644 --- a/src/Mods/equality/bse/equality_problem_list.go +++ b/src/Mods/equality/bse/equality_problem_list.go @@ -46,6 +46,7 @@ import ( "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Typing" "github.com/GoelandProver/Goeland/Unif" ) @@ -149,7 +150,7 @@ func (epml EqualityProblemMultiList) GetMetasToTPTPString() string { if metas.Cardinal() > 0 { result = "? [" for _, meta := range metas.Elements().GetSlice() { - result += meta.ToMappedString(AST.DefaultMapString, false) + ", " + result += meta.ToString() + ", " } result = result[:len(result)-2] + "] : " } @@ -208,15 +209,24 @@ func buildEqualityProblemMultiListFromPredList(pred AST.Pred, tn Unif.DataStruct predId := pred.GetID() metas := Lib.NewList[AST.Meta]() - for _, arg := range pred.GetArgs().GetSlice() { - metas = Lib.ListAdd(metas, AST.MakerMeta("METAEQ_"+arg.ToString(), -1)) + tys := Lib.NewList[AST.Ty]() + switch rty := Typing.QueryEnvInstance(predId.GetName(), pred.GetTyArgs()).(type) { + case Lib.Some[AST.Ty]: + tys = AST.GetArgsTy(rty.Val) + case Lib.None[AST.Ty]: + for range pred.GetArgs().GetSlice() { + tys.Append(AST.TIndividual()) + } + } + + for i, arg := range pred.GetArgs().GetSlice() { + metas = Lib.ListAdd(metas, AST.MakerMeta("METAEQ_"+arg.ToString(), -1, tys.At(i))) } newTerm := AST.MakerPred( predId.Copy().(AST.Id), + pred.GetTyArgs(), AST.MetaListToTermList(metas), - pred.GetTypeVars(), - pred.GetType(), ) found, complementaryPredList := tn.Unify(newTerm) @@ -230,9 +240,9 @@ func buildEqualityProblemMultiListFromPredList(pred AST.Pred, tn Unif.DataStruct } /* Take a list of form and build an equality problem list, corresponding to thoses related to a predicate and its negation */ -func buildEqualityProblemMultiListFromFormList(fl *AST.FormList, tn Unif.DataStructure, eq Equalities) EqualityProblemMultiList { +func buildEqualityProblemMultiListFromFormList(fl Lib.List[AST.Form], tn Unif.DataStructure, eq Equalities) EqualityProblemMultiList { res := makeEmptyEqualityProblemMultiList() - for _, p := range fl.Slice() { + for _, p := range fl.GetSlice() { if pt, ok := p.(AST.Pred); ok { debug( Lib.MkLazy(func() string { return fmt.Sprintf("Pred found : %v", p.ToString()) }), @@ -249,7 +259,7 @@ func buildEqualityProblemMultiListFromFormList(fl *AST.FormList, tn Unif.DataStr * Take a form list * Retun a lis of independent problem list (from predicate and negation) + a boolean, true if there is equality in the formula list, false otherwise **/ -func buildEqualityProblemMultiList(fl *AST.FormList, tp, tn Unif.DataStructure) (EqualityProblemMultiList, bool) { +func buildEqualityProblemMultiList(fl Lib.List[AST.Form], tp, tn Unif.DataStructure) (EqualityProblemMultiList, bool) { res := makeEmptyEqualityProblemMultiList() eq := retrieveEqualities(tp.Copy()) if len(eq) == 0 { @@ -259,7 +269,7 @@ func buildEqualityProblemMultiList(fl *AST.FormList, tp, tn Unif.DataStructure) debug( Lib.MkLazy(func() string { return fmt.Sprintf("Res after FromNEQ : %v", res.ToString()) }), ) - res = append(res, buildEqualityProblemMultiListFromFormList(fl.Copy(), tn.Copy(), eq.copy())...) + res = append(res, buildEqualityProblemMultiListFromFormList(Lib.ListCpy(fl), tn.Copy(), eq.copy())...) debug( Lib.MkLazy(func() string { return fmt.Sprintf("Res after FromForm : %v", res.ToString()) }), ) diff --git a/src/Mods/equality/bse/equality_rules_try_apply.go b/src/Mods/equality/bse/equality_rules_try_apply.go index 13f493fa..b24dda94 100644 --- a/src/Mods/equality/bse/equality_rules_try_apply.go +++ b/src/Mods/equality/bse/equality_rules_try_apply.go @@ -229,8 +229,7 @@ func checkUnifInTree(t AST.Term, tree Unif.DataStructure) (bool, Lib.List[AST.Te for _, subst := range ms { debug( Lib.MkLazy(func() string { - return fmt.Sprintf("Unif found with %v :%v", - subst.GetForm().ToString(), subst.GetSubst().ToString()) + return fmt.Sprintf("Unif found with: %s", subst.ToString()) }), ) result_list.Append(subst.GetForm().(Unif.TermForm).GetTerm()) diff --git a/src/Mods/equality/bse/equality_types.go b/src/Mods/equality/bse/equality_types.go index ac16dd5c..d0ce8462 100644 --- a/src/Mods/equality/bse/equality_types.go +++ b/src/Mods/equality/bse/equality_types.go @@ -120,24 +120,21 @@ func (equs Equalities) removeHalf() Equalities { /* Retrieve equalities from a datastructure */ func retrieveEqualities(dt Unif.DataStructure) Equalities { res := Equalities{} - MetaEQ1 := AST.MakerMeta("METAEQ1", -1) - MetaEQ2 := AST.MakerMeta("METAEQ2", -1) - // TODO: type this - tv := AST.MkTypeVar("EQ") - eq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Term](), []AST.TypeApp{}) - tv.ShouldBeMeta(eq_pred.GetIndex()) - tv.Instantiate(1) + meta_ty := AST.MkTyMeta("META_TY_EQ", -1) + MetaEQ1 := AST.MakerMeta("METAEQ1", -1, meta_ty) + MetaEQ2 := AST.MakerMeta("METAEQ2", -1, meta_ty) + + eq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Ty](), Lib.NewList[AST.Term]()) eq_pred = AST.MakePred( eq_pred.GetIndex(), AST.Id_eq, + Lib.MkListV[AST.Ty](meta_ty), Lib.MkListV[AST.Term](MetaEQ1, MetaEQ2), - []AST.TypeApp{}, - AST.GetPolymorphicType(AST.Id_eq.GetName(), 1, 2), ) _, eq_list := dt.Unify(eq_pred) for _, ms := range eq_list { - ms_ordered := orderSubstForRetrieve(ms.GetSubst(), MetaEQ1, MetaEQ2) + ms_ordered := orderSubstForRetrieve(ms.MatchingSubstitutions().GetSubst(), MetaEQ1, MetaEQ2) eq1_term, ok_t1 := ms_ordered.Get(MetaEQ1) if ok_t1 == -1 { Glob.PrintError("RI", "Meta_eq_1 not found in map") @@ -154,25 +151,21 @@ func retrieveEqualities(dt Unif.DataStructure) Equalities { /* Retrieve inequalities from a datastructure */ func retrieveInequalities(dt Unif.DataStructure) Inequalities { res := Inequalities{} - MetaNEQ1 := AST.MakerMeta("META_NEQ_1", -1) - MetaNEQ2 := AST.MakerMeta("META_NEQ_2", -1) - // TODO: type this - - tv := AST.MkTypeVar("EQ") - neq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Term](), []AST.TypeApp{}) - tv.ShouldBeMeta(neq_pred.GetIndex()) - tv.Instantiate(1) + meta_ty := AST.MkTyMeta("META_TY_NEQ", -1) + MetaNEQ1 := AST.MakerMeta("META_NEQ_1", -1, meta_ty) + MetaNEQ2 := AST.MakerMeta("META_NEQ_2", -1, meta_ty) + + neq_pred := AST.MakerPred(AST.Id_eq, Lib.NewList[AST.Ty](), Lib.NewList[AST.Term]()) neq_pred = AST.MakePred( neq_pred.GetIndex(), AST.Id_eq, + Lib.MkListV(meta_ty), Lib.MkListV[AST.Term](MetaNEQ1, MetaNEQ2), - []AST.TypeApp{}, - AST.GetPolymorphicType(AST.Id_eq.GetName(), 1, 2), ) _, neq_list := dt.Unify(neq_pred) for _, ms := range neq_list { - ms_ordered := orderSubstForRetrieve(ms.GetSubst(), MetaNEQ1, MetaNEQ2) + ms_ordered := orderSubstForRetrieve(ms.MatchingSubstitutions().GetSubst(), MetaNEQ1, MetaNEQ2) neq1_term, ok_t1 := ms_ordered.Get(MetaNEQ1) if ok_t1 == -1 { Glob.PrintError("RI", "Meta_eq_1 not found in map") diff --git a/src/Mods/equality/eqStruct/term_pair.go b/src/Mods/equality/eqStruct/term_pair.go index 8009e621..0b79f0bb 100644 --- a/src/Mods/equality/eqStruct/term_pair.go +++ b/src/Mods/equality/eqStruct/term_pair.go @@ -94,7 +94,7 @@ func (tp TermPair) ToString() string { return tp.GetT1().ToString() + " ≈ " + tp.GetT2().ToString() } func (tp TermPair) ToTPTPString() string { - return tp.GetT1().ToMappedString(AST.DefaultMapString, false) + " = " + tp.GetT2().ToMappedString(AST.DefaultMapString, false) + return tp.GetT1().ToString() + " = " + tp.GetT2().ToString() } func MakeTermPair(t1, t2 AST.Term) TermPair { return TermPair{t1.Copy(), t2.Copy()} diff --git a/src/Mods/equality/sateq/subsgatherer.go b/src/Mods/equality/sateq/subsgatherer.go index 3fd60f13..41b30cff 100644 --- a/src/Mods/equality/sateq/subsgatherer.go +++ b/src/Mods/equality/sateq/subsgatherer.go @@ -83,7 +83,7 @@ func translate(toTranslate *eqClass, correspondence map[*eqClass]*termRecord) AS for i, s := range tr.args { args.Upd(i, translate(s, correspondence)) } - return AST.MakerFun(tr.symbolId, args, tr.typeVars, tr.typeHint) + return AST.MakerFun(tr.symbolId, tr.tyArgs, args) } } diff --git a/src/Mods/equality/sateq/termrep.go b/src/Mods/equality/sateq/termrep.go index 8d1a2b84..244a5777 100644 --- a/src/Mods/equality/sateq/termrep.go +++ b/src/Mods/equality/sateq/termrep.go @@ -36,6 +36,7 @@ import ( "fmt" "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Lib" ) type Ordered[T any] interface { @@ -130,8 +131,6 @@ func funTermRecord(t AST.Fun, args []*eqClass) *termRecord { meta: nil, symbolId: t.GetID(), args: args, - typeHint: t.GetTypeHint(), - typeVars: t.GetTypeVars(), } } @@ -140,9 +139,8 @@ type termRecord struct { eqClass *eqClass meta *AST.Meta symbolId AST.Id + tyArgs Lib.List[AST.Ty] args []*eqClass - typeHint AST.TypeScheme - typeVars []AST.TypeApp } func (t *termRecord) isMeta() bool { diff --git a/src/Mods/gs3/dependency.go b/src/Mods/gs3/dependency.go index 7823a9ec..80209233 100644 --- a/src/Mods/gs3/dependency.go +++ b/src/Mods/gs3/dependency.go @@ -34,6 +34,7 @@ package gs3 import ( "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" ) const ( @@ -54,10 +55,10 @@ func manageGammasInstantiations(initialForm, resultForm AST.Form) AST.Term { //PrintInfo("FORMS", fmt.Sprintf("init: %s, result: %s", initialForm.ToString(), resultForm.ToString())) switch initialGamma := initialForm.(type) { case AST.All: - term = getResultTerm(initialGamma.GetVarList()[0], normalisedInitialForm, resultForm) + term = getResultTerm(initialGamma.GetVarList().At(0), normalisedInitialForm, resultForm) case AST.Not: if ex, ok := initialGamma.GetForm().(AST.Ex); ok { - term = getResultTerm(ex.GetVarList()[0], normalisedInitialForm, resultForm) + term = getResultTerm(ex.GetVarList().At(0), normalisedInitialForm, resultForm) } } //PrintInfo("TERM", fmt.Sprintf("Term: %s ; Result: %s", term.ToString(), resultForm.ToString())) @@ -73,10 +74,10 @@ func manageDeltasSkolemisations(initialForm, resultForm AST.Form) AST.Term { normalisedInitialForm := getNextFormula(initialForm.Copy()) switch initialDelta := initialForm.(type) { case AST.Ex: - term = getResultTerm(initialDelta.GetVarList()[0], normalisedInitialForm, resultForm) + term = getResultTerm(initialDelta.GetVarList().At(0), normalisedInitialForm, resultForm) case AST.Not: if all, ok := initialDelta.GetForm().(AST.All); ok { - term = getResultTerm(all.GetVarList()[0], normalisedInitialForm, resultForm) + term = getResultTerm(all.GetVarList().At(0), normalisedInitialForm, resultForm) } } return term @@ -90,14 +91,14 @@ func getNextFormula(form AST.Form) AST.Form { switch f := form.(type) { case AST.All: varList := f.GetVarList() - if len(varList) > 1 { - return AST.MakerAll(varList[1:], f.GetForm()) + if varList.Len() > 1 { + return AST.MakerAll(varList.Slice(1, varList.Len()), f.GetForm()) } return f.GetForm() case AST.Ex: varList := f.GetVarList() - if len(varList) > 1 { - return AST.MakerEx(varList[1:], f.GetForm()) + if varList.Len() > 1 { + return AST.MakerEx(varList.Slice(1, varList.Len()), f.GetForm()) } return f.GetForm() case AST.Not: @@ -106,17 +107,17 @@ func getNextFormula(form AST.Form) AST.Form { return form } -func getResultTerm(v AST.Var, bareForm, endForm AST.Form) AST.Term { +func getResultTerm(v AST.TypedVar, bareForm, endForm AST.Form) AST.Term { variablesOccurrences := getAllVariableOccurrences(v, bareForm) return getTermAt(endForm, variablesOccurrences) } // Explores the form and if a variable in the varlist is found, returns its occurrence. -func getAllVariableOccurrences(v AST.Var, form AST.Form) occurrences { +func getAllVariableOccurrences(v AST.TypedVar, form AST.Form) occurrences { return getVariableOccurrencesForm(v, form, occurrences{}, occurrence{}) } -func getVariableOccurrencesForm(v AST.Var, form AST.Form, currentOcc occurrences, path occurrence) occurrences { +func getVariableOccurrencesForm(v AST.TypedVar, form AST.Form, currentOcc occurrences, path occurrence) occurrences { workingPath := make(occurrence, len(path)) copy(workingPath, path) switch f := form.(type) { @@ -127,40 +128,38 @@ func getVariableOccurrencesForm(v AST.Var, form AST.Form, currentOcc occurrences case AST.Not: currentOcc = getUnaryOcc(v, f.GetForm(), currentOcc, workingPath) case AST.And: - currentOcc = getNAryOcc(v, currentOcc, workingPath, f.FormList) + currentOcc = getNAryOcc(v, currentOcc, workingPath, f.GetChildFormulas()) case AST.Or: - currentOcc = getNAryOcc(v, currentOcc, workingPath, f.FormList) + currentOcc = getNAryOcc(v, currentOcc, workingPath, f.GetChildFormulas()) case AST.Imp: - currentOcc = getNAryOcc(v, currentOcc, workingPath, AST.NewFormList(f.GetF1(), f.GetF2())) + currentOcc = getNAryOcc(v, currentOcc, workingPath, Lib.MkListV(f.GetF1(), f.GetF2())) case AST.Equ: - currentOcc = getNAryOcc(v, currentOcc, workingPath, AST.NewFormList(f.GetF1(), f.GetF2())) + currentOcc = getNAryOcc(v, currentOcc, workingPath, Lib.MkListV(f.GetF1(), f.GetF2())) case AST.All: currentOcc = getUnaryOcc(v, f.GetForm(), currentOcc, workingPath) case AST.Ex: currentOcc = getUnaryOcc(v, f.GetForm(), currentOcc, workingPath) - case AST.AllType: - currentOcc = getUnaryOcc(v, f.GetForm(), currentOcc, workingPath) } return currentOcc } -func getUnaryOcc(v AST.Var, form AST.Form, currentOcc occurrences, path occurrence) occurrences { +func getUnaryOcc(v AST.TypedVar, form AST.Form, currentOcc occurrences, path occurrence) occurrences { return getVariableOccurrencesForm(v, form, currentOcc, append(path, 0)) } -func getNAryOcc(v AST.Var, currentOcc occurrences, path occurrence, fl *AST.FormList) occurrences { - for i, nf := range fl.Slice() { +func getNAryOcc(v AST.TypedVar, currentOcc occurrences, path occurrence, fl Lib.List[AST.Form]) occurrences { + for i, nf := range fl.GetSlice() { currentOcc = getVariableOccurrencesForm(v, nf, currentOcc, appcp(path, i)) } return currentOcc } -func getVariableOccurrencesTerm(v AST.Var, term AST.Term, currentOcc occurrences, path occurrence) occurrences { +func getVariableOccurrencesTerm(v AST.TypedVar, term AST.Term, currentOcc occurrences, path occurrence) occurrences { workingPath := make(occurrence, len(path)) copy(workingPath, path) switch t := term.(type) { case AST.Var: - if t.Equals(v) { + if t.Equals(v.ToBoundVar()) { currentOcc = append(currentOcc, workingPath) } case AST.Fun: @@ -197,19 +196,17 @@ func getTermAux(form AST.Form, occ occurrence) AST.Term { case AST.Not: term = getUnaryTerm(f.GetForm(), occ) case AST.And: - term = getNAryTerm(f.FormList, occ) + term = getNAryTerm(f.GetChildFormulas(), occ) case AST.Or: - term = getNAryTerm(f.FormList, occ) + term = getNAryTerm(f.GetChildFormulas(), occ) case AST.Imp: - term = getNAryTerm(AST.NewFormList(f.GetF1(), f.GetF2()), occ) + term = getNAryTerm(Lib.MkListV(f.GetF1(), f.GetF2()), occ) case AST.Equ: - term = getNAryTerm(AST.NewFormList(f.GetF1(), f.GetF2()), occ) + term = getNAryTerm(Lib.MkListV(f.GetF1(), f.GetF2()), occ) case AST.All: term = getUnaryTerm(f.GetForm(), occ) case AST.Ex: term = getUnaryTerm(f.GetForm(), occ) - case AST.AllType: - term = getUnaryTerm(f.GetForm(), occ) } return term } @@ -222,12 +219,12 @@ func getUnaryTerm(form AST.Form, occ occurrence) AST.Term { return getTermAux(form, occ[1:]) } -func getNAryTerm(fl *AST.FormList, occ occurrence) AST.Term { +func getNAryTerm(fl Lib.List[AST.Form], occ occurrence) AST.Term { if occ[0] >= fl.Len() { return nil } - return getTermAux(fl.Get(occ[0]), occ[1:]) + return getTermAux(fl.At(occ[0]), occ[1:]) } func getTerm(term AST.Term, occ occurrence) AST.Term { diff --git a/src/Mods/gs3/proof.go b/src/Mods/gs3/proof.go index 67f86f9f..feaee1e3 100644 --- a/src/Mods/gs3/proof.go +++ b/src/Mods/gs3/proof.go @@ -39,6 +39,7 @@ package gs3 import ( "strings" + "fmt" "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Core" "github.com/GoelandProver/Goeland/Glob" @@ -47,34 +48,34 @@ import ( "github.com/GoelandProver/Goeland/Search" ) -type dependencyMap []Glob.Pair[AST.Term, *AST.FormList] +type dependencyMap []Glob.Pair[AST.Term, Lib.List[AST.Form]] func (d dependencyMap) Copy() dependencyMap { - oth := make([]Glob.Pair[AST.Term, *AST.FormList], 0) + oth := make([]Glob.Pair[AST.Term, Lib.List[AST.Form]], 0) for _, v := range d { if v.Fst != nil { - p := Glob.MakePair(v.Fst.Copy(), AST.NewFormList(v.Snd.Slice()...)) + p := Glob.MakePair(v.Fst.Copy(), Lib.MkListV(v.Snd.GetSlice()...)) oth = append(oth, p) } } return oth } -func (d dependencyMap) Get(t AST.Term) (*AST.FormList, bool) { +func (d dependencyMap) Get(t AST.Term) (Lib.List[AST.Form], bool) { for _, v := range d { if v.Fst != nil && v.Fst.Equals(t) { return v.Snd, true } } - return AST.NewFormList(), false + return Lib.NewList[AST.Form](), false } func (d *dependencyMap) Add(t AST.Term, f ...AST.Form) { found := false - formList := AST.NewFormList(f...) + formList := Lib.MkListV(f...) for i, v := range *d { if v.Fst != nil && t != nil && v.Fst.Equals(t) { - formList.Append(v.Snd.Slice()...) + formList.Append(v.Snd.GetSlice()...) (*d)[i] = Glob.MakePair(t, formList) found = true } @@ -85,7 +86,7 @@ func (d *dependencyMap) Add(t AST.Term, f ...AST.Form) { } } -func (d *dependencyMap) Set(t AST.Term, fl *AST.FormList) { +func (d *dependencyMap) Set(t AST.Term, fl Lib.List[AST.Form]) { for i, v := range *d { if v.Fst != nil && v.Fst.Equals(t) { (*d)[i] = Glob.MakePair(t, fl) @@ -95,24 +96,30 @@ func (d *dependencyMap) Set(t AST.Term, fl *AST.FormList) { // Utilitary struct to build the proof. Keeps everything that's needed on a proofstep. type GS3Proof struct { - dependency dependencyMap // Dependency graph for formulas - branchForms *AST.FormList // The formulas generated at the current point in the proof. + dependency dependencyMap // Dependency graph for formulas + branchForms Lib.List[AST.Form] // The formulas generated at the current point in the proof. rulesApplied []Glob.Pair[Rule, Search.ProofStruct] lastNode *GS3Sequent betaHisto []Glob.Pair[int, int] deltaHisto []Glob.Pair[AST.Term, Glob.Pair[AST.Form, int]] } +var debug func(Lib.Lazy[string]) + +func InitDebugger() { + debug = Glob.CreateDebugger("GS3") +} + var MakeGS3Proof = func(proof []Search.ProofStruct) *GS3Sequent { gs3Proof := GS3Proof{ rulesApplied: make([]Glob.Pair[Rule, Search.ProofStruct], 0), betaHisto: make([]Glob.Pair[int, int], 0), deltaHisto: make([]Glob.Pair[AST.Term, Glob.Pair[AST.Form, int]], 0), - branchForms: AST.NewFormList(), - dependency: make([]Glob.Pair[AST.Term, *AST.FormList], 0), + branchForms: Lib.NewList[AST.Form](), + dependency: make([]Glob.Pair[AST.Term, Lib.List[AST.Form]], 0), } if Glob.IsLoaded("dmt") { - gs3Proof.branchForms.Append(dmt.GetRegisteredAxioms().Slice()...) + gs3Proof.branchForms.Append(dmt.GetRegisteredAxioms().GetSlice()...) gs3Proof.branchForms.Append(proof[0].Formula.GetForm()) } sequent := gs3Proof.makeProof(proof) @@ -122,7 +129,7 @@ var MakeGS3Proof = func(proof []Search.ProofStruct) *GS3Sequent { func (gs GS3Proof) Copy() GS3Proof { return GS3Proof{ dependency: gs.dependency.Copy(), - branchForms: AST.NewFormList(appcp(gs.branchForms.Slice())...), + branchForms: Lib.MkListV(appcp(gs.branchForms.GetSlice())...), lastNode: nil, rulesApplied: appcp(gs.rulesApplied), betaHisto: appcp(gs.betaHisto), @@ -142,7 +149,7 @@ func (gs GS3Proof) makeProof(proof []Search.ProofStruct) *GS3Sequent { return seq } subRoot := MakeNewSequent() - var resultFormulas []*AST.FormList + var resultFormulas []Lib.List[AST.Form] if gs.branchForms.Len() == 0 { gs.branchForms.Append(proof[0].Formula.GetForm()) } @@ -156,7 +163,7 @@ func (gs GS3Proof) makeProof(proof []Search.ProofStruct) *GS3Sequent { for i, child := range proof[len(proof)-1].GetChildren() { childProof := GS3Proof{ dependency: gs.dependency.Copy(), - branchForms: AST.NewFormList(appcp(gs.branchForms.Slice(), resultFormulas[i].Slice()...)...), + branchForms: Lib.MkListV(appcp(gs.branchForms.GetSlice(), resultFormulas[i].GetSlice()...)...), lastNode: nil, rulesApplied: appcp(gs.rulesApplied), betaHisto: appcp(gs.betaHisto, Glob.MakePair(i, proof[len(proof)-1].GetNodeId())), @@ -172,9 +179,8 @@ func (gs GS3Proof) makeProof(proof []Search.ProofStruct) *GS3Sequent { } // Returns a sequent and the result formulas. -func (gs *GS3Proof) makeProofOneStep(proofStep Search.ProofStruct, parent *GS3Sequent) []*AST.FormList { +func (gs *GS3Proof) makeProofOneStep(proofStep Search.ProofStruct, parent *GS3Sequent) []Lib.List[AST.Form] { seq := MakeNewSequent() - seq.setHypotheses(gs.branchForms) seq.nodeId = proofStep.Node_id rule := proofStructRuleToGS3Rule(proofStep.GetRuleName()) @@ -185,7 +191,7 @@ func (gs *GS3Proof) makeProofOneStep(proofStep Search.ProofStruct, parent *GS3Se // Immediate, just apply the rule. case NNOT, NOR, NIMP, AND, NAND, NEQU, OR, IMP, EQU, AX, REWRITE: seq.setAppliedRule(rule) - seq.setAppliedOn(form) + seq.SetTargetForm(form) if rule == REWRITE { seq.setRewrittenWith(proofStep.Id_dmt) } @@ -222,7 +228,7 @@ func (gs *GS3Proof) makeProofOneStep(proofStep Search.ProofStruct, parent *GS3Se // If the length is superior, then it's a branching rule and it needs to be taken care of in makeProof. if IsAlphaRule(rule) || IsGammaRule(rule) || IsDeltaRule(rule) || rule == REWRITE { - gs.branchForms.Append(forms[0].Slice()...) + gs.branchForms.Append(forms[0].GetSlice()...) // If rule is rewrite: do not weaken the base form, as it is important to get when applying rules back. // It may however induce bad weakenings. // TODO: fix the bad weakenings in the sequent. @@ -235,7 +241,7 @@ func (gs *GS3Proof) makeProofOneStep(proofStep Search.ProofStruct, parent *GS3Se func (gs *GS3Proof) manageGammaStep(proofStep Search.ProofStruct, rule Rule, seq *GS3Sequent) *GS3Sequent { // Manage gamma: add all the gammas except the result formula to the thing - resultForm := proofStep.GetResultFormulas()[0].GetForms().Get(0) + resultForm := proofStep.GetResultFormulas()[0].GetForms().At(0) originForm := proofStep.GetFormula().GetForm() // TODO: what happens if the result form doesn't care of what it's instantiated with? // JRO: Should be OKAY as "nil" is returned if I understand everything properly. @@ -247,9 +253,8 @@ func (gs *GS3Proof) manageGammaStep(proofStep Search.ProofStruct, rule Rule, seq // Create all the next sequents needed. s := MakeNewSequent() - s.setHypotheses(gs.branchForms) s.setAppliedRule(rule) - s.setAppliedOn(originForm) + s.SetTargetForm(originForm) s.setTermGenerated(term) if seq.IsEmpty() { @@ -282,7 +287,7 @@ func getDepFromTerm(term AST.Term) Lib.List[AST.Term] { // TODO: factorise this function to merge some steps that are similar between the two cases. func (gs *GS3Proof) manageDeltaStep(proofStep Search.ProofStruct, rule Rule, parent *GS3Sequent) AST.Form { originForm := proofStep.GetFormula().GetForm() - resultForm := proofStep.GetResultFormulas()[0].GetForms().Get(0) + resultForm := proofStep.GetResultFormulas()[0].GetForms().At(0) termGenerated := manageDeltasSkolemisations(proofStep.GetFormula().GetForm(), resultForm) if Glob.IsPreInnerSko() && !gs.termHasBeenIntroducedByBranch(termGenerated, proofStep.Node_id) { @@ -351,15 +356,15 @@ func (gs *GS3Proof) manageDeltaStep(proofStep Search.ProofStruct, rule Rule, par return resultForm } -func (gs *GS3Proof) postTreatment(proofStep Search.ProofStruct, rule Rule) []*AST.FormList { +func (gs *GS3Proof) postTreatment(proofStep Search.ProofStruct, rule Rule) []Lib.List[AST.Form] { // Add the rule applied & the formula it has been applied on. gs.rulesApplied = append(gs.rulesApplied, Glob.MakePair(rule, proofStep)) - var forms []*AST.FormList + var forms []Lib.List[AST.Form] for i, fs := range proofStep.GetResultFormulas() { forms = append(forms, fs.GetForms()) if (rule == NOR || rule == NIMP || rule == AND || rule == EQU) && forms[i].Len() == 1 { - forms[i].Append(forms[i].Get(0).Copy()) + forms[i].Append(forms[i].At(0).Copy()) } } @@ -376,21 +381,21 @@ func makeProofStructFrom(f, nf AST.Form, rule Rule) Search.ProofStruct { nf, Lib.NewList[AST.Term]()), ))} - proofStruct.Rule_name = ruleToTableauxString(rule) + proofStruct.Rule_name = rule.ToString() return proofStruct } -func (gs GS3Proof) getFormulasDependantFromTerm(term AST.Term) (*AST.FormList, bool) { +func (gs GS3Proof) getFormulasDependantFromTerm(term AST.Term) (Lib.List[AST.Form], bool) { fs, ok := gs.dependency.Get(term) return fs, ok } -func (gs GS3Proof) getRulesAppliedInOrder(term AST.Term, dependantForms *AST.FormList, deltaForm AST.Form) ([]Glob.Pair[Rule, Search.ProofStruct], *AST.FormList) { +func (gs GS3Proof) getRulesAppliedInOrder(term AST.Term, dependantForms Lib.List[AST.Form], deltaForm AST.Form) ([]Glob.Pair[Rule, Search.ProofStruct], Lib.List[AST.Form]) { offsprings := gs.getOffspringsOf(term) rules := []Glob.Pair[Rule, Search.ProofStruct]{} for _, rule := range gs.rulesApplied { f := rule.Snd.GetFormula().GetForm() - if !f.Equals(deltaForm) && (offsprings.Contains(f) || dependantForms.Contains(f)) { + if !f.Equals(deltaForm) && (Lib.ListMem(f, offsprings) || Lib.ListMem(f, dependantForms)) { rules = append(rules, rule) } } @@ -398,9 +403,9 @@ func (gs GS3Proof) getRulesAppliedInOrder(term AST.Term, dependantForms *AST.For return rules, offsprings } -func (gs GS3Proof) getOffspringsOf(term AST.Term) *AST.FormList { - offsprings := AST.NewFormList() - for _, form := range gs.branchForms.Slice() { +func (gs GS3Proof) getOffspringsOf(term AST.Term) Lib.List[AST.Form] { + offsprings := Lib.NewList[AST.Form]() + for _, form := range gs.branchForms.GetSlice() { if form.GetSubTerms().Contains(term, AST.TermEquals) { offsprings.Append(form) } @@ -408,8 +413,8 @@ func (gs GS3Proof) getOffspringsOf(term AST.Term) *AST.FormList { return offsprings } -func (gs *GS3Proof) weakenForms(forms *AST.FormList, parent *GS3Sequent) *GS3Sequent { - for i, form := range forms.Slice() { +func (gs *GS3Proof) weakenForms(forms Lib.List[AST.Form], parent *GS3Sequent) *GS3Sequent { + for i, form := range forms.GetSlice() { newSeq := gs.weakenForm(form) if newSeq != nil { if i == 0 && parent.IsEmpty() { @@ -426,9 +431,8 @@ func (gs *GS3Proof) weakenForms(forms *AST.FormList, parent *GS3Sequent) *GS3Seq func (gs *GS3Proof) weakenForm(form AST.Form) *GS3Sequent { seq := MakeNewSequent() - seq.setHypotheses(gs.branchForms) seq.setAppliedRule(W) - seq.setAppliedOn(form) + seq.SetTargetForm(form) gs.removeHypothesis(form) gs.removeDependency(form) @@ -441,7 +445,6 @@ func (gs *GS3Proof) weakenForm(form AST.Form) *GS3Sequent { func (gs *GS3Proof) weakenTerm(term AST.Term) *GS3Sequent { seq := MakeNewSequent() - seq.setHypotheses(gs.branchForms) seq.setAppliedRule(W) seq.setTermGenerated(term) @@ -456,19 +459,24 @@ func (gs *GS3Proof) weakenTerm(term AST.Term) *GS3Sequent { } func (gs *GS3Proof) removeHypothesis(form AST.Form) { - index, _ := gs.branchForms.GetIndexOf(form) - gs.branchForms.Remove(index) + index := Lib.ListIndexOf(form, gs.branchForms) + switch i := index.(type) { + case Lib.Some[int]: + gs.branchForms = gs.branchForms.RemoveAt(i.Val) + case Lib.None[int]: + Glob.PrintWarn("gs3", fmt.Sprintf("Hypothesis %s not found", form.ToString())) + } } func (gs *GS3Proof) removeDependency(form AST.Form) { for _, v := range gs.dependency { if v.Fst != nil { ls, _ := gs.dependency.Get(v.Fst) - removed := ls.Copy() + removed := Lib.ListCpy(ls) nb_rm := 0 - for i, f := range v.Snd.Slice() { + for i, f := range v.Snd.GetSlice() { if f.Equals(form) { - removed.Remove(i - nb_rm) + removed.RemoveAt(i - nb_rm) nb_rm++ } } @@ -488,11 +496,10 @@ func (gs *GS3Proof) removeRuleAppliedOn(form AST.Form) { func (gs *GS3Proof) applyDeltaRule(form, result AST.Form, rule Rule, term AST.Term, nodeId int) *GS3Sequent { seq := MakeNewSequent() - seq.setHypotheses(gs.branchForms) seq.setAppliedRule(rule) - seq.setAppliedOn(form) + seq.SetTargetForm(form) seq.setTermGenerated(term) - seq.setFormsGenerated([]*AST.FormList{AST.NewFormList(result)}) + seq.setFormsGenerated([]Lib.List[AST.Form]{Lib.MkListV(result)}) gs.branchForms.Append(result) gs.deltaHisto = append(gs.deltaHisto, Glob.MakePair(term, Glob.MakePair(result, nodeId))) @@ -503,7 +510,7 @@ func (gs *GS3Proof) applyDeltaRule(form, result AST.Form, rule Rule, term AST.Te return seq } -func (gs GS3Proof) applyRulesBack(rulesApplied, rulesToApply []Glob.Pair[Rule, Search.ProofStruct], weakenedForms *AST.FormList) (*GS3Sequent, []int) { +func (gs GS3Proof) applyRulesBack(rulesApplied, rulesToApply []Glob.Pair[Rule, Search.ProofStruct], weakenedForms Lib.List[AST.Form]) (*GS3Sequent, []int) { // Transform everything back to a proof struct & call makeProof on it. // We need to have the right proofstructs here: the proofstructs of the branches that is not this one // on the beta formulas. @@ -514,7 +521,7 @@ func (gs GS3Proof) applyRulesBack(rulesApplied, rulesToApply []Glob.Pair[Rule, S return gs.makeProof(proof), childrenIndex } -func (gs *GS3Proof) rebuildProof(rulesApplied, rules []Glob.Pair[Rule, Search.ProofStruct], weakenedForms *AST.FormList) ([]Search.ProofStruct, []int) { +func (gs *GS3Proof) rebuildProof(rulesApplied, rules []Glob.Pair[Rule, Search.ProofStruct], weakenedForms Lib.List[AST.Form]) ([]Search.ProofStruct, []int) { rebuiltProof := make([]Search.ProofStruct, 0) childrenIndex := make([]int, 0) for i, rule := range rules { @@ -557,8 +564,8 @@ func (gs GS3Proof) getCurrentBranchChildId(id int) int { return -1 } -func (gs GS3Proof) getFormsToWeaken(rulesApplied, rulesAlreadyWeakened []Glob.Pair[Rule, Search.ProofStruct]) *AST.FormList { - formsToWeaken := AST.NewFormList() +func (gs GS3Proof) getFormsToWeaken(rulesApplied, rulesAlreadyWeakened []Glob.Pair[Rule, Search.ProofStruct]) Lib.List[AST.Form] { + formsToWeaken := Lib.NewList[AST.Form]() rule := getFirstRuleAppliedAfter(gs.rulesApplied, rulesAlreadyWeakened[0]) canBeAppending := false for _, r := range gs.rulesApplied { @@ -567,7 +574,8 @@ func (gs GS3Proof) getFormsToWeaken(rulesApplied, rulesAlreadyWeakened []Glob.Pa } if canBeAppending { if !Glob.IsPreInnerSko() || !(rule.Fst == EX || rule.Fst == NALL) { - formsToWeaken.Append(gs.getIntersectionBetweenResultAndBranchForms(rule.Snd.GetResultFormulas()).Slice()...) + formsToWeaken.Append( + gs.getIntersectionBetweenResultAndBranchForms(rule.Snd.GetResultFormulas()).GetSlice()...) } } } @@ -583,11 +591,11 @@ func getFirstRuleAppliedAfter(rulesApplied []Glob.Pair[Rule, Search.ProofStruct] return Glob.Pair[Rule, Search.ProofStruct]{} } -func (gs GS3Proof) getIntersectionBetweenResultAndBranchForms(forms []Search.IntFormAndTermsList) *AST.FormList { - fs := AST.NewFormList() +func (gs GS3Proof) getIntersectionBetweenResultAndBranchForms(forms []Search.IntFormAndTermsList) Lib.List[AST.Form] { + fs := Lib.NewList[AST.Form]() for _, fl := range forms { - for _, f := range fl.GetForms().Slice() { - if gs.branchForms.Contains(f) { + for _, f := range fl.GetForms().GetSlice() { + if Lib.ListMem(f, gs.branchForms) { fs.Append(f) } } @@ -599,9 +607,9 @@ func equalRulePair(a, b Glob.Pair[Rule, Search.ProofStruct]) bool { return a.Fst == b.Fst && a.Snd.Formula.GetForm().Equals(b.Snd.Formula.GetForm()) } -func makeWeakeningProofStructs(forms *AST.FormList) []Search.ProofStruct { +func makeWeakeningProofStructs(forms Lib.List[AST.Form]) []Search.ProofStruct { resultingProof := make([]Search.ProofStruct, 0) - for _, f := range forms.Slice() { + for _, f := range forms.GetSlice() { proofStruct := Search.MakeEmptyProofStruct() proofStruct.SetFormulaProof(Core.MakeFormAndTerm( f, @@ -642,23 +650,23 @@ func (gs GS3Proof) findInBetaHist(id int) int { return -1 } -func getAllFormulasDependantOn(term AST.Term, form AST.Form) *AST.FormList { +func getAllFormulasDependantOn(term AST.Term, form AST.Form) Lib.List[AST.Form] { switch f := form.(type) { case AST.All: - return getSubformulas(term, f.GetVarList()[0], f.GetForm()) + return getSubformulas(term, f.GetVarList().At(0), f.GetForm()) case AST.Not: if ex, isEx := f.GetForm().(AST.Ex); isEx { - return getSubformulas(term, ex.GetVarList()[0], AST.MakerNot(f.GetForm())) + return getSubformulas(term, ex.GetVarList().At(0), AST.MakerNot(f.GetForm())) } } - return AST.NewFormList() + return Lib.NewList[AST.Form]() } -func getSubformulas(term AST.Term, v AST.Var, form AST.Form) *AST.FormList { +func getSubformulas(term AST.Term, v AST.TypedVar, form AST.Form) Lib.List[AST.Form] { subforms := form.GetSubFormulasRecur() - dependantSubforms := AST.NewFormList() - for _, f := range subforms.Slice() { - f, res := f.ReplaceTermByTerm(v, term) + dependantSubforms := Lib.NewList[AST.Form]() + for _, f := range subforms.GetSlice() { + f, res := f.ReplaceTermByTerm(v.ToBoundVar(), term) if res { dependantSubforms.Append(f) } @@ -666,10 +674,10 @@ func getSubformulas(term AST.Term, v AST.Var, form AST.Form) *AST.FormList { return dependantSubforms } -func (gs GS3Proof) findInDeltaHisto(term AST.Term, forms *AST.FormList) (*AST.FormList, bool) { +func (gs GS3Proof) findInDeltaHisto(term AST.Term, forms Lib.List[AST.Form]) (Lib.List[AST.Form], bool) { for _, p := range gs.deltaHisto { if p.Fst != nil && p.Fst.Equals(term) { - result := forms.Copy() + result := Lib.ListCpy(forms) result.Append(p.Snd.Fst) return result, true } @@ -685,10 +693,10 @@ func (gs *GS3Proof) removeFromDeltaHisto(term AST.Term) { } } -func (gs *GS3Proof) weakenAllFormsRelatedToTheTerm(term AST.Term) (*AST.FormList, []Glob.Pair[Rule, Search.ProofStruct]) { +func (gs *GS3Proof) weakenAllFormsRelatedToTheTerm(term AST.Term) (Lib.List[AST.Form], []Glob.Pair[Rule, Search.ProofStruct]) { rules := []Glob.Pair[Rule, Search.ProofStruct]{} - forms := AST.NewFormList() - for _, form := range gs.branchForms.Slice() { + forms := Lib.NewList[AST.Form]() + for _, form := range gs.branchForms.GetSlice() { if form.GetSubTerms().Contains(term, AST.TermEquals) { // Get the rule to apply it back for _, rule := range gs.rulesApplied { diff --git a/src/Mods/gs3/sequent.go b/src/Mods/gs3/sequent.go index 647f0047..36b6125b 100644 --- a/src/Mods/gs3/sequent.go +++ b/src/Mods/gs3/sequent.go @@ -36,15 +36,16 @@ import ( "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Mods/dmt" ) type GS3Sequent struct { - hypotheses *AST.FormList rule Rule - appliedOn int - rewriteWith int + appliedOn AST.Form + rewriteWith AST.Form termGenerated AST.Term - formsGenerated []*AST.FormList + formsGenerated []Lib.List[AST.Form] children []*GS3Sequent proof GS3Proof nodeId int @@ -76,7 +77,6 @@ const ( func MakeNewSequent() *GS3Sequent { seq := new(GS3Sequent) - seq.hypotheses = AST.NewFormList() seq.children = make([]*GS3Sequent, 0) return seq } @@ -102,7 +102,7 @@ func IsAlphaRule(rule Rule) bool { // ---------------------------------------------------------------------------- func (seq *GS3Sequent) GetTargetForm() AST.Form { - return seq.hypotheses.Get(seq.appliedOn) + return seq.appliedOn } func (seq *GS3Sequent) Child(i int) *GS3Sequent { @@ -117,12 +117,12 @@ func (seq *GS3Sequent) Rule() Rule { return seq.rule } -func (seq *GS3Sequent) GetResultFormulasOfChild(i int) *AST.FormList { +func (seq *GS3Sequent) GetResultFormulasOfChild(i int) Lib.List[AST.Form] { return seq.formsGenerated[i] } -func (seq *GS3Sequent) GetResultFormulasOfChildren() []*AST.FormList { - result := []*AST.FormList{} +func (seq *GS3Sequent) GetResultFormulasOfChildren() []Lib.List[AST.Form] { + result := []Lib.List[AST.Form]{} for i := range seq.children { result = append(result, seq.formsGenerated[i]) @@ -136,7 +136,7 @@ func (seq *GS3Sequent) TermGenerated() AST.Term { } func (seq *GS3Sequent) IsEmpty() bool { - return seq.hypotheses.IsEmpty() + return seq.appliedOn == nil } func (seq *GS3Sequent) ToString() string { @@ -144,7 +144,7 @@ func (seq *GS3Sequent) ToString() string { } func (seq *GS3Sequent) GetRewriteWith() AST.Form { - return seq.hypotheses.Get(seq.rewriteWith) + return seq.rewriteWith } func (seq *GS3Sequent) GetId() int { @@ -155,7 +155,7 @@ func (seq *GS3Sequent) SetId(i int) { seq.nodeId = i } -func (seq *GS3Sequent) SetFormGenerated(fg []*AST.FormList) { +func (seq *GS3Sequent) SetFormGenerated(fg []Lib.List[AST.Form]) { seq.formsGenerated = fg } @@ -164,7 +164,7 @@ func (seq *GS3Sequent) SetChildren(c []*GS3Sequent) { } func (seq *GS3Sequent) SetTargetForm(f AST.Form) { - seq.hypotheses.Set(seq.appliedOn, f) + seq.appliedOn = f } func (seq *GS3Sequent) SetTermGenerated(t AST.Term) { @@ -175,35 +175,10 @@ func (seq *GS3Sequent) SetTermGenerated(t AST.Term) { // Private methods & functions // ---------------------------------------------------------------------------- -func (seq *GS3Sequent) setHypotheses(forms *AST.FormList) { - seq.hypotheses = forms.Copy() - // If equality reasoning has been used to terminate the proof, then an empty predicate is expected - // (see search_destructive, manageClosureRule on eq reasoning). - // As such, add an hypothesis with the empty = - seq.hypotheses.Append(AST.EmptyPredEq) -} - func (seq *GS3Sequent) setAppliedRule(rule Rule) { seq.rule = rule } -func (seq *GS3Sequent) setAppliedOn(hypothesis AST.Form) { - index := -1 - for i, h := range seq.hypotheses.Slice() { - if hypothesis.Equals(h) { - index = i - break - } - } - - if index == -1 { - Glob.PrintInfo("APPLIED ON", hypothesis.ToString()) - Glob.Anomaly("GS3", "Failure: tried to apply a missing hypothesis") - } - - seq.appliedOn = index -} - func (seq *GS3Sequent) setTermGenerated(t AST.Term) { seq.termGenerated = t } @@ -214,7 +189,7 @@ func (seq *GS3Sequent) addChild(oth ...*GS3Sequent) { func (seq *GS3Sequent) toStringAux(i int) string { identation := strings.Repeat(" ", i) - status := seq.ruleToString(seq.rule) + " on " + seq.hypotheses.Get(seq.appliedOn).ToString() + status := seq.ruleToString(seq.rule) + " on " + seq.appliedOn.ToString() if seq.IsEmpty() { status = "EMPTY" } @@ -248,7 +223,7 @@ func (seq *GS3Sequent) ruleToString(rule Rule) string { return mapping[rule] } -func (seq *GS3Sequent) setFormsGenerated(forms []*AST.FormList) { +func (seq *GS3Sequent) setFormsGenerated(forms []Lib.List[AST.Form]) { seq.formsGenerated = forms } @@ -274,7 +249,8 @@ func proofStructRuleToGS3Rule(rule string) Rule { } return mapping[rule] } -func ruleToTableauxString(rule Rule) string { + +func (rule Rule) ToString() string { mapping := map[Rule]string{ NNOT: "ALPHA_NOT_NOT", NOR: "ALPHA_NOT_OR", @@ -297,19 +273,20 @@ func ruleToTableauxString(rule Rule) string { } func (seq *GS3Sequent) setRewrittenWith(rewriteId int) { - for i, h := range seq.hypotheses.Slice() { + axioms := dmt.GetRegisteredAxioms() + for _, h := range axioms.GetSlice() { endForm := h for Glob.Is[AST.All](endForm) { endForm = endForm.(AST.All).GetForm() } endForm = getAtomic(endForm) if endForm.GetIndex() == rewriteId { - seq.rewriteWith = i + seq.rewriteWith = h return } } - panic("Failure: tried to rewrite using a missing hypothesis") + panic("Failure: tried to rewrite using a missing axiom") } func getAtomic(f AST.Form) AST.Form { diff --git a/src/Mods/lambdapi/context.go b/src/Mods/lambdapi/context.go index e9496c46..25b5c368 100644 --- a/src/Mods/lambdapi/context.go +++ b/src/Mods/lambdapi/context.go @@ -33,11 +33,11 @@ package lambdapi import ( "fmt" - "strings" "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Mods/CertifUtils" "github.com/GoelandProver/Goeland/Mods/dmt" ) @@ -50,254 +50,35 @@ func makeContextIfNeeded(root AST.Form, metaList Lib.List[AST.Meta]) string { root = AST.MakerAnd(registeredAxioms) } - if AST.EmptyGlobalContext() { - resultString += strings.Join(getContextFromFormula(root), "\n") + "\n" - - if metaList.Len() > 0 { - resultString += contextualizeMetas(metaList) - } - } else { - resultString += getContextAsString(root) - - if metaList.Len() > 0 { - resultString += contextualizeMetas(metaList) - } - } - return resultString -} - -func getContextAsString(root AST.Form) string { - types, arrows, others := GlobContextPairs() - ids := getIdsFromFormula(root) - - final := types - - for _, arrow := range arrows { - for _, id := range ids { - if id.Fst == arrow.Fst { - found := false - for _, fin := range final { - if fin.Fst == id.Snd { - found = true - } - } - - if !found { - final = append(final, Glob.MakePair(id.Snd, arrow.Snd)) - } - } - } - } - - for _, other := range others { - for _, id := range ids { - if id.Fst == other.Fst { - found := false - for _, fin := range final { - if fin.Fst == id.Snd { - found = true - } - } - - if !found { - final = append(final, Glob.MakePair(id.Snd, other.Snd)) - } - } - } + // if AST.EmptyGlobalContext() { + contextual_symbols := CertifUtils.GetContextFromFormula(root) + for _, p := range contextual_symbols.GetSlice() { + addToGlobalEnv(Lib.MkPair(p.Fst.ToString(), p.Snd)) + resultString += fmt.Sprintf("symbol %s : %s;\n", p.Fst.ToString(), p.Snd.ToString()) } - result := "" - - for _, fin := range final { - result += "symbol " + fin.Fst + " : " + mapDefault(fin.Snd) + ";\n" - } - - return result -} - -func GlobContextPairs() (types, arrows, others []Glob.Pair[string, string]) { - context := AST.GetGlobalContext() - for k, v := range context { - if k != "=" && k[0] != '$' { - switch typed := v[0].App.(type) { - case AST.TypeArrow: - primitives := typed.GetPrimitives() - typesStr := "" - - for i, prim := range primitives { - if i != len(primitives)-1 { - typesStr += "τ (" + prim.ToString() + ") → " - } else { - typesStr += prim.ToString() - } - } - arrows = append(arrows, Glob.MakePair(k, typesStr)) - case AST.QuantifiedType: - primitives := typed.GetPrimitives() - typesStr := "" - contextualized := []string{} - - for i, prim := range primitives { - if i != len(primitives)-1 { - switch typedPrim := prim.(type) { - case AST.TypeVar: - str := AST.SimpleStringMappable(typedPrim.ToString()) - symbol := addToContext(&str) - typesStr += "τ (" + symbol + ") → " - contextualized = append(contextualized, symbol) - case AST.TypeHint: - typesStr += "τ (" + prim.ToString() + ") → " - } - } else { - typesStr += prim.ToString() - } - } - arrows = append(arrows, Glob.MakePair(k, fmt.Sprintf("Π (%s : Type), %s", strings.Join(contextualized, " : Type), ("), typesStr))) - case AST.TypeHint: - if k == typed.ToString() { - types = append(types, Glob.MakePair(k, "Type")) - } else { - others = append(others, Glob.MakePair(k, fmt.Sprintf("τ (%s)", typed.ToString()))) - } - } - } + if metaList.Len() > 0 { + resultString += contextualizeMetas(metaList) } + // } else { + // resultString += getContextAsString(root) - return types, arrows, others + // if metaList.Len() > 0 { + // resultString += contextualizeMetas(metaList) + // } + // } + return resultString } func contextPreamble() string { return "require open Logic.Goeland.FOL Logic.Goeland.LL Logic.Goeland.ND Logic.Goeland.ND_eps Logic.Goeland.ND_eps_full Logic.Goeland.ND_eps_aux Logic.Goeland.LL_ND Logic.Goeland.GS3;" } -func getContextFromFormula(root AST.Form) []string { - result := []string{} - - switch nf := root.(type) { - case AST.All: - result = getContextFromFormula(nf.GetForm()) - case AST.Ex: - result = getContextFromFormula(nf.GetForm()) - case AST.AllType: - result = getContextFromFormula(nf.GetForm()) - case AST.And: - for _, f := range nf.FormList.Slice() { - result = append(result, clean(result, getContextFromFormula(f))...) - } - case AST.Or: - for _, f := range nf.FormList.Slice() { - result = append(result, clean(result, getContextFromFormula(f))...) - } - case AST.Imp: - result = clean(result, getContextFromFormula(nf.GetF1())) - result = append(result, clean(result, getContextFromFormula(nf.GetF2()))...) - case AST.Equ: - result = clean(result, getContextFromFormula(nf.GetF1())) - result = append(result, clean(result, getContextFromFormula(nf.GetF2()))...) - case AST.Not: - result = append(result, getContextFromFormula(nf.GetForm())...) - case AST.Pred: - if !nf.GetID().Equals(AST.Id_eq) { - primitives := nf.GetType().GetPrimitives() - typesStr := "" - - for i, prim := range primitives { - if i != len(primitives)-1 { - typesStr += "τ (" + prim.ToString() + ") → " - } else { - typesStr += prim.ToString() - } - } - - result = append(result, mapDefault(fmt.Sprintf("symbol %s : %s;", nf.GetID().ToMappedString(lambdaPiMapConnectors, false), typesStr))) - } - for _, term := range nf.GetArgs().GetSlice() { - result = append(result, clean(result, getContextFromTerm(term))...) - } - } - return result -} - -func getIdsFromFormula(root AST.Form) []Glob.Pair[string, string] { - result := []Glob.Pair[string, string]{} - - switch nf := root.(type) { - case AST.All: - result = getIdsFromFormula(nf.GetForm()) - case AST.Ex: - result = getIdsFromFormula(nf.GetForm()) - case AST.AllType: - result = getIdsFromFormula(nf.GetForm()) - case AST.And: - for _, f := range nf.FormList.Slice() { - result = append(result, getIdsFromFormula(f)...) - } - case AST.Or: - for _, f := range nf.FormList.Slice() { - result = append(result, getIdsFromFormula(f)...) - } - case AST.Imp: - result = getIdsFromFormula(nf.GetF1()) - result = append(result, getIdsFromFormula(nf.GetF2())...) - case AST.Equ: - result = getIdsFromFormula(nf.GetF1()) - result = append(result, getIdsFromFormula(nf.GetF2())...) - case AST.Not: - result = getIdsFromFormula(nf.GetForm()) - case AST.Pred: - result = append(result, Glob.MakePair(nf.GetID().GetName(), nf.GetID().ToMappedString(lambdaPiMapConnectors, false))) - for _, f := range nf.GetArgs().GetSlice() { - result = append(result, Glob.MakePair(f.GetName(), f.ToMappedString(lambdaPiMapConnectors, false))) - } - } - return result -} - -func getContextFromTerm(trm AST.Term) []string { - result := []string{} - - if fun, isFun := trm.(AST.Fun); isFun { - - primitives := fun.GetTypeHint().GetPrimitives() - typesStr := "" - for i, prim := range primitives { - if i != len(primitives)-1 { - typesStr += "τ (" + prim.ToString() + ") → " - } else { - typesStr += "τ (" + prim.ToString() + ")" - } - } - - result = append(result, mapDefault(fmt.Sprintf("symbol %s : %s;", fun.GetID().ToMappedString(lambdaPiMapConnectors, false), typesStr))) - for _, term := range fun.GetArgs().GetSlice() { - result = append(result, clean(result, getContextFromTerm(term))...) - } - } - return result -} - -// Returns everything in add not in set -func clean(set, add []string) []string { - result := []string{} - for _, str := range add { - found := false - for _, s := range set { - if s == str { - found = true - break - } - } - if !found { - result = append(result, str) - } - } - return result -} - func contextualizeMetas(metaList Lib.List[AST.Meta]) string { - result := []string{} + result := "" for _, meta := range metaList.GetSlice() { - result = append(result, meta.ToMappedString(lambdaPiMapConnectors, false)) + addToGlobalEnv(Lib.MkPair(meta.ToString(), meta.GetTy())) + result += fmt.Sprintf("symbol %s : %s;\n", meta.ToString(), meta.GetTy().ToString()) } - return "symbol " + strings.Join(result, " ") + " : τ (ι);" + return result } diff --git a/src/Mods/lambdapi/formDecorator.go b/src/Mods/lambdapi/formDecorator.go index 9838a873..e7847d3a 100644 --- a/src/Mods/lambdapi/formDecorator.go +++ b/src/Mods/lambdapi/formDecorator.go @@ -32,136 +32,137 @@ package lambdapi import ( - "fmt" + _ "fmt" - "github.com/GoelandProver/Goeland/AST" + _ "github.com/GoelandProver/Goeland/AST" + _ "github.com/GoelandProver/Goeland/Lib" ) -type DecoratedAll struct { - AST.All -} - -func MakeDecoratedAll(all AST.All) DecoratedAll { - if typed, ok := all.Copy().(AST.All); ok { - all = typed - } - decorated := DecoratedAll{all} - decorated.MappedString.MappableString = decorated - return decorated -} - -func (da DecoratedAll) ToMappedStringSurround(mapping AST.MapString, displayTypes bool) string { - return QuantifierToMappedString(mapping[AST.AllQuant], da.GetVarList()) -} - -func QuantifierToMappedString(quant string, varList []AST.Var) string { - if len(varList) == 0 { - return "%s" - } else { - result := "(" + quant + " (" + toLambdaIntroString(varList[0], varList[0].GetTypeHint().ToString()) + ", %s))" - result = fmt.Sprintf(result, QuantifierToMappedString(quant, varList[1:])) - return result - } -} - -type DecoratedEx struct { - AST.Ex -} - -func MakeDecoratedEx(ex AST.Ex) DecoratedEx { - if typed, ok := ex.Copy().(AST.Ex); ok { - ex = typed - } - decorated := DecoratedEx{ex} - decorated.MappedString.MappableString = decorated - return decorated -} - -func (de DecoratedEx) ToMappedStringSurround(mapping AST.MapString, displayTypes bool) string { - return QuantifierToMappedString(mapping[AST.ExQuant], de.GetVarList()) -} - -type DecoratedVar struct { - AST.Var -} - -func MakeDecoratedVar(newVar AST.Var) DecoratedVar { - if typed, ok := newVar.Copy().(AST.Var); ok { - newVar = typed - } - decorated := DecoratedVar{newVar} - decorated.MappedString.MappableString = decorated - return decorated -} - -func (da DecoratedVar) ToMappedStringChild(mapping AST.MapString, displayTypes bool) (separator, emptyValue string) { - emptyValue = getFromContext(da.Var) - return "", emptyValue -} - -type DecoratedPred struct { - AST.Pred -} - -func MakeDecoratedPred(newPred AST.Pred) DecoratedPred { - if typed, ok := newPred.Copy().(AST.Pred); ok { - newPred = typed - } - decorated := DecoratedPred{newPred} - decorated.MappedString.MappableString = decorated - return decorated -} - -func (dp DecoratedPred) ToMappedStringChild(mapping AST.MapString, displayTypes bool) (separator, emptyValue string) { - _, emptyValue = dp.Pred.ToMappedStringChild(mapping, displayTypes) - return " ", emptyValue -} - -type DecoratedFun struct { - AST.Fun -} - -func MakeDecoratedFun(newFun AST.Fun) DecoratedFun { - if typed, ok := newFun.Copy().(AST.Fun); ok { - newFun = typed - } - decorated := DecoratedFun{newFun} - decorated.MappedString.MappableString = decorated - return decorated -} - -func (df DecoratedFun) ToMappedStringChild(mapping AST.MapString, displayTypes bool) (separator, emptyValue string) { - return " ", mapping[AST.PredEmpty] -} - -func (df DecoratedFun) ToMappedStringSurround(mapping AST.MapString, displayTypes bool) string { - result := df.Fun.ToMappedStringSurround(mapping, displayTypes) - - possible, exists := context.GetExists(df.Fun) - if exists { - if result[:6] == "skolem" { - result = string(possible) + "%s" - } else { - result = df.Fun.ToMappedStringSurroundWithId(string(possible), mapping, displayTypes) - } - } - - return result -} - -func decorateForm(form AST.MappableString) AST.MappableString { - switch typed := form.(type) { - case AST.All: - return MakeDecoratedAll(typed) - case AST.Ex: - return MakeDecoratedEx(typed) - case AST.Var: - return MakeDecoratedVar(typed) - case AST.Pred: - return MakeDecoratedPred(typed) - case AST.Fun: - return MakeDecoratedFun(typed) - default: - return typed - } -} +// type DecoratedAll struct { +// AST.All +// } + +// func MakeDecoratedAll(all AST.All) DecoratedAll { +// if typed, ok := all.Copy().(AST.All); ok { +// all = typed +// } +// decorated := DecoratedAll{all} +// decorated.MappedString.MappableString = decorated +// return decorated +// } + +// func (da DecoratedAll) ToMappedStringSurround(mapping AST.MapString, displayTypes bool) string { +// return QuantifierToMappedString(mapping[AST.AllQuant], da.GetVarList()) +// } + +// func QuantifierToMappedString(quant string, varList Lib.List[AST.TypedVar]) string { +// if varList.Len() == 0 { +// return "%s" +// } else { +// result := "(" + quant + " (" + toLambdaIntroString(varList.At(0), "") + ", %s))" +// result = fmt.Sprintf(result, QuantifierToMappedString(quant, varList.Slice(1, varList.Len()))) +// return result +// } +// } + +// type DecoratedEx struct { +// AST.Ex +// } + +// func MakeDecoratedEx(ex AST.Ex) DecoratedEx { +// if typed, ok := ex.Copy().(AST.Ex); ok { +// ex = typed +// } +// decorated := DecoratedEx{ex} +// decorated.MappedString.MappableString = decorated +// return decorated +// } + +// func (de DecoratedEx) ToMappedStringSurround(mapping AST.MapString, displayTypes bool) string { +// return QuantifierToMappedString(mapping[AST.ExQuant], de.GetVarList()) +// } + +// type DecoratedVar struct { +// AST.Var +// } + +// func MakeDecoratedVar(newVar AST.Var) DecoratedVar { +// if typed, ok := newVar.Copy().(AST.Var); ok { +// newVar = typed +// } +// decorated := DecoratedVar{newVar} +// decorated.MappedString.MappableString = decorated +// return decorated +// } + +// func (da DecoratedVar) ToMappedStringChild(mapping AST.MapString, displayTypes bool) (separator, emptyValue string) { +// emptyValue = getFromContext(da.Var) +// return "", emptyValue +// } + +// type DecoratedPred struct { +// AST.Pred +// } + +// func MakeDecoratedPred(newPred AST.Pred) DecoratedPred { +// if typed, ok := newPred.Copy().(AST.Pred); ok { +// newPred = typed +// } +// decorated := DecoratedPred{newPred} +// decorated.MappedString.MappableString = decorated +// return decorated +// } + +// func (dp DecoratedPred) ToMappedStringChild(mapping AST.MapString, displayTypes bool) (separator, emptyValue string) { +// _, emptyValue = dp.Pred.ToMappedStringChild(mapping, displayTypes) +// return " ", emptyValue +// } + +// type DecoratedFun struct { +// AST.Fun +// } + +// func MakeDecoratedFun(newFun AST.Fun) DecoratedFun { +// if typed, ok := newFun.Copy().(AST.Fun); ok { +// newFun = typed +// } +// decorated := DecoratedFun{newFun} +// decorated.MappedString.MappableString = decorated +// return decorated +// } + +// func (df DecoratedFun) ToMappedStringChild(mapping AST.MapString, displayTypes bool) (separator, emptyValue string) { +// return " ", mapping[AST.PredEmpty] +// } + +// func (df DecoratedFun) ToMappedStringSurround(mapping AST.MapString, displayTypes bool) string { +// result := df.Fun.ToMappedStringSurround(mapping, displayTypes) + +// possible, exists := context.GetExists(df.Fun) +// if exists { +// if result[:6] == "skolem" { +// result = string(possible) + "%s" +// } else { +// result = df.Fun.ToMappedStringSurroundWithId(string(possible), mapping, displayTypes) +// } +// } + +// return result +// } + +// func decorateForm(form AST.MappableString) AST.MappableString { +// switch typed := form.(type) { +// case AST.All: +// return MakeDecoratedAll(typed) +// case AST.Ex: +// return MakeDecoratedEx(typed) +// case AST.Var: +// return MakeDecoratedVar(typed) +// case AST.Pred: +// return MakeDecoratedPred(typed) +// case AST.Fun: +// return MakeDecoratedFun(typed) +// default: +// return typed +// } +// } diff --git a/src/AST/formula_list.go b/src/Mods/lambdapi/local_context.go similarity index 53% rename from src/AST/formula_list.go rename to src/Mods/lambdapi/local_context.go index e0762008..a6edc97b 100644 --- a/src/AST/formula_list.go +++ b/src/Mods/lambdapi/local_context.go @@ -29,85 +29,56 @@ * The fact that you are presently reading this means that you have had * knowledge of the CeCILL license and that you accept its terms. **/ - -/** -* This file contains functions and types which describe the fomula_list's data -* structure -**/ - -package AST +package lambdapi import ( - "sort" + "fmt" + "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" ) -type FormList struct { - *Glob.List[Form] -} +var global_env Lib.List[Lib.Pair[string, AST.Ty]] = Lib.NewList[Lib.Pair[string, AST.Ty]]() -func NewFormList(slice ...Form) *FormList { - return &FormList{Glob.NewList(slice...)} +func toLocalVar(i int) string { + return fmt.Sprintf("v%d", i) } -func (fl *FormList) Less(i, j int) bool { - return (fl.Get(i).ToString() < fl.Get(j).ToString()) +func addToLocalContext(form AST.Form, local_con Lib.List[AST.Form]) (string, Lib.List[AST.Form]) { + index := local_con.Len() + local_con.Append(form) + return toLocalVar(index), local_con } -func (fl *FormList) Copy() *FormList { - return &FormList{fl.List.Copy()} -} - -func (lf *FormList) ToMappableStringSlice() []MappableString { - forms := []MappableString{} - - for _, form := range lf.Slice() { - forms = append(forms, form.(MappableString)) +func getFromLocalContext(form AST.Form, local_con Lib.List[AST.Form]) string { + opt_int := Lib.ListIndexOf(form, local_con) + + switch index := opt_int.(type) { + case Lib.Some[int]: + return toLocalVar(index.Val) + case Lib.None[int]: + debug(Lib.MkLazy(func() string { + return fmt.Sprintf( + "Trying to find %s in local context %s", + form.ToString(), + Lib.ListToString(local_con, ", ", "{}"), + ) + })) + Glob.Anomaly("LambdaPi", "a formula was not found in the local context while translating") } - - return forms + return "" } -func (fl *FormList) Equals(other *FormList) bool { - if fl.Len() != other.Len() { - return false - } - - flSorted := fl.Copy() - sort.Sort(flSorted) - - otherSorted := other.Copy() - sort.Sort(otherSorted) - - for i := range flSorted.Slice() { - if !flSorted.Get(i).Equals(otherSorted.Get(i)) { - return false - } - } - - return true +func addToGlobalEnv(p Lib.Pair[string, AST.Ty]) { + global_env.Append(p) } -// Removes all AND formulas: {(a & b), (b => c), (d & (e & f))} -> {(a), (b), (b => c), (d), (e), (f)} -func (fl *FormList) Flatten() *FormList { - result := NewFormList() - - for _, form := range fl.Slice() { - if typed, ok := form.(And); ok { - result.Append(typed.FormList.Flatten().Slice()...) - } else { - result.Append(form) +func searchGlobalEnv(ty AST.Ty) Lib.Option[string] { + for _, p := range global_env.GetSlice() { + if p.Snd.Equals(ty) { + return Lib.MkSome(p.Fst) } } - - return result -} - -func (fl *FormList) ReplaceMetaByTerm(meta Meta, term Term) *FormList { - for i, f := range fl.Slice() { - fl.Set(i, f.ReplaceMetaByTerm(meta, term)) - } - - return fl + return Lib.MkNone[string]() } diff --git a/src/Mods/lambdapi/output.go b/src/Mods/lambdapi/output.go index cd5de4d0..0f891d6a 100644 --- a/src/Mods/lambdapi/output.go +++ b/src/Mods/lambdapi/output.go @@ -32,6 +32,8 @@ package lambdapi import ( + "fmt" + "regexp" "strings" "github.com/GoelandProver/Goeland/AST" @@ -42,58 +44,141 @@ import ( ) var contextEnabled bool = false - -var lambdaPiMapConnectors = map[AST.FormulaType]string{ - AST.AndConn: "∧", - AST.OrConn: "∨", - AST.ImpConn: "⇒", - AST.EquConn: "⇔", - AST.NotConn: "¬", - AST.TopType: "⊤", - AST.BotType: "⊥", - AST.AllQuant: "∀α", - AST.ExQuant: "∃α", - AST.AllTypeQuant: "∀", - AST.QuantVarOpen: "(", - AST.QuantVarClose: ")", - AST.QuantVarSep: " ", - AST.PredEmpty: "", - AST.PredTypeVarSep: ") (", - AST.TypeVarType: "Type", -} - +var debug Glob.Debugger var LambdapiOutputProofStruct = &Search.OutputProofStruct{ProofOutput: MakeLambdapiOutput, Name: "Lambdapi", Extension: ".lp"} // ---------------------------------------------------------------------------- // Plugin initialisation and main function to call. // Section: init -// Functions: MakeRocqOutput -// Main functions of the rocq module. +// Functions: MakeLambdapiOutput +// Main functions of the lambdapi module. // TODO: // * Write the context for TFF problems +func InitDebugger() { + debug = Glob.CreateDebugger("LambdaPi") +} + func MakeLambdapiOutput(prf []Search.ProofStruct, meta Lib.List[AST.Meta]) string { if len(prf) == 0 { - Glob.PrintError("LambdaPi", "Nothing to output") - return "" + Glob.Fatal("LambdaPi", "Nothing to output") } + connectives := LambdapiPrinterConnectives() + printer := AST.Printer{PrinterAction: LambdapiPrinterAction(), PrinterConnective: &connectives} + AST.SetPrinter(printer) + // Transform tableaux's proof in GS3 proof return MakeLambdaPiProof(gs3.MakeGS3Proof(prf), meta) } +func LambdapiPrinterConnectives() AST.PrinterConnective { + return AST.MkPrinterConnective( + "LambdapiPrinterConnectives", + map[AST.Connective]string{ + AST.ConnAll: "∀α λ", + AST.ConnEx: "∃α λ", + AST.ConnAnd: " ∧ ", + AST.ConnOr: " ∨ ", + AST.ConnImp: "⇒", + AST.ConnEqu: "⇔", + AST.ConnTop: "⊤", + AST.ConnBot: "⊥", + AST.ConnNot: "¬ ", + + AST.ConnPi: "∀", + AST.ConnMap: "→", + AST.ConnProd: "→", + + AST.SepArgs: " ", + AST.SepTyArgs: " ", + AST.SepArgsTyArgs: " ", + AST.SepVarsForm: ", ", + AST.SepTyVars: " ", + AST.SepVarTy: "", + + AST.SurQuantStart: "", + AST.SurQuantEnd: "", + AST.SurFunctionalStart: " ", + AST.SurFunctionalEnd: "", + }, + ) +} + +func LambdapiPrinterAction() AST.PrinterAction { + connectives := LambdapiPrinterConnectives() + + sanitize_type := func(ty_str string) string { + replace := map[string]string{ + "$i": "τ (ι)", + "$o": "Prop", + "$tType": "Type", + // FIXME: define a replacement for every defined stuff + } + for k, v := range replace { + ty_str = strings.ReplaceAll(ty_str, k, v) + } + return ty_str + } + lambdapi_action := AST.MkPrinterAction( + func(s string) string { + reg := regexp.MustCompile("([^∀∃]*)(∀α|∃α) λ ([^,]+), ([^∀∃]*)") + matches := reg.FindAllStringSubmatch(s, -1) + + if len(matches) == 0 { + return s + } + + // Properly format quantifiers: Q λ (X1 : t1), Q λ (X2 : t2), ... instead of + // Q λ (X1 : t1) (X2 : t2) ..., ... + result_string := "" + for _, match := range matches { + result_string += match[1] + quantifier := match[2] + variables := match[3] + ed := match[4] + variables_list := strings.Split(variables, ") (") + for i, variable := range variables_list { + prefix := "(" + suffix := ")" + if i == 0 { + prefix = "" + } + if i == len(variables_list)-1 { + suffix = "" + } + result_string += quantifier + " λ " + prefix + variable + suffix + ", " + } + result_string += ed + } + return result_string + }, + func(i AST.Id) string { return i.GetName() }, + AST.PrinterIdentity2[int], + func(metaName string, index int) string { return fmt.Sprintf("%s_%d", metaName, index) }, + sanitize_type, + func(typed_var Lib.Pair[string, AST.Ty]) string { + return fmt.Sprintf("(%s : %s)", typed_var.Fst, sanitize_type(typed_var.Snd.ToString())) + }, + func(id AST.Id, tys Lib.List[string], args Lib.List[string]) string { + if strings.Contains(id.GetName(), "sko") { + return id.ToString() + } else { + return connectives.DefaultOnFunctionalArgs(id, tys, args) + } + }, + ) + lambdapi_action = lambdapi_action.Compose(AST.SanitizerAction(connectives, []string{"@"})) + return lambdapi_action.Compose(AST.RemoveSuperfluousParenthesesAction(connectives)) +} + var MakeLambdaPiProof = func(proof *gs3.GS3Sequent, meta Lib.List[AST.Meta]) string { contextString := makeContextIfNeeded(proof.GetTargetForm(), meta) proofString := makeLambdaPiProofFromGS3(proof) return contextString + "\n" + proofString } -func mapDefault(str string) string { - result := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(str, "$i", "ι"), "$o", "Prop"), "->", "→"), "*", "→") - return result -} - // Context flag utility function func GetContextEnabled() bool { return contextEnabled diff --git a/src/Mods/lambdapi/proof.go b/src/Mods/lambdapi/proof.go index 852a7697..d8dcc6f1 100644 --- a/src/Mods/lambdapi/proof.go +++ b/src/Mods/lambdapi/proof.go @@ -37,89 +37,100 @@ import ( "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Mods/CertifUtils" "github.com/GoelandProver/Goeland/Mods/gs3" ) func makeLambdaPiProofFromGS3(proof *gs3.GS3Sequent) string { - axioms, conjecture := processMainFormula(proof.GetTargetForm()) - var resultingString string - - resultingString = makeTheorem(axioms, conjecture) - formula := proof.GetTargetForm() - - formulaStr := toCorrectString(formula) - resultingString += fmt.Sprintf("λ (%s : ϵ %s),\n", addToContext(formula), formulaStr) - proofStr := makeProofStep(proof) - resultingString += proofStr - - return resultingString + ";\n" + axioms, conjecture := processMainFormula(formula) + + resulting_string, to_introduce := makeTheorem(axioms, conjecture) + context := Lib.NewList[AST.Form]() + resulting_string += "begin\n " + str, local_context := assume(to_introduce, context) + if to_introduce.Len() != 1 { + proof = proof.Child(0) + } + return resulting_string + str + makeProofStep(proof, local_context) + "end;\n" } -func makeProofStep(proof *gs3.GS3Sequent) string { +func makeProofStep(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { var resultingString string switch proof.Rule() { - // Closure. case gs3.AX: - resultingString = closureAxiom(proof) - - // Alpha rules + resultingString = closureAxiom(proof, context) case gs3.NNOT: - resultingString = alphaNotNot(proof) + resultingString = alphaNotNot(proof, context) case gs3.AND: - resultingString = alphaAnd(proof) + resultingString = alphaAnd(proof, context) case gs3.NOR: - resultingString = alphaNotOr(proof) + resultingString = alphaNotOr(proof, context) case gs3.NIMP: - resultingString = alphaNotImp(proof) - - // Beta rules + resultingString = alphaNotImp(proof, context) case gs3.OR: - resultingString = betaOr(proof) + resultingString = betaOr(proof, context) case gs3.NAND: - resultingString = betaNotAnd(proof) + resultingString = betaNotAnd(proof, context) case gs3.IMP: - resultingString = betaImp(proof) + resultingString = betaImp(proof, context) case gs3.EQU: - resultingString = betaEqu(proof) + resultingString = betaEqu(proof, context) case gs3.NEQU: - resultingString = betaNotEqu(proof) - - // Delta rules + resultingString = betaNotEqu(proof, context) case gs3.EX: - resultingString = deltaEx(proof) + resultingString = deltaEx(proof, context) case gs3.NALL: - resultingString = deltaNotAll(proof) - - // Gamma rules + resultingString = deltaNotAll(proof, context) case gs3.ALL: - resultingString = gammaAll(proof) + resultingString = gammaAll(proof, context) case gs3.NEX: - resultingString = gammaNotEx(proof) + resultingString = gammaNotEx(proof, context) + default: + Glob.Fatal("LambdaPi", fmt.Sprintf("Translation of rule %s not implemented yet", proof.Rule().ToString())) + } + + return resultingString +} - // Weakening rule - case gs3.W: - Glob.PrintError("LP", "Trying to do a weakening rule but it's not implemented yet") +func assume(formulas Lib.List[AST.Form], context Lib.List[AST.Form]) (string, Lib.List[AST.Form]) { + resulting_string := " assume" + for _, form := range formulas.GetSlice() { + val, con := addToLocalContext(form, context) + resulting_string += fmt.Sprintf(" %s", val) + context = con } + return resulting_string + ";\n", context +} - return "//" + toCorrectString(proof.GetTargetForm()) + "\n" + resultingString +func refine(lemma string, arguments Lib.List[string], in_con string, goals int) string { + arguments_string := strings.Join(arguments.GetSlice(), " ") + goals_string := strings.Repeat("_ ", goals) + return fmt.Sprintf(" refine %s %s %s %s\n", lemma, arguments_string, goals_string, in_con) } -func closureAxiom(proof *gs3.GS3Sequent) string { - target, notTarget := getPosAndNeg(proof.GetTargetForm()) +func closureAxiom(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + if CertifUtils.IsPredEqual(proof.GetTargetForm()) { + Glob.Fatal("LambdaPi", "congruence closure is not implemented yet") + } + target, notTarget := getPosAndNeg(proof.GetTargetForm()) result := "" - switch target.(type) { case AST.Pred: - result = fmt.Sprintf("GS3axiom (%s) (%s) (%s)\n", toCorrectString(target), getFromContext(target), getFromContext(notTarget)) + result = refine("GS3axiom", Lib.MkListV( + "("+target.ToString()+")", + getFromLocalContext(target, context), + getFromLocalContext(notTarget, context), + ), "", 0) case AST.Top: - result = fmt.Sprintf("GS3ntop (%s)\n", getFromContext(notTarget)) + result = refine("GS3ntop", Lib.MkListV(getFromLocalContext(notTarget, context)), "", 0) case AST.Bot: - result = fmt.Sprintf("GS3bot (%s)\n", getFromContext(target)) + result = refine("GS3bot", Lib.MkListV(getFromLocalContext(target, context)), "", 0) } - return result + return result + ";" } func getPosAndNeg(target AST.Form) (pos, neg AST.Form) { @@ -129,226 +140,255 @@ func getPosAndNeg(target AST.Form) (pos, neg AST.Form) { return target, AST.MakerNot(target) } -func allRules(rule string, target AST.Form, composingForms *AST.FormList, nexts []*gs3.GS3Sequent, children []*AST.FormList) string { - result := rule + "\n" - - for _, composingForm := range composingForms.Slice() { - result += "(" + toCorrectString(composingForm) + ")\n" +func refineGenericRule(lemma string, proof *gs3.GS3Sequent, remaining_goals int, context Lib.List[AST.Form]) string { + formulas_list := Lib.NewList[string]() + + // If a term was generated, get its type and place the stuff in the right order: the type of + // the generated term, the formula and then the term. + if gs3.IsGammaRule(proof.Rule()) || gs3.IsDeltaRule(proof.Rule()) { + ty := getTypeOfFirstBoundVar(proof.GetTargetForm()) + formated_child := getFormattedChild(proof.GetTargetForm()) + formulas_list = Lib.MkListV("("+strings.ReplaceAll(ty.ToString(), "τ", "")+")", "("+formated_child+")") + if gs3.IsGammaRule(proof.Rule()) { + // FIXME: use an option type instead of nil + if proof.TermGenerated() != nil { + formulas_list.Append(getFormattedTerm(proof.TermGenerated())) + } else { + // Try to find something in the global env, otherwise: fail + // FIXME: we should also try to find something in the local (term) environment + // (this does not exist yet) + switch term := searchGlobalEnv(ty).(type) { + case Lib.Some[string]: + formulas_list.Append(term.Val) + default: + Glob.Fatal("LambdaPi", fmt.Sprintf( + "no term of type %s available to instantiate the universal formula %s.", + ty.ToString(), + proof.GetTargetForm().ToString(), + )) + } + } + } + } else { + child_formulas := proof.GetTargetForm().GetChildFormulas() + switch f := proof.GetTargetForm().(type) { + case AST.Not: + child_formulas = f.GetForm().GetChildFormulas() + } + for _, form := range child_formulas.GetSlice() { + formulas_list.Append("(" + form.ToString() + ")") + } } - result += getRecursionUnivStr(nexts, children) - - result += fmt.Sprintf("(%s)\n", getFromContext(target)) - - return result -} - -func allRulesQuantUniv(rule string, target AST.Form, composingForms *AST.FormList, nexts []*gs3.GS3Sequent, children []*AST.FormList, vars []AST.Var, termGen AST.Term) string { + result_string := refine(lemma, formulas_list, getFromLocalContext(proof.GetTargetForm(), context), remaining_goals) - quant := "" - typeStr := vars[0].GetTypeApp().ToString() - switch typed := target.(type) { - case AST.All: - quant = lambdaPiMapConnectors[AST.AllQuant] - typeStr = typed.GetVarList()[0].GetTypeHint().ToString() - case AST.Not: - quant = lambdaPiMapConnectors[AST.ExQuant] + if remaining_goals <= 1 { + result_string = result_string[:len(result_string)-1] + ";\n" + assumptions, con := assume(proof.GetResultFormulasOfChild(0), Lib.ListCpy(context)) + if gs3.IsDeltaRule(proof.Rule()) { + assumptions = fmt.Sprintf("assume %s;", getFormattedTerm(proof.TermGenerated())) + assumptions + } + result_string += assumptions + result_string += makeProofStep(proof.Child(0), con) + } else { + for i := 0; i < remaining_goals; i++ { + result_string += "{\n" + assumptions, con := assume(proof.GetResultFormulasOfChild(i), Lib.ListCpy(context)) + result_string += assumptions + result_string += makeProofStep(proof.Child(i), con) + result_string += "}\n" + } + result_string = result_string[:len(result_string)-1] + ";\n" } + return result_string +} - typeStr = mapDefault(typeStr) - - result := rule + "\n" - result += "(" + typeStr + ")\n" - result += "(%s, " + toCorrectString(composingForms.Get(0)) + ")\n" - - varStrs := []string{} - for _, singleVar := range vars { - varStrs = append(varStrs, toLambdaIntroString(singleVar, singleVar.GetTypeHint().ToString())) +func getFormattedTerm(term AST.Term) string { + switch t := term.(type) { + case AST.Fun: + if strings.Contains(t.GetName(), "sko") { + return t.GetID().ToString() + } } - result = fmt.Sprintf(result, strings.Join(varStrs, ", "+quant+" ")) - - result += "(" + toCorrectString(termGen) + ")\n" - - result += getRecursionUnivStr(nexts, children) - - result += fmt.Sprintf("(%s)\n", getFromContext(target)) - - return result + return term.ToString() } -func getRecursionUnivStr(nexts []*gs3.GS3Sequent, children []*AST.FormList) (result string) { - for i, next := range nexts { - result += "(\n" - for _, childForm := range children[i].Slice() { - result += toLambdaString(childForm, toCorrectString(childForm)) + ",\n" +func getTypeOfFirstBoundVar(form AST.Form) AST.Ty { + getTySafe := func(var_list Lib.List[AST.TypedVar]) AST.Ty { + if var_list.Empty() { + debug(Lib.MkLazy(func() string { + return fmt.Sprintf( + "Formula %s has no bound variable, cannot get its type", + form.ToString(), + ) + })) + Glob.Anomaly("LambdaPi", "No bound variable.") } - proofStr := makeProofStep(next) - result += proofStr - result += ")\n" + return var_list.At(0).GetTy() } - return result -} -func allRulesQuantExist(rule string, target AST.Form, composingForms *AST.FormList, nexts []*gs3.GS3Sequent, children []*AST.FormList, vars []AST.Var, termGen AST.Term) string { - quant := "" - typeStr := vars[0].GetTypeApp().ToString() - switch typed := target.(type) { - case AST.Ex: - quant = lambdaPiMapConnectors[AST.ExQuant] - typeStr = typed.GetVarList()[0].GetTypeHint().ToString() + switch f := form.(type) { case AST.Not: - quant = lambdaPiMapConnectors[AST.AllQuant] + switch nf := f.GetForm().(type) { + case AST.All: + return getTySafe(nf.GetVarList()) + case AST.Ex: + return getTySafe(nf.GetVarList()) + } + case AST.All: + return getTySafe(f.GetVarList()) + case AST.Ex: + return getTySafe(f.GetVarList()) } - typeStr = mapDefault(typeStr) - - result := rule + "\n" - result += "(" + typeStr + ")\n" - result += "(%s, " + toCorrectString(composingForms.Get(0)) + ")\n" + debug(Lib.MkLazy(func() string { + return fmt.Sprintf( + "Called getTypeOfFirstBoundVar of %s which should have been a quantified formula (or a negation of such a formula)", + form.ToString(), + ) + })) + Glob.Anomaly("LambdaPi", "Not a quantifier formula") + return nil +} - varStrs := []string{} - for _, singleVar := range vars { - varStrs = append(varStrs, toLambdaIntroString(singleVar, singleVar.GetTypeHint().ToString())) +// Gets the child formula as a λ (bound_var : ty), P +func getFormattedChild(form AST.Form) string { + format := func(var_list Lib.List[AST.TypedVar], f AST.Form, maker func(Lib.List[AST.TypedVar], AST.Form) AST.Form) string { + f = maker(var_list.Slice(1, var_list.Len()), f) + return fmt.Sprintf( + "λ (%s : %s), %s", + var_list.At(0).GetName(), + var_list.At(0).GetTy().ToString(), + f.ToString(), + ) } - result = fmt.Sprintf(result, strings.Join(varStrs, ", "+quant+" ")) - - result += getRecursionExistStr(nexts, children, termGen) - - result += fmt.Sprintf("(%s)\n", getFromContext(target)) - - return result -} -func getRecursionExistStr(nexts []*gs3.GS3Sequent, children []*AST.FormList, termGen AST.Term) (result string) { - for i, next := range nexts { - result += "(\n" - typesStr := "" - if typed, ok := termGen.(AST.Fun); ok { - typesStr = mapDefault(typed.GetTypeHint().ToString()) - } - result += toLambdaIntroString(termGen, typesStr) + ",\n" - for _, childForm := range children[i].Slice() { - result += toLambdaString(childForm, toCorrectString(childForm)) + ",\n" + switch f := form.(type) { + case AST.Not: + switch nf := f.GetForm().(type) { + case AST.All: + return format(nf.GetVarList(), nf.GetForm(), func(vl Lib.List[AST.TypedVar], f AST.Form) AST.Form { + if !vl.Empty() { + f = AST.MakerAll(vl, f) + } + return f + }) + case AST.Ex: + return format(nf.GetVarList(), nf.GetForm(), func(vl Lib.List[AST.TypedVar], f AST.Form) AST.Form { + if !vl.Empty() { + f = AST.MakerEx(vl, f) + } + return f + }) } - proofStr := makeProofStep(next) - result += proofStr - result += ")\n" + case AST.All: + return format(f.GetVarList(), f.GetForm(), func(vl Lib.List[AST.TypedVar], f AST.Form) AST.Form { + if !vl.Empty() { + f = AST.MakerAll(vl, f) + } + return f + }) + case AST.Ex: + return format(f.GetVarList(), f.GetForm(), func(vl Lib.List[AST.TypedVar], f AST.Form) AST.Form { + if !vl.Empty() { + f = AST.MakerEx(vl, f) + } + return f + }) } - return result -} -func alphaNotNot(proof *gs3.GS3Sequent) string { - composingForms := proof.GetTargetForm().GetChildFormulas().Get(0).GetChildFormulas() - return allRules("GS3nnot", proof.GetTargetForm(), composingForms, proof.Children(), proof.GetResultFormulasOfChildren()) + Glob.Anomaly("LambdaPi", "Not a quantifier formula") + return "" } -func alphaAnd(proof *gs3.GS3Sequent) string { - return allRules("GS3and", proof.GetTargetForm(), proof.GetTargetForm().GetChildFormulas(), proof.Children(), proof.GetResultFormulasOfChildren()) +func refineUnaryRule(lemma string, proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineGenericRule(lemma, proof, 1, context) } -func alphaNotOr(proof *gs3.GS3Sequent) string { - composingForms := proof.GetTargetForm().GetChildFormulas().Get(0).GetChildFormulas() - return allRules("GS3nor", proof.GetTargetForm(), composingForms, proof.Children(), proof.GetResultFormulasOfChildren()) +func refineBinaryRule(lemma string, proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineGenericRule(lemma, proof, 2, context) } -func alphaNotImp(proof *gs3.GS3Sequent) string { - composingForms := proof.GetTargetForm().GetChildFormulas().Get(0).GetChildFormulas() - return allRules("GS3nimp", proof.GetTargetForm(), composingForms, proof.Children(), proof.GetResultFormulasOfChildren()) +func alphaNotNot(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineUnaryRule("GS3nnot", proof, context) } -func betaOr(proof *gs3.GS3Sequent) string { - return allRules("GS3or", proof.GetTargetForm(), proof.GetTargetForm().GetChildFormulas(), proof.Children(), proof.GetResultFormulasOfChildren()) +func alphaAnd(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineUnaryRule("GS3and", proof, context) } -func betaNotAnd(proof *gs3.GS3Sequent) string { - composingForms := proof.GetTargetForm().GetChildFormulas().Get(0).GetChildFormulas() - return allRules("GS3nand", proof.GetTargetForm(), composingForms, proof.Children(), proof.GetResultFormulasOfChildren()) +func alphaNotOr(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineUnaryRule("GS3nor", proof, context) } -func betaImp(proof *gs3.GS3Sequent) string { - return allRules("GS3imp", proof.GetTargetForm(), proof.GetTargetForm().GetChildFormulas(), proof.Children(), proof.GetResultFormulasOfChildren()) +func alphaNotImp(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineUnaryRule("GS3nimp", proof, context) } -func betaEqu(proof *gs3.GS3Sequent) string { - return allRules("GS3equ", proof.GetTargetForm(), proof.GetTargetForm().GetChildFormulas(), proof.Children(), proof.GetResultFormulasOfChildren()) +func betaOr(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineBinaryRule("GS3or", proof, context) } -func betaNotEqu(proof *gs3.GS3Sequent) string { - composingForms := proof.GetTargetForm().GetChildFormulas().Get(0).GetChildFormulas() - return allRules("GS3nequ", proof.GetTargetForm(), composingForms, proof.Children(), proof.GetResultFormulasOfChildren()) +func betaNotAnd(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineBinaryRule("GS3nand", proof, context) } -func deltaEx(proof *gs3.GS3Sequent) string { - var formulaEx AST.Ex - if form, ok := proof.GetTargetForm().(AST.Ex); ok { - formulaEx = form - } - - return allRulesQuantExist("GS3ex", proof.GetTargetForm(), proof.GetTargetForm().GetChildFormulas(), proof.Children(), proof.GetResultFormulasOfChildren(), formulaEx.GetVarList(), proof.TermGenerated()) +func betaImp(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineBinaryRule("GS3imp", proof, context) } -func deltaNotAll(proof *gs3.GS3Sequent) string { - var formulaAll AST.All - if notForm, ok := proof.GetTargetForm().(AST.Not); ok { - if form, ok := notForm.GetForm().(AST.All); ok { - formulaAll = form - } - } - composingForms := proof.GetTargetForm().GetChildFormulas().Get(0).GetChildFormulas() +func betaEqu(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineBinaryRule("GS3equ", proof, context) +} - return allRulesQuantExist("GS3nall", proof.GetTargetForm(), composingForms, proof.Children(), proof.GetResultFormulasOfChildren(), formulaAll.GetVarList(), proof.TermGenerated()) +func betaNotEqu(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineBinaryRule("GS3nequ", proof, context) } -func gammaAll(proof *gs3.GS3Sequent) string { - var formulaAll AST.All - if form, ok := proof.GetTargetForm().(AST.All); ok { - formulaAll = form - } +func deltaEx(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineUnaryRule("GS3ex", proof, context) +} - return allRulesQuantUniv("GS3all", proof.GetTargetForm(), proof.GetTargetForm().GetChildFormulas(), proof.Children(), proof.GetResultFormulasOfChildren(), formulaAll.GetVarList(), proof.TermGenerated()) +func deltaNotAll(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineUnaryRule("GS3nall", proof, context) } -func gammaNotEx(proof *gs3.GS3Sequent) string { - var formulaEx AST.Ex - if notForm, ok := proof.GetTargetForm().(AST.Not); ok { - if form, ok := notForm.GetForm().(AST.Ex); ok { - formulaEx = form - } - } - composingForms := proof.GetTargetForm().GetChildFormulas().Get(0).GetChildFormulas() +func gammaAll(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineUnaryRule("GS3all", proof, context) +} - return allRulesQuantUniv("GS3nex", proof.GetTargetForm(), composingForms, proof.Children(), proof.GetResultFormulasOfChildren(), formulaEx.GetVarList(), proof.TermGenerated()) +func gammaNotEx(proof *gs3.GS3Sequent, context Lib.List[AST.Form]) string { + return refineUnaryRule("GS3nex", proof, context) } -// Processes the formula that was proven by Goéland. -func processMainFormula(form AST.Form) (*AST.FormList, AST.Form) { - formList := AST.NewFormList() +// Split the axiom & conjecture formula from the root formula. +func processMainFormula(form AST.Form) (Lib.List[AST.Form], AST.Form) { + formList := Lib.NewList[AST.Form]() switch nf := form.(type) { case AST.Not: form = nf.GetForm() case AST.And: - last := nf.FormList.Len() - 1 - formList = AST.NewFormList(nf.FormList.GetElements(0, last)...) - form = nf.FormList.Get(last).(AST.Not).GetForm() + last := nf.GetChildFormulas().Len() - 1 + formList = Lib.MkListV(nf.GetChildFormulas().Get(0, last)...) + form = nf.GetChildFormulas().At(last).(AST.Not).GetForm() } return formList, form } // Prints the theorem's name & properly formats the first formula. -func makeTheorem(axioms *AST.FormList, conjecture AST.Form) string { - problemName := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(Glob.GetProblemName(), ".", "_"), "=", "_"), "+", "_") - axioms = axioms.Copy() +func makeTheorem(axioms Lib.List[AST.Form], conjecture AST.Form) (string, Lib.List[AST.Form]) { + problemName := CertifUtils.SanitizedTheoremName() + axioms = Lib.ListCpy(axioms) axioms.Append(AST.MakerNot(conjecture)) formattedProblem := makeImpChain(axioms) - return "symbol goeland_" + problemName + " : \nϵ " + toCorrectString(formattedProblem) + " → ϵ ⊥ ≔ \n" + return "symbol goeland_" + problemName + " : \n" + formattedProblem + " → ϵ ⊥ ≔ \n", axioms } // If [F1, F2, F3] is a formlist, then this function returns F1 -> (F2 -> F3). -func makeImpChain(forms *AST.FormList) AST.Form { - last := forms.Len() - 1 - form := forms.Get(last) - for i := last - 1; i >= 0; i-- { - form = AST.MakerImp(forms.Get(i), form) +func makeImpChain(forms Lib.List[AST.Form]) string { + imp_chain := []string{} + for _, form := range forms.GetSlice() { + imp_chain = append(imp_chain, fmt.Sprintf("ϵ (%s)", form.ToString())) } - return form + return strings.Join(imp_chain, " → ") } diff --git a/src/Mods/lambdapi/utils.go b/src/Mods/lambdapi/utils.go deleted file mode 100644 index 803f16d5..00000000 --- a/src/Mods/lambdapi/utils.go +++ /dev/null @@ -1,95 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ -package lambdapi - -import ( - "fmt" - "strings" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" -) - -var varCounter int - -func getIncreasedCounter() int { - varCounter++ - return varCounter - 1 -} - -var context Glob.Map[AST.MappableString, Glob.String] = *Glob.NewMap[AST.MappableString, Glob.String]() - -func addToContext(key AST.MappableString) string { - if _, ok := context.GetExists(key); !ok { - context.Set(key, Glob.String(fmt.Sprintf("v%v", getIncreasedCounter()))) - } - - return string(context.Get(key)) -} - -func getFromContext(key AST.MappableString) string { - return string(context.Get(key)) -} - -func toLambdaString(element AST.MappableString, str string) string { - return fmt.Sprintf("λ (%s : ϵ (%s))", addToContext(element), str) -} - -func toLambdaIntroString(element AST.MappableString, typeStr string) string { - return fmt.Sprintf("λ (%s : τ (%s))", addToContext(element), mapDefault(typeStr)) -} - -func toCorrectString(element AST.MappableString) string { - isNotSkolem := len(element.ToString()) <= 5 || element.ToString()[:6] != "skolem" - element = decorateForm(element) - surround := element.ToMappedStringSurround(lambdaPiMapConnectors, false) - separator, emptyValue := element.ToMappedStringChild(lambdaPiMapConnectors, false) - children := "" - if isNotSkolem { - children = ListToMappedString(element.GetChildrenForMappedString(), separator, emptyValue) - } - return fmt.Sprintf(surround, children) -} - -func ListToMappedString[T AST.MappableString](children []T, separator, emptyValue string) string { - strArr := []string{} - - for _, element := range children { - strArr = append(strArr, toCorrectString(element)) - } - - if len(strArr) == 0 && emptyValue != "" { - strArr = append(strArr, emptyValue) - } - - return strings.Join(strArr, separator) -} diff --git a/src/Mods/rocq/context.go b/src/Mods/rocq/context.go index dca1bf5d..27d185e3 100644 --- a/src/Mods/rocq/context.go +++ b/src/Mods/rocq/context.go @@ -43,6 +43,7 @@ import ( "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Mods/CertifUtils" "github.com/GoelandProver/Goeland/Mods/dmt" ) @@ -59,29 +60,32 @@ func makeContextIfNeeded(root AST.Form, metaList Lib.List[AST.Meta]) string { root = AST.MakerAnd(registeredAxioms) } - if AST.EmptyGlobalContext() { - resultingString += strings.Join(getContextFromFormula(root), "\n") + "\n" - - if metaList.Len() > 0 { - resultingString += contextualizeMetas(metaList) - } - } else { - context := AST.GetGlobalContext() - for k, v := range context { - if typed, ok := v[0].App.(AST.TypeHint); ok { - if k[0] != '$' && k == typed.ToString() { - resultingString += "Parameter " + k + ": Type.\n" - - } - } - } - - resultingString += strings.Join(getContextFromFormula(root), "\n") + "\n" + // if AST.EmptyGlobalContext() { + contextual_symbols := CertifUtils.GetContextFromFormula(root) + for _, p := range contextual_symbols.GetSlice() { + resultingString += fmt.Sprintf("Parameter %s : %s.\n", p.Fst.ToString(), p.Snd.ToString()) + } - if metaList.Len() > 0 { - resultingString += contextualizeMetas(metaList) - } + if metaList.Len() > 0 { + resultingString += contextualizeMetas(metaList) } + // } else { + // context := AST.GetGlobalContext() + // for k, v := range context { + // if typed, ok := v[0].App.(AST.TypeHint); ok { + // if k[0] != '$' && k == typed.ToString() { + // resultingString += "Parameter " + k + ": Type.\n" + + // } + // } + // } + + // resultingString += strings.Join(getContextFromFormula(root), "\n") + "\n" + + // if metaList.Len() > 0 { + // resultingString += contextualizeMetas(metaList) + // } + // } return resultingString } @@ -92,82 +96,15 @@ func contextPreamble() string { return str } -func getContextFromFormula(root AST.Form) []string { - result := []string{} - switch nf := root.(type) { - case AST.All: - result = getContextFromFormula(nf.GetForm()) - case AST.Ex: - result = getContextFromFormula(nf.GetForm()) - case AST.AllType: - result = getContextFromFormula(nf.GetForm()) - case AST.And: - for _, f := range nf.FormList.Slice() { - result = append(result, clean(result, getContextFromFormula(f))...) - } - case AST.Or: - for _, f := range nf.FormList.Slice() { - result = append(result, clean(result, getContextFromFormula(f))...) - } - case AST.Imp: - result = clean(result, getContextFromFormula(nf.GetF1())) - result = append(result, clean(result, getContextFromFormula(nf.GetF2()))...) - case AST.Equ: - result = clean(result, getContextFromFormula(nf.GetF1())) - result = append(result, clean(result, getContextFromFormula(nf.GetF2()))...) - case AST.Not: - result = clean(result, getContextFromFormula(nf.GetForm())) - case AST.Pred: - if !nf.GetID().Equals(AST.Id_eq) { - result = append(result, mapDefault(fmt.Sprintf("Parameter %s : %s.", - nf.GetID().ToMappedString(rocqMapConnectors(), false), nf.GetType().ToString()))) - } - for _, term := range nf.GetArgs().GetSlice() { - result = append(result, clean(result, getContextFromTerm(term))...) - } - } - return result -} - -func getContextFromTerm(trm AST.Term) []string { - result := []string{} - if fun, isFun := trm.(AST.Fun); isFun { - result = append(result, mapDefault(fmt.Sprintf("Parameter %s : %s.", - fun.GetID().ToMappedString(rocqMapConnectors(), false), fun.GetTypeHint().ToString()))) - for _, term := range fun.GetArgs().GetSlice() { - result = append(result, clean(result, getContextFromTerm(term))...) - } - } - return result -} - -// Returns everything in add not in set -func clean(set, add []string) []string { - result := []string{} - for _, str := range add { - found := false - for _, s := range set { - if s == str { - found = true - break - } - } - if !found { - result = append(result, str) - } - } - return result -} - func contextualizeMetas(metaList Lib.List[AST.Meta]) string { result := []string{} for _, meta := range metaList.GetSlice() { - result = append(result, meta.ToMappedString(rocqMapConnectors(), false)) + result = append(result, meta.ToString()) } return "Parameters " + strings.Join(result, " ") + " : goeland_U." } -var lemmas = `Require Export Classical. +var lemmas = `From Stdlib Require Import Classical. Lemma goeland_notnot : forall P : Prop, P -> (~ P -> False). diff --git a/src/Mods/rocq/output.go b/src/Mods/rocq/output.go index 1efaaff6..bea023d6 100644 --- a/src/Mods/rocq/output.go +++ b/src/Mods/rocq/output.go @@ -37,6 +37,7 @@ package rocq import ( + "fmt" "strings" "github.com/GoelandProver/Goeland/AST" @@ -53,53 +54,85 @@ var RocqOutputProofStruct = &Search.OutputProofStruct{ProofOutput: MakeRocqOutpu // ---------------------------------------------------------------------------- // Plugin initialisation and main function to call. -// Section: init -// Functions: MakeRocqOutput -// Main functions of the rocq module. -// TODO: -// * Write the context for TFF problems - func MakeRocqOutput(prf []Search.ProofStruct, meta Lib.List[AST.Meta]) string { if len(prf) == 0 { Glob.PrintError("Rocq", "Nothing to output") return "" } + // Setup Rocq printer + connectives := RocqPrinterConnectives() + printer := AST.Printer{PrinterAction: RocqPrinterAction(), PrinterConnective: &connectives} + AST.SetPrinter(printer) + // Transform tableaux's proof in GS3 proof return MakeRocqProof(gs3.MakeGS3Proof(prf), meta) } +func RocqPrinterConnectives() AST.PrinterConnective { + return AST.MkPrinterConnective( + "RocqPrinterConnective", + map[AST.Connective]string{ + AST.ConnAll: "forall", + AST.ConnEx: "exists", + AST.ConnAnd: " /\\ ", + AST.ConnOr: " \\/ ", + AST.ConnImp: "->", + AST.ConnEqu: "<->", + AST.ConnTop: "True", + AST.ConnBot: "False", + + AST.ConnPi: "forall", + AST.ConnMap: "->", + + AST.SepVarsForm: ", ", + AST.SepTyArgs: ", ", + AST.SepArgsTyArgs: ", ", + AST.SepTyVars: " ", + AST.SepVarTy: "", + + AST.SurQuantStart: "", + AST.SurQuantEnd: "", + }, + ) +} + +func RocqPrinterAction() AST.PrinterAction { + connectives := RocqPrinterConnectives() + + sanitize_type := func(ty_str string) string { + replace := map[string]string{ + "$i": "goeland_U", + "$o": "Prop", + "$tType": "Type", + // FIXME: define a replacement for every defined stuff + } + for k, v := range replace { + ty_str = strings.ReplaceAll(ty_str, k, v) + } + return ty_str + } + rocq_action := AST.MkPrinterAction( + AST.PrinterIdentity, + func(i AST.Id) string { return i.GetName() }, + AST.PrinterIdentity2[int], + func(metaName string, index int) string { return fmt.Sprintf("%s_%d", metaName, index) }, + sanitize_type, + func(typed_var Lib.Pair[string, AST.Ty]) string { + return fmt.Sprintf("(%s : %s)", typed_var.Fst, sanitize_type(typed_var.Snd.ToString())) + }, + connectives.DefaultOnFunctionalArgs, + ) + rocq_action = rocq_action.Compose(AST.SanitizerAction(connectives, []string{"@"})) + return rocq_action.Compose(AST.RemoveSuperfluousParenthesesAction(connectives)) +} + var MakeRocqProof = func(proof *gs3.GS3Sequent, meta Lib.List[AST.Meta]) string { contextString := makeContextIfNeeded(proof.GetTargetForm(), meta) proofString := makeRocqProofFromGS3(proof) return contextString + "\n" + proofString } -// Replace defined symbols by Rocq's defined symbols. -func mapDefault(str string) string { - return strings.ReplaceAll(strings.ReplaceAll(str, "$i", "goeland_U"), "$o", "Prop") -} -func rocqMapConnectors() map[AST.FormulaType]string { - return map[AST.FormulaType]string{ - AST.AndConn: "/\\", - AST.OrConn: "\\/", - AST.ImpConn: "->", - AST.EquConn: "<->", - AST.NotConn: "~", - AST.TopType: "True", - AST.BotType: "False", - AST.AllQuant: "forall", - AST.ExQuant: "exists", - AST.AllTypeQuant: "forall", - AST.QuantVarOpen: "(", - AST.QuantVarClose: ")", - AST.QuantVarSep: ",", - AST.PredEmpty: "", - AST.PredTypeVarSep: ",", - AST.TypeVarType: "Type", - } -} - // Context flag utility function func GetContextEnabled() bool { return contextEnabled diff --git a/src/Mods/rocq/proof.go b/src/Mods/rocq/proof.go index e9beda52..9eec8f0d 100644 --- a/src/Mods/rocq/proof.go +++ b/src/Mods/rocq/proof.go @@ -42,6 +42,8 @@ import ( "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Mods/CertifUtils" "github.com/GoelandProver/Goeland/Mods/dmt" "github.com/GoelandProver/Goeland/Mods/gs3" ) @@ -53,15 +55,15 @@ func makeRocqProofFromGS3(proof *gs3.GS3Sequent) string { axioms, conjecture := processMainFormula(proof.GetTargetForm()) totalAxioms := axioms.Len() if Glob.IsLoaded("dmt") { - axioms.Append(dmt.GetRegisteredAxioms().Slice()...) + axioms.Append(dmt.GetRegisteredAxioms().GetSlice()...) } var resultingString string resultingString = makeTheorem(axioms, conjecture) resultingString += "Proof.\n" - hypotheses := AST.NewFormList() + hypotheses := Lib.NewList[AST.Form]() if axioms.Len() > 0 { indices := make([]int, axioms.Len()) - for i, form := range axioms.Slice() { + for i, form := range axioms.GetSlice() { indices[i], hypotheses = introduce(form, hypotheses) } resultingString += "intros " + strings.Join(Glob.MapTo(indices, func(_ int, index int) string { return introName(index) }), " ") + ". " @@ -76,36 +78,53 @@ func makeRocqProofFromGS3(proof *gs3.GS3Sequent) string { return resultingString + "\nQed.\n" } -func followProofSteps(proof *gs3.GS3Sequent, hypotheses *AST.FormList, constantsCreated []AST.Term) string { +func followProofSteps(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], constantsCreated []AST.Term) string { var resultingString string - var childrenHypotheses []*AST.FormList + var childrenHypotheses []Lib.List[AST.Form] if !proof.IsEmpty() { resultingString, childrenHypotheses, constantsCreated = makeProofStep(proof, hypotheses, constantsCreated) } for i, child := range proof.Children() { if proof.IsEmpty() { - resultingString += "\n" + followProofSteps(child, hypotheses.Copy(), cp(constantsCreated)) + resultingString += "\n" + followProofSteps(child, Lib.ListCpy(hypotheses), cp(constantsCreated)) } else { - resultingString += "\n" + followProofSteps(child, childrenHypotheses[i].Copy(), cp(constantsCreated)) + resultingString += "\n" + followProofSteps(child, Lib.ListCpy(childrenHypotheses[i]), cp(constantsCreated)) } } return resultingString } -func makeProofStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, constantsCreated []AST.Term) (string, []*AST.FormList, []AST.Term) { +func makeProofStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], constantsCreated []AST.Term) (string, []Lib.List[AST.Form], []AST.Term) { stepResult, childrenHypotheses, constantsCreated := makeStep(proof, hypotheses, constantsCreated) return stepResult, childrenHypotheses, constantsCreated } -func makeStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, constantsCreated []AST.Term) (string, []*AST.FormList, []AST.Term) { +func makeStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], constantsCreated []AST.Term) (string, []Lib.List[AST.Form], []AST.Term) { var resultingString string - childrenHypotheses := []*AST.FormList{hypotheses} + childrenHypotheses := []Lib.List[AST.Form]{hypotheses} + + target := Lib.ListIndexOf(proof.GetTargetForm(), hypotheses) + var actualTarget int + switch t := target.(type) { + case Lib.Some[int]: + actualTarget = t.Val + case Lib.None[int]: + // If the target formula is an equality, it _does not_ target any formula of the context, + // it simply tells us to close by congruence. Hence, we don't raise an anomaly if the + // target form is an equality. + if !CertifUtils.IsPredEqual(proof.GetTargetForm()) { + Glob.Anomaly("rocq", fmt.Sprintf( + "Index of %s not found in { %s }", + proof.GetTargetForm().ToString(), + Lib.ListToString(hypotheses, " ;; ", ""), + )) + } + } - target, _ := hypotheses.GetIndexOf(proof.GetTargetForm()) switch proof.Rule() { // Closure. case gs3.AX: - if isPredEqual(proof.GetTargetForm()) { + if CertifUtils.IsPredEqual(proof.GetTargetForm()) { resultingString = "congruence." } else { resultingString = "auto." @@ -113,37 +132,37 @@ func makeStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, constantsCreated // Alpha rules case gs3.NNOT: - resultingString, childrenHypotheses = alphaStep(proof, hypotheses, target, "%s") + resultingString, childrenHypotheses = alphaStep(proof, hypotheses, actualTarget, "%s") case gs3.AND: - resultingString, childrenHypotheses = alphaStep(proof, hypotheses, target, "(goeland_and_s _ _ %s)") + resultingString, childrenHypotheses = alphaStep(proof, hypotheses, actualTarget, "(goeland_and_s _ _ %s)") case gs3.NOR: - resultingString, childrenHypotheses = alphaStep(proof, hypotheses, target, "(goeland_notor_s _ _ %s)") + resultingString, childrenHypotheses = alphaStep(proof, hypotheses, actualTarget, "(goeland_notor_s _ _ %s)") case gs3.NIMP: - resultingString, childrenHypotheses = alphaStep(proof, hypotheses, target, "(goeland_notimply_s _ _ %s)") + resultingString, childrenHypotheses = alphaStep(proof, hypotheses, actualTarget, "(goeland_notimply_s _ _ %s)") // Beta rules case gs3.NAND: - resultingString, childrenHypotheses = betaStep(proof, hypotheses, target, "(goeland_notand_s _ _ %s)") + resultingString, childrenHypotheses = betaStep(proof, hypotheses, actualTarget, "(goeland_notand_s _ _ %s)") case gs3.NEQU: - resultingString, childrenHypotheses = betaStep(proof, hypotheses, target, "(goeland_notequiv_s _ _ %s)") + resultingString, childrenHypotheses = betaStep(proof, hypotheses, actualTarget, "(goeland_notequiv_s _ _ %s)") case gs3.OR: - resultingString, childrenHypotheses = betaStep(proof, hypotheses, target, "(goeland_or_s _ _ %s)") + resultingString, childrenHypotheses = betaStep(proof, hypotheses, actualTarget, "(goeland_or_s _ _ %s)") case gs3.IMP: - resultingString, childrenHypotheses = betaStep(proof, hypotheses, target, "(goeland_imply_s _ _ %s)") + resultingString, childrenHypotheses = betaStep(proof, hypotheses, actualTarget, "(goeland_imply_s _ _ %s)") case gs3.EQU: - resultingString, childrenHypotheses = betaStep(proof, hypotheses, target, "(goeland_equiv_s _ _ %s)") + resultingString, childrenHypotheses = betaStep(proof, hypotheses, actualTarget, "(goeland_equiv_s _ _ %s)") // Delta rules case gs3.NALL: - resultingString, childrenHypotheses, constantsCreated = deltaStep(proof, hypotheses, target, "apply %s. intros %s. apply NNPP. intros %s. ", constantsCreated) + resultingString, childrenHypotheses, constantsCreated = deltaStep(proof, hypotheses, actualTarget, "apply %s. intros %s. apply NNPP. intros %s. ", constantsCreated) case gs3.EX: - resultingString, childrenHypotheses, constantsCreated = deltaStep(proof, hypotheses, target, "elim %s. intros %s. intros %s. ", constantsCreated) + resultingString, childrenHypotheses, constantsCreated = deltaStep(proof, hypotheses, actualTarget, "elim %s. intros %s. intros %s. ", constantsCreated) // Gamma rules case gs3.ALL: - resultingString, childrenHypotheses = gammaStep(proof, hypotheses, target, "generalize (%s %s). intros %s. ", constantsCreated) + resultingString, childrenHypotheses = gammaStep(proof, hypotheses, actualTarget, "generalize (%s %s). intros %s. ", constantsCreated) case gs3.NEX: - resultingString, childrenHypotheses = gammaStep(proof, hypotheses, target, "apply %s. exists %s. apply NNPP. intros %s. ", constantsCreated) + resultingString, childrenHypotheses = gammaStep(proof, hypotheses, actualTarget, "apply %s. exists %s. apply NNPP. intros %s. ", constantsCreated) // Weakening rule case gs3.W: @@ -154,26 +173,26 @@ func makeStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, constantsCreated } case gs3.REWRITE: - resultingString, childrenHypotheses = rewriteStep(proof.GetRewriteWith(), hypotheses, target, proof.GetResultFormulasOfChild(0).Get(0)) + resultingString, childrenHypotheses = rewriteStep(proof.GetRewriteWith(), hypotheses, actualTarget, proof.GetResultFormulasOfChild(0).At(0)) } return resultingString, childrenHypotheses, constantsCreated } -func alphaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, format string) (string, []*AST.FormList) { +func alphaStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int, format string) (string, []Lib.List[AST.Form]) { var indices []int indices, hypotheses = introduceList(proof.GetResultFormulasOfChild(0), hypotheses) resultingString := fmt.Sprintf("apply "+format+". intros %s. ", introName(target), introNames(indices)) - return resultingString, []*AST.FormList{hypotheses} + return resultingString, []Lib.List[AST.Form]{hypotheses} } -func betaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, format string) (string, []*AST.FormList) { - resultHyps := []*AST.FormList{} +func betaStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int, format string) (string, []Lib.List[AST.Form]) { + resultHyps := []Lib.List[AST.Form]{} var indices []int resultingString := fmt.Sprintf("apply "+format+"; ", introName(target)) introducedNames := make([]string, 0) for i := range proof.Children() { - hypoCopy := hypotheses.Copy() + hypoCopy := Lib.ListCpy(hypotheses) indices, hypoCopy = introduceList(proof.GetResultFormulasOfChild(i), hypoCopy) introducedNames = append(introducedNames, "intros "+introNames(indices, " ")) resultHyps = append(resultHyps, hypoCopy) @@ -182,75 +201,86 @@ func betaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, forma return resultingString + "[ " + strings.Join(introducedNames, " | ") + " ].", resultHyps } -func deltaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, format string, constantsCreated []AST.Term) (string, []*AST.FormList, []AST.Term) { +func deltaStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int, format string, constantsCreated []AST.Term) (string, []Lib.List[AST.Form], []AST.Term) { var indices []int var name string //PrintInfo("DELTA", fmt.Sprintf("%s\n%s", hypotheses[target].ToString(), proof.GetResultFormulasOfChild(0).ToString())) indices, hypotheses = introduceList(proof.GetResultFormulasOfChild(0), hypotheses) constantsCreated, name = addTermGenerated(constantsCreated, proof.TermGenerated()) resultingString := fmt.Sprintf(format, introName(target), name, introNames(indices)) - return resultingString, []*AST.FormList{hypotheses}, constantsCreated + return resultingString, []Lib.List[AST.Form]{hypotheses}, constantsCreated } -func gammaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, format string, constantsCreated []AST.Term) (string, []*AST.FormList) { +func gammaStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int, format string, constantsCreated []AST.Term) (string, []Lib.List[AST.Form]) { var indices []int indices, hypotheses = introduceList(proof.GetResultFormulasOfChild(0), hypotheses) name := "(" + getRealConstantName(constantsCreated, proof.TermGenerated()) + ")" resultingString := fmt.Sprintf(format, introName(target), name, introNames(indices)) - return resultingString, []*AST.FormList{hypotheses} + return resultingString, []Lib.List[AST.Form]{hypotheses} } -func rewriteStep(rewriteRule AST.Form, hypotheses *AST.FormList, target int, replacementForm AST.Form) (string, []*AST.FormList) { - index, _ := hypotheses.GetIndexOf(rewriteRule) - resultingString := fmt.Sprintf("rewrite %s in %s.", introName(index), introName(target)) - hypotheses.Set(target, replacementForm) - return resultingString, []*AST.FormList{hypotheses} +func rewriteStep(rewriteRule AST.Form, hypotheses Lib.List[AST.Form], target int, replacementForm AST.Form) (string, []Lib.List[AST.Form]) { + index := Lib.ListIndexOf(rewriteRule, hypotheses) + var actualIndex int + switch i := index.(type) { + case Lib.Some[int]: + actualIndex = i.Val + case Lib.None[int]: + Glob.Anomaly("rocq", fmt.Sprintf( + "Index of %s not found in %s", + rewriteRule.ToString(), + Lib.ListToString(hypotheses, ", ", "[]"), + )) + } + + resultingString := fmt.Sprintf("rewrite %s in %s.", introName(actualIndex), introName(target)) + hypotheses.Upd(target, replacementForm) + return resultingString, []Lib.List[AST.Form]{hypotheses} } // Processes the formula that was proven by Goéland. -func processMainFormula(form AST.Form) (*AST.FormList, AST.Form) { - formList := AST.NewFormList() +func processMainFormula(form AST.Form) (Lib.List[AST.Form], AST.Form) { + formList := Lib.NewList[AST.Form]() switch nf := form.(type) { case AST.Not: form = nf.GetForm() case AST.And: - last := nf.FormList.Len() - 1 - formList = AST.NewFormList(nf.FormList.GetElements(0, last)...) - form = nf.FormList.Get(last).(AST.Not).GetForm() + last := nf.GetChildFormulas().Len() - 1 + formList = Lib.MkListV(nf.GetChildFormulas().Get(0, last)...) + form = nf.GetChildFormulas().At(last).(AST.Not).GetForm() } return formList, form } // Prints the theorem's name & properly formats the first formula. -func makeTheorem(axioms *AST.FormList, conjecture AST.Form) string { - problemName := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(Glob.GetProblemName(), ".", "_"), "=", "_"), "+", "_") - axiomsWithConj := axioms.Copy() +func makeTheorem(axioms Lib.List[AST.Form], conjecture AST.Form) string { + problemName := CertifUtils.SanitizedTheoremName() + axiomsWithConj := Lib.ListCpy(axioms) axiomsWithConj.Append(AST.MakerNot(AST.MakerNot(conjecture))) formattedProblem := makeImpChain(axiomsWithConj) - return "Theorem goeland_proof_of_" + problemName + " : " + - mapDefault(formattedProblem.ToMappedString(rocqMapConnectors(), Glob.GetTypeProof())) + ".\n" + return "Theorem goeland_proof_of_" + problemName + " : " + formattedProblem.ToString() + ".\n" } // If [F1, F2, F3] is a formlist, then this function returns F1 -> (F2 -> F3). -func makeImpChain(forms *AST.FormList) AST.Form { +func makeImpChain(forms Lib.List[AST.Form]) AST.Form { last := forms.Len() - 1 - form := forms.Get(last) + form := forms.At(last) for i := last - 1; i >= 0; i-- { - form = AST.MakerImp(forms.Get(i), form) + form = AST.MakerImp(forms.At(i), form) } return form } // Introduces a new formula in rocq's hypotheses. -func introduce(f AST.Form, hypotheses *AST.FormList) (int, *AST.FormList) { +func introduce(f AST.Form, hypotheses Lib.List[AST.Form]) (int, Lib.List[AST.Form]) { index := hypotheses.Len() hypotheses.Append(f) return index, hypotheses } -func introduceList(fl, hypotheses *AST.FormList) ([]int, *AST.FormList) { +func introduceList(fl, hypotheses Lib.List[AST.Form]) ([]int, Lib.List[AST.Form]) { indices := make([]int, fl.Len()) - for i, f := range fl.Slice() { + for i, f := range fl.GetSlice() { indices[i], hypotheses = introduce(f, hypotheses) } return indices, hypotheses @@ -271,16 +301,6 @@ func introNames(il []int, sep ...string) string { return strings.Join(Glob.MapTo(il, func(_ int, f int) string { return introName(f) }), s) } -func isPredEqual(f AST.Form) bool { - if not, isNot := f.(AST.Not); isNot { - f = not.GetForm() - } - if p, isPred := f.(AST.Pred); isPred { - return p.GetID().Equals(AST.Id_eq) - } - return false -} - func addTermGenerated(constantsCreated []AST.Term, term AST.Term) ([]AST.Term, string) { if term == nil { dummy++ @@ -297,7 +317,7 @@ func getRealConstantName(constantsCreated []AST.Term, term AST.Term) string { if fun, isFun := term.(AST.Fun); isFun { res := "" if isGroundTerm(fun.GetID()) { - res = fun.GetID().ToMappedString(rocqMapConnectors(), Glob.GetTypeProof()) + res = fun.GetID().ToString() subterms := make([]string, 0) for _, t := range fun.GetArgs().GetSlice() { subterms = append(subterms, getRealConstantName(constantsCreated, t)) @@ -321,7 +341,7 @@ func findInConstants(constantsCreated []AST.Term, term AST.Term) string { return getConstantName(term.(AST.Fun).GetID()) } if isGroundTerm(term) { - return "(" + term.ToMappedString(rocqMapConnectors(), Glob.GetTypeProof()) + ")" + return "(" + term.ToString() + ")" } return "goeland_I" } @@ -332,14 +352,24 @@ func cp[T any](source []T) []T { return arr } -func cleanHypotheses(hypotheses *AST.FormList, form AST.Form) (string, []*AST.FormList) { +func cleanHypotheses(hypotheses Lib.List[AST.Form], form AST.Form) (string, []Lib.List[AST.Form]) { result := "" - index, _ := hypotheses.GetIndexOf(form) - if index != -1 { - hypotheses.Set(index, AST.MakerTop()) - result = fmt.Sprintf("clear %s. ", introName(index)) + index := Lib.ListIndexOf(form, hypotheses) + var actualIndex int + switch i := index.(type) { + case Lib.Some[int]: + actualIndex = i.Val + case Lib.None[int]: + Glob.Anomaly("rocq", fmt.Sprintf( + "Index of %s not found in %s", + form.ToString(), + Lib.ListToString(hypotheses, ", ", "[]"), + )) } - return result, []*AST.FormList{hypotheses} + + hypotheses.Upd(actualIndex, AST.MakerTop()) + result = fmt.Sprintf("clear %s. ", introName(actualIndex)) + return result, []Lib.List[AST.Form]{hypotheses} } func getConstantName(id AST.Id) string { diff --git a/src/Mods/tptp/output.go b/src/Mods/tptp/output.go index ee48f084..f27acd44 100644 --- a/src/Mods/tptp/output.go +++ b/src/Mods/tptp/output.go @@ -37,8 +37,6 @@ package tptp import ( - "strings" - "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" @@ -61,7 +59,10 @@ func MakeTptpOutput(prf []Search.ProofStruct, meta Lib.List[AST.Meta]) string { return "" } + // FIXME: set AST's printer to be the one of TPTP + if Glob.IsSCTPTPOutput() { + // FIXME: the one of TSTP here prefix_const = "Sko_" } @@ -70,33 +71,6 @@ func MakeTptpOutput(prf []Search.ProofStruct, meta Lib.List[AST.Meta]) string { } var MakeTptpProof = func(proof *gs3.GS3Sequent, meta Lib.List[AST.Meta]) string { - old := AST.ChangeVarSeparator(", ") proofString := makeTptpProofFromGS3(proof) - AST.ChangeVarSeparator(old) return proofString } - -// Replace defined symbols by TSTP's defined symbols. -func mapDefault(str string) string { - return strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(str, " : $i", ""), " : $o", ""), " : , ", " : ") -} -func tptpMapConnectors() map[AST.FormulaType]string { - return map[AST.FormulaType]string{ - AST.AndConn: "&", - AST.OrConn: "|", - AST.ImpConn: "=>", - AST.EquConn: "<=>", - AST.NotConn: "~", - AST.TopType: "$true", - AST.BotType: "$false", - AST.AllQuant: "!", - AST.ExQuant: "?", - AST.AllTypeQuant: "!", - AST.QuantVarOpen: "[", - AST.QuantVarClose: "] : ", - AST.QuantVarSep: ",", - AST.PredEmpty: "", - AST.PredTypeVarSep: ",", - AST.TypeVarType: "Type", - } -} diff --git a/src/Mods/tptp/proof.go b/src/Mods/tptp/proof.go index 83475561..6d28f59c 100644 --- a/src/Mods/tptp/proof.go +++ b/src/Mods/tptp/proof.go @@ -48,6 +48,7 @@ import ( "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Mods/gs3" ) @@ -64,7 +65,7 @@ var dummyTerm = AST.MakerConst(AST.MakerId("Goeland_I")) func makeTptpProofFromGS3(proof *gs3.GS3Sequent) string { axioms, conjecture := processMainFormula(proof.GetTargetForm()) resultingString := makeTheorem(axioms, conjecture) - hypotheses := axioms.Copy() + hypotheses := Lib.ListCpy(axioms) hypotheses.Append(AST.MakerNot(conjecture.Copy())) AxiomCut := performCutAxiomStep(axioms, conjecture) @@ -84,31 +85,31 @@ func makeTptpProofFromGS3(proof *gs3.GS3Sequent) string { /*** Proof Steps ***/ -func followProofSteps(proof *gs3.GS3Sequent, hypotheses *AST.FormList, new_current_id int) string { +func followProofSteps(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], new_current_id int) string { var resultingString string var resultingStringParent string - var childrenHypotheses []*AST.FormList + var childrenHypotheses []Lib.List[AST.Form] if !proof.IsEmpty() { resultingStringParent, childrenHypotheses, new_current_id = makeProofStep(proof, hypotheses, new_current_id) } for i, child := range proof.Children() { if proof.IsEmpty() { - resultingString += followProofSteps(child, hypotheses.Copy(), new_current_id) + "\n" + resultingString += followProofSteps(child, Lib.ListCpy(hypotheses), new_current_id) + "\n" } else { - newHypotheses := hypotheses.Copy() - newHypotheses.AppendIfNotContains(childrenHypotheses[i].Slice()...) + newHypotheses := Lib.ListCpy(hypotheses) + newHypotheses = Lib.ListAdd(newHypotheses, childrenHypotheses[i].GetSlice()...) resultingString += followProofSteps(child, newHypotheses, new_current_id) + "\n" } } return resultingString + resultingStringParent } -func makeProofStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, new_current_id int) (string, []*AST.FormList, int) { +func makeProofStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], new_current_id int) (string, []Lib.List[AST.Form], int) { stepResult, childrenHypotheses, next_child_weakened_id := makeStep(proof, hypotheses, new_current_id) return stepResult, childrenHypotheses, next_child_weakened_id } -func findIndexPos(f AST.Form, hypotheses *AST.FormList, target int) int { +func findIndexPos(f AST.Form, hypotheses Lib.List[AST.Form], target int) int { targetPos := -1 switch initial_formula := f.(type) { @@ -125,9 +126,9 @@ func findIndexPos(f AST.Form, hypotheses *AST.FormList, target int) int { return targetPos } -func makeStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, new_current_id int) (string, []*AST.FormList, int) { +func makeStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], new_current_id int) (string, []Lib.List[AST.Form], int) { var resultingString string - childrenHypotheses := []*AST.FormList{hypotheses} + childrenHypotheses := []Lib.List[AST.Form]{hypotheses} next_child_weakened_id := -1 updateId(proof, new_current_id) @@ -140,7 +141,7 @@ func makeStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, new_current_id in if isPredEqual(proof.GetTargetForm()) { resultingString = fmt.Sprintf("fof("+prefix_step+"%d, plain, [%s] --> [], inference(%s, [status(thm)], [%s])).", proof.GetId(), - mapDefault(AST.ListToMappedString(hypotheses.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), + Lib.ListToString(hypotheses, ", ", ""), "congruence", "") } else { @@ -148,7 +149,7 @@ func makeStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, new_current_id in resultingString = fmt.Sprintf("fof("+prefix_step+"%d, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s])).", proof.GetId(), - mapDefault(AST.ListToMappedString(hypotheses.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), + Lib.ListToString(hypotheses, ", ", ""), "leftHyp", targetPos, "") @@ -191,19 +192,19 @@ func makeStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, new_current_id in // Weakening rule case gs3.W: if proof.TermGenerated() != nil { - resultingString = fmt.Sprintf("leftWeaken %s", findInConstants(proof.TermGenerated()).ToMappedString(tptpMapConnectors(), Glob.GetTypeProof())) + resultingString = fmt.Sprintf("leftWeaken %s", findInConstants(proof.TermGenerated()).ToString()) } else { resultingString, childrenHypotheses, next_child_weakened_id = weakenStep(proof, hypotheses, target, "leftWeaken") } case gs3.REWRITE: - resultingString, childrenHypotheses = rewriteStep(proof.GetRewriteWith(), hypotheses, target, proof.GetResultFormulasOfChild(0).Get(0)) + resultingString, childrenHypotheses = rewriteStep(proof.GetRewriteWith(), hypotheses, target, proof.GetResultFormulasOfChild(0).At(0)) } return resultingString + "\n", childrenHypotheses, next_child_weakened_id } -func alphaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, format string) (string, []*AST.FormList) { +func alphaStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int, format string) (string, []Lib.List[AST.Form]) { children_id := []int{} for _, c := range proof.Children() { @@ -215,33 +216,33 @@ func alphaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, form resultingString := fmt.Sprintf("fof(%s%d, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s])).", prefix_step, proof.GetId(), - mapDefault(AST.ListToMappedString(hypotheses.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), + Lib.ListToString(hypotheses, ", ", ""), format, target, Glob.IntListToString(children_id, prefix_step)) - newHypotheses := hypotheses.Copy() - newHypotheses.AppendIfNotContains(proof.GetResultFormulasOfChild(0).Slice()...) - return resultingString, []*AST.FormList{newHypotheses} + newHypotheses := Lib.ListCpy(hypotheses) + newHypotheses = Lib.ListAdd(newHypotheses, proof.GetResultFormulasOfChild(0).GetSlice()...) + return resultingString, []Lib.List[AST.Form]{newHypotheses} } -func betaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, format string) (string, []*AST.FormList) { - resultHyps := []*AST.FormList{} +func betaStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int, format string) (string, []Lib.List[AST.Form]) { + resultHyps := []Lib.List[AST.Form]{} children_id := []int{} for i, c := range proof.Children() { new_id := incrByOne(&id_proof_step, &mutex_proof_step) children_id = append(children_id, new_id) c.SetId(new_id) - newHypotheses := hypotheses.Copy() - newHypotheses.AppendIfNotContains(proof.GetResultFormulasOfChild(i).Slice()...) + newHypotheses := Lib.ListCpy(hypotheses) + newHypotheses = Lib.ListAdd(newHypotheses, proof.GetResultFormulasOfChild(i).GetSlice()...) resultHyps = append(resultHyps, newHypotheses) } resultingString := fmt.Sprintf("fof(%s%d, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s])).", prefix_step, proof.GetId(), - mapDefault(AST.ListToMappedString(hypotheses.Slice(), ", ", "", tptpMapConnectors(), false)), + Lib.ListToString(hypotheses, ", ", ""), format, target, Glob.IntListToString(children_id, prefix_step)) @@ -249,7 +250,7 @@ func betaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, forma return resultingString, resultHyps } -func deltaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, format string) (string, []*AST.FormList) { +func deltaStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int, format string) (string, []Lib.List[AST.Form]) { children_id := []int{} for _, c := range proof.Children() { new_id := incrByOne(&id_proof_step, &mutex_proof_step) @@ -258,25 +259,25 @@ func deltaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, form } new_term := createNewConstant(proof.TermGenerated()) - + proof = updateSkolemSymbol(proof.TermGenerated(), new_term, proof) resultingString := fmt.Sprintf("fof(%s%d, plain, [%s] --> [], inference(%s, [status(thm), %d, '%s'], [%s])).", prefix_step, proof.GetId(), - mapDefault(AST.ListToMappedString(hypotheses.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), + Lib.ListToString(hypotheses, ", ", ""), format, target, - new_term.ToMappedString(tptpMapConnectors(), Glob.GetTypeProof()), + new_term.ToString(), Glob.IntListToString(children_id, prefix_step)) - newHypotheses := hypotheses.Copy() - newHypotheses.AppendIfNotContains(proof.GetResultFormulasOfChild(0).Slice()...) + newHypotheses := Lib.ListCpy(hypotheses) + newHypotheses = Lib.ListAdd(newHypotheses, proof.GetResultFormulasOfChild(0).GetSlice()...) - return resultingString, []*AST.FormList{newHypotheses} + return resultingString, []Lib.List[AST.Form]{newHypotheses} } -func gammaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, format string) (string, []*AST.FormList) { +func gammaStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int, format string) (string, []Lib.List[AST.Form]) { children_id := []int{} for _, c := range proof.Children() { new_id := incrByOne(&id_proof_step, &mutex_proof_step) @@ -289,61 +290,61 @@ func gammaStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, form resultingString := fmt.Sprintf("fof(%s%d, plain, [%s] --> [], inference(%s, [status(thm), %d, $fot(%s)], [%s])).", prefix_step, proof.GetId(), - mapDefault(AST.ListToMappedString(hypotheses.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), + Lib.ListToString(hypotheses, ", ", ""), format, target, - findInConstants(proof.TermGenerated()).ToMappedString(tptpMapConnectors(), Glob.GetTypeProof()), + findInConstants(proof.TermGenerated()).ToString(), Glob.IntListToString(children_id, prefix_step)) - newHypotheses := hypotheses.Copy() - newHypotheses.AppendIfNotContains(proof.GetResultFormulasOfChild(0).Slice()...) + newHypotheses := Lib.ListCpy(hypotheses) + newHypotheses = Lib.ListAdd(newHypotheses, proof.GetResultFormulasOfChild(0).GetSlice()...) - return resultingString, []*AST.FormList{newHypotheses} + return resultingString, []Lib.List[AST.Form]{newHypotheses} } -func weakenStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int, format string) (string, []*AST.FormList, int) { +func weakenStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int, format string) (string, []Lib.List[AST.Form], int) { child_id := incrByOne(&id_proof_step, &mutex_proof_step) if target != -1 { - hypotheses.Remove(target) + hypotheses = hypotheses.RemoveAt(target) } resultingString := fmt.Sprintf("fof(%s%d, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s%d])).", prefix_step, proof.GetId(), - mapDefault(AST.ListToMappedString(hypotheses.Slice(), ", ", "", tptpMapConnectors(), false)), + Lib.ListToString(hypotheses, ", ", ""), format, target, prefix_step, child_id) - return resultingString, []*AST.FormList{hypotheses}, child_id + return resultingString, []Lib.List[AST.Form]{hypotheses}, child_id } -func rewriteStep(rewriteRule AST.Form, hypotheses *AST.FormList, target int, replacementForm AST.Form) (string, []*AST.FormList) { +func rewriteStep(rewriteRule AST.Form, hypotheses Lib.List[AST.Form], target int, replacementForm AST.Form) (string, []Lib.List[AST.Form]) { // resultingString := fmt.Sprintf("rewrite %s in %s.", introName(get(rewriteRule, hypotheses)), introName(target)) // hypotheses[target] = replacementForm - // return resultingString, []*AST.FormList{hypotheses} - return "", []*AST.FormList{} + // return resultingString, []Lib.List[AST.Form]{hypotheses} + return "", []Lib.List[AST.Form]{} } -func EquStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int) (string, []*AST.FormList) { +func EquStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int) (string, []Lib.List[AST.Form]) { resultingString := "" - resultHyps := []*AST.FormList{} + resultHyps := []Lib.List[AST.Form]{} children_id := []int{} for i, c := range proof.Children() { new_id := incrByOne(&id_proof_step, &mutex_proof_step) children_id = append(children_id, new_id) c.SetId(new_id) - newHypotheses := hypotheses.Copy() - newHypotheses.AppendIfNotContains(proof.GetResultFormulasOfChild(i).Slice()...) + newHypotheses := Lib.ListCpy(hypotheses) + newHypotheses = Lib.ListAdd(newHypotheses, proof.GetResultFormulasOfChild(i).GetSlice()...) resultHyps = append(resultHyps, newHypotheses) } // Sub-formulas - A := hypotheses.Get(target).(AST.Equ).GetF1() - B := hypotheses.Get(target).(AST.Equ).GetF2() + A := hypotheses.At(target).(AST.Equ).GetF1() + B := hypotheses.At(target).(AST.Equ).GetF2() notA := AST.MakerNot(A) notB := AST.MakerNot(B) A_imp_B := AST.MakerImp(A, B) @@ -352,96 +353,95 @@ func EquStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int) (strin // from A <=> B to A => B, B => A (unary) s1_id := fmt.Sprintf("%s%dext1", prefix_step, proof.GetId()) resultingString = fmt.Sprintf("fof(%s%d, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s])).", - prefix_step, - proof.GetId(), - mapDefault(AST.ListToMappedString(hypotheses.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - "leftIff", - target, - s1_id) + resultingString + prefix_step, + proof.GetId(), + Lib.ListToString(hypotheses, ", ", ""), + "leftIff", + target, + s1_id) + resultingString // from A => B, B => A to ~A, B => A | B, B => A (binary) s2_id := fmt.Sprintf("%s%dext2", prefix_step, proof.GetId()) s3_id := fmt.Sprintf("%s%dext3", prefix_step, proof.GetId()) - newHyp := hypotheses.Copy() - newHyp.AppendIfNotContains([]AST.Form{A_imp_B, B_imp_A}...) + newHyp := Lib.ListCpy(hypotheses) + newHyp = Lib.ListAdd(newHyp, []AST.Form{A_imp_B, B_imp_A}...) resultingString = fmt.Sprintf("fof(%s, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s, %s])).\n\n", - s1_id, - mapDefault(AST.ListToMappedString(newHyp.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - "leftImp2", - get(A_imp_B, newHyp), - s2_id, - s3_id) + resultingString + s1_id, + Lib.ListToString(newHyp, ", ", ""), + "leftImp2", + get(A_imp_B, newHyp), + s2_id, + s3_id) + resultingString // Branch s2 : from ~A, B => A to ~A, ~B | ~A, A s2_closure_id := fmt.Sprintf("%sext1", s2_id) - newHypS2 := newHyp.Copy() - newHypS2.AppendIfNotContains(notA) + newHypS2 := Lib.ListCpy(newHyp) + newHypS2 = Lib.ListAdd(newHypS2, notA.Copy()) resultingString = fmt.Sprintf("fof(%s, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s%d, %s])).\n\n", - s2_id, - mapDefault(AST.ListToMappedString(newHypS2.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - "leftImp2", - get(B_imp_A, newHypS2), - prefix_step, - children_id[0], - s2_closure_id) + resultingString - resultHyps[0].AppendIfNotContains(newHypS2.Slice()...) - + s2_id, + Lib.ListToString(newHypS2, ", ", ""), + "leftImp2", + get(B_imp_A, newHypS2), + prefix_step, + children_id[0], + s2_closure_id) + resultingString + resultHyps[0] = Lib.ListAdd(resultHyps[0], newHypS2.GetSlice()...) // Branch 2.closure : from ~A, A closure - check polarity before - newHypS2Closure := newHypS2.Copy() - newHypS2Closure.AppendIfNotContains(A) + newHypS2Closure := Lib.ListCpy(newHypS2) + newHypS2Closure = Lib.ListAdd(newHypS2Closure, A) targetPosS2 := findIndexPos(A, newHypS2Closure, get(A, newHypS2Closure)) resultingString = fmt.Sprintf("fof(%s, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s])).\n\n", - s2_closure_id, - mapDefault(AST.ListToMappedString(newHypS2Closure.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - "leftHyp", - targetPosS2, - "") + resultingString + s2_closure_id, + Lib.ListToString(newHypS2Closure, ", ", ""), + "leftHyp", + targetPosS2, + "") + resultingString // Branch s3: from B, B => A to B, ~B | B, A s3_closure_id := fmt.Sprintf("%sext1", s3_id) - newHypS3 := newHyp.Copy() - newHypS3.AppendIfNotContains(B) + newHypS3 := Lib.ListCpy(newHyp) + newHypS3 = Lib.ListAdd(newHypS3, B) resultingString = fmt.Sprintf("fof(%s, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s, %s%d])).\n\n", - s3_id, - mapDefault(AST.ListToMappedString(newHypS3.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - "leftImp2", - get(B_imp_A, newHypS3), - s3_closure_id, - prefix_step, - children_id[1]) + resultingString - resultHyps[1].AppendIfNotContains(newHypS3.Slice()...) + s3_id, + Lib.ListToString(newHypS3, ", ", ""), + "leftImp2", + get(B_imp_A, newHypS3), + s3_closure_id, + prefix_step, + children_id[1]) + resultingString + resultHyps[1] = Lib.ListAdd(resultHyps[1], newHypS3.GetSlice()...) // Branch 3.closure : from B, ~B closure - check polarity before - newHypS3Closure := newHypS3.Copy() - newHypS3Closure.AppendIfNotContains(notB) + newHypS3Closure := Lib.ListCpy(newHypS3) + newHypS3Closure = Lib.ListAdd(newHypS3Closure, notB.Copy()) targetPosS3 := findIndexPos(B, newHypS3Closure, get(B, newHypS3Closure)) resultingString = fmt.Sprintf("fof(%s, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s])).\n\n", - s3_closure_id, - mapDefault(AST.ListToMappedString(newHypS3Closure.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - "leftHyp", - targetPosS3, - "") + resultingString + s3_closure_id, + Lib.ListToString(newHypS3Closure, ", ", ""), + "leftHyp", + targetPosS3, + "") + resultingString return resultingString, resultHyps } -func NotEquStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int) (string, []*AST.FormList) { +func NotEquStep(proof *gs3.GS3Sequent, hypotheses Lib.List[AST.Form], target int) (string, []Lib.List[AST.Form]) { resultingString := "" - resultHyps := []*AST.FormList{} + resultHyps := []Lib.List[AST.Form]{} children_id := []int{} for i, c := range proof.Children() { new_id := incrByOne(&id_proof_step, &mutex_proof_step) children_id = append(children_id, new_id) c.SetId(new_id) - newHypotheses := hypotheses.Copy() - newHypotheses.AppendIfNotContains(proof.GetResultFormulasOfChild(i).Slice()...) + newHypotheses := Lib.ListCpy(hypotheses) + newHypotheses = Lib.ListAdd(newHypotheses, proof.GetResultFormulasOfChild(i).GetSlice()...) resultHyps = append(resultHyps, newHypotheses) } // Sub-formulas - equ := hypotheses.Get(target).(AST.Not).GetForm().(AST.Equ) + equ := hypotheses.At(target).(AST.Not).GetForm().(AST.Equ) A := equ.GetF1() B := equ.GetF2() not_A_imp_B := AST.MakerNot(AST.MakerImp(A, B)) @@ -451,73 +451,73 @@ func NotEquStep(proof *gs3.GS3Sequent, hypotheses *AST.FormList, target int) (st s1_id := fmt.Sprintf("%s%dext1", prefix_step, proof.GetId()) s2_id := fmt.Sprintf("%s%dext2", prefix_step, proof.GetId()) resultingString = fmt.Sprintf("fof(%s%d, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s, %s])).", - prefix_step, - proof.GetId(), - mapDefault(AST.ListToMappedString(hypotheses.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - "leftNotIff", - target, - s1_id, - s2_id) + resultingString + prefix_step, + proof.GetId(), + Lib.ListToString(hypotheses, ", ", ""), + "leftNotIff", + target, + s1_id, + s2_id) + resultingString // from ~(A => B) to A, ~B - newHyp1 := hypotheses.Copy() - newHyp1.AppendIfNotContains(not_A_imp_B) + newHyp1 := Lib.ListCpy(hypotheses) + newHyp1 = Lib.ListAdd(newHyp1, not_A_imp_B.Copy()) resultingString = fmt.Sprintf("fof(%s, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s%d])).\n\n", - s1_id, - mapDefault(AST.ListToMappedString(newHyp1.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - "leftNotImplies", - get(not_A_imp_B, newHyp1), - prefix_step, - children_id[1]) + resultingString - resultHyps[1].AppendIfNotContains(newHyp1.Slice()...) + s1_id, + Lib.ListToString(newHyp1, ", ", ""), + "leftNotImplies", + get(not_A_imp_B, newHyp1), + prefix_step, + children_id[1]) + resultingString + resultHyps[1] = Lib.ListAdd(resultHyps[1], newHyp1.GetSlice()...) // from ~(B => A) to B, ~A - newHyp2 := hypotheses.Copy() - newHyp2.AppendIfNotContains(not_B_imp_A) + newHyp2 := Lib.ListCpy(hypotheses) + newHyp2 = Lib.ListAdd(newHyp2, not_B_imp_A.Copy()) resultingString = fmt.Sprintf("fof(%s, plain, [%s] --> [], inference(%s, [status(thm), %d], [%s%d])).\n\n", - s2_id, - mapDefault(AST.ListToMappedString(newHyp2.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - "leftNotImplies", - get(not_B_imp_A, newHyp2), - prefix_step, - children_id[0]) + resultingString - resultHyps[0].AppendIfNotContains(newHyp2.Slice()...) + s2_id, + Lib.ListToString(newHyp2, ", ", ""), + "leftNotImplies", + get(not_B_imp_A, newHyp2), + prefix_step, + children_id[0]) + resultingString + resultHyps[0] = Lib.ListAdd(resultHyps[0], newHyp2.GetSlice()...) return resultingString, resultHyps } - /*** Initial Formula Management ***/ // Processes the formula that was proven by Goéland. -func processMainFormula(form AST.Form) (*AST.FormList, AST.Form) { - formList := AST.NewFormList() +func processMainFormula(form AST.Form) (Lib.List[AST.Form], AST.Form) { + formList := Lib.NewList[AST.Form]() switch nf := form.(type) { case AST.Not: form = nf.GetForm() case AST.And: - last := nf.FormList.Len() - 1 - formList = AST.NewFormList(nf.FormList.GetElements(0, last)...) - form = nf.FormList.Get(last).(AST.Not).GetForm() + last := nf.GetChildFormulas().Len() - 1 + formList = Lib.MkListV(nf.GetChildFormulas().Get(0, last)...) + form = nf.GetChildFormulas().At(last).(AST.Not).GetForm() } return formList, form } // Prints the theorem's name & properly formats the first formula. -func makeTheorem(axioms *AST.FormList, conjecture AST.Form) string { +func makeTheorem(axioms Lib.List[AST.Form], conjecture AST.Form) string { var resulting_string string problemName := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(Glob.GetProblemName(), ".", "_"), "=", "_"), "+", "_") - for _, ax := range axioms.Slice() { - resulting_string = resulting_string + "fof(" + fmt.Sprintf("ax%d", ax.GetIndex()) + ", axiom, " + mapDefault(ax.ToMappedString(tptpMapConnectors(), Glob.GetTypeProof())) + ").\n\n" + for _, ax := range axioms.GetSlice() { + resulting_string = resulting_string + "fof(" + fmt.Sprintf("ax%d", ax.GetIndex()) + ", axiom, " + + ax.ToString() + ").\n\n" } - resulting_string = resulting_string + "fof(c_" + problemName + ", conjecture, " + mapDefault(conjecture.ToMappedString(tptpMapConnectors(), Glob.GetTypeProof())) + ").\n\n" + resulting_string = resulting_string + "fof(c_" + problemName + ", conjecture, " + conjecture.ToString() + ").\n\n" return resulting_string } // Perform the first step to go from ax |- c to ax, ~c |- -func performFirstStep(axioms *AST.FormList, conjecture AST.Form, hypothesis *AST.FormList, nextId int) (string, int) { +func performFirstStep(axioms Lib.List[AST.Form], conjecture AST.Form, hypothesis Lib.List[AST.Form], nextId int) (string, int) { cutFormNotId := incrByOne(&id_proof_step, &mutex_proof_step) cutFormHypId := incrByOne(&id_proof_step, &mutex_proof_step) nextFormId := incrByOne(&id_proof_step, &mutex_proof_step) @@ -525,9 +525,9 @@ func performFirstStep(axioms *AST.FormList, conjecture AST.Form, hypothesis *AST // Cut initial formula, |- ~c, c step cutFormNot := fmt.Sprintf("fof("+prefix_step+"%d, plain, [%s] --> [%s, %s], inference(%s, [status(thm), %d], [%s])).", cutFormNotId, - mapDefault(AST.ListToMappedString(axioms.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - mapDefault(conjecture.ToMappedString(tptpMapConnectors(), false)), - mapDefault(AST.MakerNot(conjecture).ToMappedString(tptpMapConnectors(), Glob.GetTypeProof())), + Lib.ListToString(axioms, ", ", ""), + conjecture.ToString(), + AST.MakerNot(conjecture).ToString(), "rightNot", 1, prefix_step+strconv.Itoa(cutFormHypId)) @@ -535,8 +535,8 @@ func performFirstStep(axioms *AST.FormList, conjecture AST.Form, hypothesis *AST // Cut initial formula, c |- c step cutFormHyp := fmt.Sprintf("fof("+prefix_step+"%d, plain, [%s] --> [%s], inference(%s, [status(thm), %d], [%s])).", cutFormHypId, - mapDefault(AST.ListToMappedString(append(axioms.Slice(), conjecture), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - mapDefault(conjecture.ToMappedString(tptpMapConnectors(), Glob.GetTypeProof())), + Lib.ListToString(Lib.MkListV(append(axioms.GetSlice(), conjecture)...), ", ", ""), + conjecture.ToString(), "hyp", axioms.Len(), // 0, @@ -546,8 +546,8 @@ func performFirstStep(axioms *AST.FormList, conjecture AST.Form, hypothesis *AST // indexHyp, _ := hypothesis.GetIndexOf(AST.MakerNot(conjecture)) startForm := fmt.Sprintf("fof(f%d, plain, [%s] --> [%s], inference(cut, [status(thm), %d], [%s%d, %s%d])).\n\n", nextId, - mapDefault(AST.ListToMappedString(axioms.Slice(), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - mapDefault(conjecture.ToMappedString(tptpMapConnectors(), Glob.GetTypeProof())), + Lib.ListToString(axioms, ", ", ""), + conjecture.ToString(), 1, //indexHyp, prefix_step, @@ -558,14 +558,13 @@ func performFirstStep(axioms *AST.FormList, conjecture AST.Form, hypothesis *AST return cutFormHyp + "\n\n" + cutFormNot + "\n\n" + startForm, nextFormId } - // Perform the cut axiom steps -func performCutAxiomStep(axioms *AST.FormList, conjecture AST.Form) string { +func performCutAxiomStep(axioms Lib.List[AST.Form], conjecture AST.Form) string { resultString := "" // Loop on axioms - for i, ax := range axioms.Slice() { + for i, ax := range axioms.GetSlice() { var nextStep string if i == axioms.Len()-1 { nextStep = "f0" @@ -577,8 +576,8 @@ func performCutAxiomStep(axioms *AST.FormList, conjecture AST.Form) string { prefix_axiom_cut, i, // AST.ListToMappedString(axioms.GetElements(0, i), ", ", "", tptpMapConnectors(), GetTypeProof()), - mapDefault(AST.ListToMappedString(axioms.GetElements(0, i), ", ", "", tptpMapConnectors(), Glob.GetTypeProof())), - mapDefault(conjecture.ToMappedString(tptpMapConnectors(), Glob.GetTypeProof())), + Lib.ListToString(Lib.MkListV(axioms.Get(0, i)...), ", ", ""), + conjecture.ToString(), 0, //i, "ax", @@ -592,11 +591,15 @@ func performCutAxiomStep(axioms *AST.FormList, conjecture AST.Form) string { /*** Utility Functions ***/ -func get(f AST.Form, fl *AST.FormList) int { - for i, h := range fl.Slice() { - if h.Equals(f) { - return i - } +func get(f AST.Form, fl Lib.List[AST.Form]) int { + switch index := Lib.ListIndexOf(f, fl).(type) { + case Lib.Some[int]: + return index.Val + case Lib.None[int]: + Glob.Anomaly( + "TPTP", + fmt.Sprintf("Formula %s not found in context", f.ToString()), + ) } return -1 } @@ -638,15 +641,15 @@ func updateSkolemSymbol(old, new AST.Term, proof *gs3.GS3Sequent) *gs3.GS3Sequen proof.SetTermGenerated(new_generated_term) } - new_forms_generated := make([]*AST.FormList, len(proof.GetResultFormulasOfChildren())) + new_forms_generated := make([]Lib.List[AST.Form], len(proof.GetResultFormulasOfChildren())) for i, fg := range proof.GetResultFormulasOfChildren() { - new_forms_generated_bis := AST.NewFormList() - for _, fg_bis := range fg.Slice() { + new_forms_generated_bis := Lib.NewList[AST.Form]() + for _, fg_bis := range fg.GetSlice() { new_term, _ := fg_bis.ReplaceTermByTerm(old, new) new_forms_generated_bis.Append(new_term) } new_forms_generated[i] = new_forms_generated_bis - } + } proof.SetFormGenerated(new_forms_generated) // Update Children @@ -666,7 +669,7 @@ func createNewConstant(term AST.Term) AST.Term { mutex_constant.Lock() new_id := len(constant_created) new_term_name := fmt.Sprintf("%s%d", prefix_const, new_id) - new_term := AST .MakerConst(AST.MakerNewId(new_term_name)) + new_term := AST.MakerConst(AST.MakerNewId(new_term_name)) original_term = append(original_term, term) constant_created = append(constant_created, new_term) mutex_constant.Unlock() diff --git a/src/Parser/pprinter.go b/src/Parser/pprinter.go index b8233333..c9318312 100644 --- a/src/Parser/pprinter.go +++ b/src/Parser/pprinter.go @@ -40,27 +40,27 @@ import ( ) func (t PVar) ToString() string { - return fmt.Sprintf("Var{%s}", t.name) + return fmt.Sprintf("Var(%s)", t.name) } func (f PFun) ToString() string { args := Lib.MkListV(f.arguments...) - return fmt.Sprintf("Fun{%s, %s}", f.symbol, args.ToString(PTerm.ToString, ", ", "[]")) + return fmt.Sprintf("%s(%s)", f.symbol, args.ToString(PTerm.ToString, ", ", "")) } func (c PConst) ToString() string { switch c.PConstant { case PTop: - return "Const{$true}" + return "$true" case PBot: - return "Const{$false}" + return "$false" } - return "Const{$unknown}" + return "Const{unknown}" } func (p PPred) ToString() string { args := Lib.MkListV(p.arguments...) - return fmt.Sprintf("Pred{%s, %s}", p.symbol, args.ToString(PTerm.ToString, ", ", "[]")) + return fmt.Sprintf("%s(%s)", p.symbol, args.ToString(PTerm.ToString, ", ", "")) } func (u PUnary) ToString() string { @@ -69,37 +69,37 @@ func (u PUnary) ToString() string { case PUnaryNeg: prefix = "Neg" } - return fmt.Sprintf("%s{%s}", prefix, u.PForm.ToString()) + return fmt.Sprintf("%s(%s)", prefix, u.PForm.ToString()) } func (b PBin) ToString() string { - prefix := "" + infix := "" switch b.operator { case PBinaryAnd: - prefix = "And" + infix = "&" case PBinaryOr: - prefix = "Or" + infix = "|" case PBinaryImp: - prefix = "Imp" + infix = "=>" case PBinaryEqu: - prefix = "Equ" + infix = "<=>" } - return fmt.Sprintf("%s{%s, %s}", prefix, b.left.ToString(), b.right.ToString()) + return fmt.Sprintf("(%s) %s (%s)", b.left.ToString(), infix, b.right.ToString()) } func (q PQuant) ToString() string { prefix := "" switch q.PQuantifier { case PQuantAll: - prefix = "All" + prefix = "!" case PQuantEx: - prefix = "Ex" + prefix = "?" } vars := Lib.MkListV(q.vars...) pairStr := func(p Lib.Pair[string, PAtomicType]) string { return "(" + p.Fst + ": " + p.Snd.(PType).ToString() + ")" } - return fmt.Sprintf("%s{%s, %s}", prefix, vars.ToString(pairStr, ", ", ""), q.PForm.ToString()) + return fmt.Sprintf("%s [%s]: (%s)", prefix, vars.ToString(pairStr, ", ", ""), q.PForm.ToString()) } func (v PTypeVar) ToString() string { @@ -140,7 +140,7 @@ func (q PTypeQuant) ToString() string { pairStr := func(p Lib.Pair[string, PAtomicType]) string { return "(" + p.Fst + ": " + p.Snd.(PType).ToString() + ")" } - return fmt.Sprintf("%s[%s]: (%s)", prefix, vars.ToString(pairStr, ", ", ""), q.t.ToString()) + return fmt.Sprintf("%s [%s]: (%s)", prefix, vars.ToString(pairStr, ", ", ""), q.t.ToString()) } func (stmt PStatement) ToString() string { diff --git a/src/Parser/psyntax.go b/src/Parser/psyntax.go index 8fd2dde8..24c4bf1c 100644 --- a/src/Parser/psyntax.go +++ b/src/Parser/psyntax.go @@ -51,6 +51,7 @@ type PAtomicType interface { type PType interface { isPType() ToString() string + Equals(any) bool } type PTypeVar struct { @@ -59,6 +60,12 @@ type PTypeVar struct { func MkPTypeVar(name string) PType { return PTypeVar{name} } func (v PTypeVar) Name() string { return v.name } +func (v PTypeVar) Equals(other any) bool { + if oth, ok := other.(PTypeVar); ok { + return oth.name == v.name + } + return false +} type PTypeFun struct { symbol string @@ -69,7 +76,20 @@ func MkPTypeFun(symbol string, args []PAtomicType) PType { return PTypeFun{symbo func (f PTypeFun) Symbol() string { return f.symbol } func (f PTypeFun) Args() []PAtomicType { return f.arguments } - +func (f PTypeFun) Equals(other any) bool { + if oth, ok := other.(PTypeFun); ok { + if len(f.arguments) != len(oth.arguments) { + return false + } + for i := range f.arguments { + if !f.arguments[i].(PType).Equals(oth.arguments[i]) { + return false + } + } + return oth.symbol == f.symbol + } + return false +} func (PTypeVar) isPAtomicType() {} func (PTypeVar) isPType() {} func (PTypeFun) isPAtomicType() {} @@ -100,6 +120,12 @@ type PTypeBin struct { func (b PTypeBin) Operator() PTypeBinOp { return b.op } func (b PTypeBin) Left() PType { return b.left } func (b PTypeBin) Right() PType { return b.right } +func (b PTypeBin) Equals(other any) bool { + if oth, ok := other.(PTypeBin); ok { + return oth.op == b.op && oth.left.Equals(b.left) && oth.right.Equals(b.right) + } + return false +} type PTypeQuantifier int @@ -116,7 +142,21 @@ type PTypeQuant struct { func (q PTypeQuant) Quant() PTypeQuantifier { return q.quant } func (q PTypeQuant) Vars() []Lib.Pair[string, PAtomicType] { return q.vars } func (q PTypeQuant) Ty() PType { return q.t } - +func (q PTypeQuant) Equals(other any) bool { + if oth, ok := other.(PTypeQuant); ok { + if len(oth.vars) != len(q.vars) { + return false + } + for i := range q.vars { + if q.vars[i].Fst != oth.vars[i].Fst || + !q.vars[i].Snd.(PType).Equals(oth.vars[i].Snd) { + return false + } + } + return oth.quant == q.quant && oth.t.Equals(q.t) + } + return false +} func (PTypeBin) isPType() {} func (PTypeQuant) isPType() {} @@ -156,6 +196,10 @@ type PVar struct { func (v PVar) Name() string { return v.name } +func MkVar(name string) PTerm { + return PVar{name} +} + func (PFun) isPTerm() {} func (PVar) isPTerm() {} diff --git a/src/Search/child_management.go b/src/Search/child_management.go index a02c580c..91df332c 100644 --- a/src/Search/child_management.go +++ b/src/Search/child_management.go @@ -127,8 +127,10 @@ func (ds *destructiveSearch) childrenClosedByThemselves(args wcdArgs, proofChild // Remove all the metavariables that have been introduced in this node: the parent do not know them. substForFather := Core.RemoveElementWithoutMM(args.st.GetAppliedSubst().GetSubst(), args.st.GetMM()) - if !substForFather.IsEmpty() { - args.st.SetSubstsFound([]Core.SubstAndForm{Core.MakeSubstAndForm(substForFather, args.st.GetAppliedSubst().GetForm())}) + if !substForFather.Empty() { + args.st.SetSubstsFound( + []Core.SubstAndForm{Core.MakeSubstAndForm(substForFather, args.st.GetAppliedSubst().GetForm())}, + ) } else { args.st.SetSubstsFound([]Core.SubstAndForm{}) } @@ -159,8 +161,9 @@ func (ds *destructiveSearch) passSubstToParent(args wcdArgs, proofChildren [][]P debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "All children agree on the substitution(s) : %v", - Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(substs))) + "All children agree on the substitution(s) : %s", + Unif.SubstsToString(Core.GetSubstListFromSubstAndFormList(substs)), + ) }), ) @@ -177,14 +180,15 @@ func (ds *destructiveSearch) passSubstToParent(args wcdArgs, proofChildren [][]P // Remove all the metas introduced by the current node to only retrieve relevant ones for the parent. resultingSubstsAndForms := []Core.SubstAndForm{} - resultingSubsts := []Unif.Substitutions{} + resultingSubsts := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() for _, subst := range substs { debug( Lib.MkLazy(func() string { return fmt.Sprintf( "Check the susbt, remove useless element and merge with applied subst :%v", - subst.GetSubst().ToString()) + Lib.ListToString(subst.GetSubst(), ", ", ""), + ) }), ) err, merged := Core.MergeSubstAndForm(subst, args.st.GetAppliedSubst()) @@ -194,18 +198,18 @@ func (ds *destructiveSearch) passSubstToParent(args wcdArgs, proofChildren [][]P return err } - cleaned := Core.RemoveElementWithoutMM(merged.GetSubst().Copy(), args.st.GetMM()) + cleaned := Core.RemoveElementWithoutMM(merged.GetSubst(), args.st.GetMM()) substAndFormCleaned := Core.MakeSubstAndForm(cleaned, subst.GetForm()) // If the cleaned subst is empty, we don't need to do anything. // Otherwise, we have to check if the cleaned substitution is already in the resulting substs list // and, if applicable, add the formula to the list of substituted formulas. // It is useful for the nondestructive mode, to store with which formula the contradiction has been found. - if !cleaned.IsEmpty() { + if !cleaned.Empty() { // Check if the new substitution is already in the list, merge formulas added := false - for i := 0; !added && i < len(resultingSubsts); i++ { - if resultingSubstsAndForms[i].GetSubst().Equals(cleaned) { + for i := 0; !added && i < resultingSubsts.Len(); i++ { + if Lib.ListEquals(resultingSubstsAndForms[i].GetSubst(), cleaned) { added = true resultingSubstsAndForms[i] = resultingSubstsAndForms[i].AddFormulas(subst.GetForm()) } @@ -213,7 +217,7 @@ func (ds *destructiveSearch) passSubstToParent(args wcdArgs, proofChildren [][]P if !added { resultingSubstsAndForms = append(resultingSubstsAndForms, substAndFormCleaned.Copy()) - resultingSubsts = append(resultingSubsts, substAndFormCleaned.GetSubst()) + resultingSubsts.Append(substAndFormCleaned.GetSubst()) } newMetas = Glob.UnionIntList(newMetas, retrieveMetaFromSubst(cleaned)) @@ -278,7 +282,9 @@ func (ds *destructiveSearch) manageOpenedChild(args wcdArgs) { // If the completeness mode is active, then we need to deal with forbidden substitutions. if Glob.GetCompleteness() { - args.st.SetForbiddenSubsts(Unif.AddSubstToSubstitutionsList(args.st.GetForbiddenSubsts(), args.currentSubst.GetSubst())) + forbidden := args.st.GetForbiddenSubsts() + forbidden.Add(Lib.ListEquals[Unif.MixedSubstitution], args.currentSubst.GetSubst()) + args.st.SetForbiddenSubsts(forbidden) } if args.st.GetBTOnFormulas() && len(args.formsBT) > 0 { diff --git a/src/Search/children.go b/src/Search/children.go index 4e94c0b7..c83a2846 100644 --- a/src/Search/children.go +++ b/src/Search/children.go @@ -63,7 +63,7 @@ type Result struct { closed, need_answer bool subst_for_children Core.SubstAndForm subst_list_for_father []Core.SubstAndForm - forbidden []Unif.Substitutions + forbidden Lib.List[Lib.List[Unif.MixedSubstitution]] proof []ProofStruct node_id int original_node_id int @@ -85,8 +85,8 @@ func (r Result) getSubstForChildren() Core.SubstAndForm { func (r Result) getSubstListForFather() []Core.SubstAndForm { return Core.CopySubstAndFormList(r.subst_list_for_father) } -func (r Result) getForbiddenSubsts() []Unif.Substitutions { - return Unif.CopySubstList(r.forbidden) +func (r Result) getForbiddenSubsts() Lib.List[Lib.List[Unif.MixedSubstitution]] { + return r.forbidden.Copy(Lib.ListCpy[Unif.MixedSubstitution]) } func (r Result) getProof() []ProofStruct { return CopyProofStructList(r.proof) @@ -164,12 +164,19 @@ func sendSubToChildren(children []Communication, s Core.SubstAndForm) { debug( Lib.MkLazy(func() string { return fmt.Sprintf("children : %v/%v", i+1, len(children)) }), ) - v.result <- Result{Glob.GetGID(), true, true, s.Copy(), []Core.SubstAndForm{}, Unif.MakeEmptySubstitutionList(), nil, -1, -1, Core.MakeUnifier()} + v.result <- Result{ + Glob.GetGID(), + true, + true, + s.Copy(), + []Core.SubstAndForm{}, + Lib.NewList[Lib.List[Unif.MixedSubstitution]](), + nil, -1, -1, Core.MakeUnifier()} } } /* Send a substitution to a list of child */ -func sendForbiddenToChildren(children []Communication, s []Unif.Substitutions) { +func sendForbiddenToChildren(children []Communication, s Lib.List[Lib.List[Unif.MixedSubstitution]]) { debug( Lib.MkLazy(func() string { return fmt.Sprintf("Send forbidden to children : %v", len(children)) }), ) @@ -187,8 +194,8 @@ func (ds *destructiveSearch) sendSubToFather(c Communication, closed, need_answe debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Send subst to father : %v, closed : %v, need answer : %v", - Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(subst_for_father)), + "Send subst to father : %s, closed : %v, need answer : %v", + Unif.SubstsToString(Core.GetSubstListFromSubstAndFormList(subst_for_father)), closed, need_answer) }), ) @@ -219,7 +226,14 @@ func (ds *destructiveSearch) sendSubToFather(c Communication, closed, need_answe ) select { - case c.result <- Result{Glob.GetGID(), closed, need_answer, Core.MakeEmptySubstAndForm(), Core.CopySubstAndFormList(subst_for_father), Unif.MakeEmptySubstitutionList(), st.GetProof(), node_id, original_node_id, st.GetGlobUnifier()}: + case c.result <- Result{ + Glob.GetGID(), + closed, + need_answer, + Core.MakeEmptySubstAndForm(), + Core.CopySubstAndFormList(subst_for_father), + Lib.NewList[Lib.List[Unif.MixedSubstitution]](), + st.GetProof(), node_id, original_node_id, st.GetGlobUnifier()}: if need_answer { ds.waitFather(father_id, st, c, Core.FusionSubstAndFormListWithoutDouble(subst_for_father, given_substs), node_id, original_node_id, []int{}, meta_to_reintroduce) } else { diff --git a/src/Search/destructive.go b/src/Search/destructive.go index ba555609..963711aa 100644 --- a/src/Search/destructive.go +++ b/src/Search/destructive.go @@ -62,7 +62,7 @@ type BasicSearchAlgorithm interface { ProofSearch(uint64, State, Communication, Core.SubstAndForm, int, int, []int, bool) DoEndManageBeta(uint64, State, Communication, []Communication, int, int, []int, []int) manageRewriteRules(uint64, State, Communication, Core.FormAndTermsList, int, int, []int) - ManageClosureRule(uint64, *State, Communication, []Unif.Substitutions, Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) + ManageClosureRule(uint64, *State, Communication, Lib.List[Lib.List[Unif.MixedSubstitution]], Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) manageResult(c Communication) (Core.Unifier, []ProofStruct, bool) } @@ -142,7 +142,7 @@ func (ds *destructiveSearch) doOneStep(limit int, formula AST.Form) (bool, int) PrintSearchResult(result) } - if unif := unifier.GetUnifier(); !unif.IsEmpty() { + if unif := unifier.GetUnifier(); !unif.Empty() { finalProof = ApplySubstitutionOnProofList(unif, finalProof) } uninstanciatedMeta := RetrieveUninstantiatedMetaFromProof(finalProof) @@ -176,9 +176,9 @@ func (ds *destructiveSearch) chooseSubstitutionDestructive(subst_list []Core.Sub i := 0 saved_i := 0 - // Choix de la subst - celle qui ne contient pas de MM, ou la première + // Choose either a subst that does not contain any meta from the parents, or a random one for i < len(subst_list)-1 && !found { - if !Core.ContainsMetaMother((subst_list)[i].GetSubst(), mm) { + if !Core.ContainsMetaMother(subst_list[i].GetSubst(), mm) { subst_found = subst_list[i] saved_i = i found = true @@ -193,7 +193,7 @@ func (ds *destructiveSearch) chooseSubstitutionDestructive(subst_list []Core.Sub subst_found = subst_found.Copy() } - // Maj subst_list avec les subst restantes pour le BT + // Remember the substs for backtracking if len(subst_list) > 1 { subst_list[saved_i] = subst_list[len(subst_list)-1] subst_list = subst_list[:len(subst_list)-1] @@ -214,7 +214,15 @@ func (ds *destructiveSearch) searchContradictionAfterApplySusbt(father_id uint64 ) // Check if exists a contradiction after applying the substitution if res, subst := ApplyClosureRules(f.GetForm(), &st); res { - ds.ManageClosureRule(father_id, &st, cha, Unif.CopySubstList(subst), f.Copy(), node_id, original_node_id) + ds.ManageClosureRule( + father_id, + &st, + cha, + subst.Copy(Lib.ListCpy[Unif.MixedSubstitution]), + f.Copy(), + node_id, + original_node_id, + ) return true } } @@ -233,7 +241,12 @@ func (ds *destructiveSearch) searchContradiction(atomic AST.Form, father_id uint fAt := Core.MakeFormAndTerm(atomic, Lib.MkList[AST.Term](0)) if clos_res { - ds.ManageClosureRule(father_id, &st, cha, Unif.CopySubstList(subst), fAt, node_id, original_node_id) + ds.ManageClosureRule( + father_id, + &st, + cha, + subst.Copy(Lib.ListCpy[Unif.MixedSubstitution]), + fAt, node_id, original_node_id) return true } return false @@ -299,7 +312,8 @@ func (ds *destructiveSearch) ProofSearch(father_id uint64, st State, cha Communi Lib.MkLazy(func() string { return fmt.Sprintf( "Current substitutions list: %v", - Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound()))) + Unif.SubstsToString(Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound())), + ) }), ) } @@ -313,7 +327,12 @@ func (ds *destructiveSearch) ProofSearch(father_id uint64, st State, cha Communi for _, f := range st.GetLF() { if Core.ShowKindOfRule(f.GetForm()) == Core.Atomic { if searchObviousClosureRule(f.GetForm()) { - ds.ManageClosureRule(father_id, &st, cha, []Unif.Substitutions{}, f, node_id, original_node_id) + ds.ManageClosureRule( + father_id, + &st, + cha, + Lib.NewList[Lib.List[Unif.MixedSubstitution]](), + f, node_id, original_node_id) return } step_atomics = append(step_atomics, f) @@ -427,7 +446,8 @@ func (ds *destructiveSearch) waitChildren(args wcdArgs) { Lib.MkLazy(func() string { return fmt.Sprintf( "Current substs : %v", - args.currentSubst.GetSubst().ToString()) + Lib.ListToString(args.currentSubst.GetSubst(), ", ", "[]"), + ) }), ) status, substs, proofs, unifiers := ds.selectChildren(args.c, &args.children, args.currentSubst, args.childOrdering) @@ -502,12 +522,12 @@ func (ds *destructiveSearch) waitFather(father_id uint64, st State, c Communicat ) // Check if the subst was already seen, returns eventually the subst with new formula(s) - if Unif.ContainsSubst(Core.GetSubstListFromSubstAndFormList(given_substs), answer_father.subst_for_children.GetSubst()) { + if Core.GetSubstListFromSubstAndFormList(given_substs).Contains(answer_father.subst_for_children.GetSubst(), Lib.ListEquals[Unif.MixedSubstitution]) { debug( Lib.MkLazy(func() string { return "This substitution was sent by this child" }), ) for _, subst_sent := range given_substs { - if subst_sent.GetSubst().Equals(answer_father.subst_for_children.GetSubst()) { + if Lib.ListEquals(subst_sent.GetSubst(), answer_father.subst_for_children.GetSubst()) { subst = answer_father.getSubstForChildren().AddFormulas(subst_sent.GetForm()) } } @@ -530,21 +550,23 @@ func (ds *destructiveSearch) waitFather(father_id uint64, st State, c Communicat x1 := x.MakeDataStruct(x2, false) st.SetTreeNeg(x1) - // Maj forbidden - if len(answer_father.forbidden) > 0 { + // Update forbidden + if answer_father.forbidden.Len() > 0 { debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Forbidden received : %v", - Unif.SubstListToString(answer_father.getForbiddenSubsts())) + "Forbidden received : %s", + Unif.SubstsToString(answer_father.getForbiddenSubsts()), + ) }), ) st.SetForbiddenSubsts(answer_father.getForbiddenSubsts()) debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "New forbidden fo this state : %v", - Unif.SubstListToString(st.GetForbiddenSubsts())) + "New forbidden for this state: %s", + Unif.SubstsToString(st.GetForbiddenSubsts()), + ) }), ) } else { @@ -598,13 +620,14 @@ func (ds *destructiveSearch) waitFather(father_id uint64, st State, c Communicat debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Apply substitution on myself and wait : %v", - answer_father.getSubstForChildren().GetSubst().ToString()) + "Apply substitution on myself and wait : %s", + Lib.ListToString(answer_father.getSubstForChildren().GetSubst(), ", ", "[]"), + ) }), ) debug( Lib.MkLazy(func() string { - return fmt.Sprintf("Forbidden : %v", Unif.SubstListToString(st_copy.GetForbiddenSubsts())) + return fmt.Sprintf("Forbidden : %s", Unif.SubstsToString(st_copy.GetForbiddenSubsts())) }), ) go ds.ProofSearch(Glob.GetGID(), st_copy, c2, answer_father.getSubstForChildren(), node_id, original_node_id, new_meta_to_reintroduce, false) @@ -740,7 +763,8 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co }), ) - if len(res.subst_list_for_father) == 1 && res.subst_list_for_father[0].GetSubst().Equals(current_subst.GetSubst()) { + if len(res.subst_list_for_father) == 1 && + Lib.ListEquals(res.subst_list_for_father[0].GetSubst(), current_subst.GetSubst()) { debug( Lib.MkLazy(func() string { return fmt.Sprintf( @@ -758,12 +782,18 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co // Check if there is common substitutions for _, current_subst_from_children := range res.subst_list_for_father { for i := range result_subst { - if current_subst_from_children.GetSubst().Equals(result_subst[i].GetSubst()) { + if Lib.ListEquals( + current_subst_from_children.GetSubst(), + result_subst[i].GetSubst(), + ) { debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Subst in common found : %v !", - current_subst_from_children.GetSubst().ToString()) + "Subst in common found : %s !", + Lib.ListToString( + current_subst_from_children.GetSubst(), + ", ", "[]"), + ) }), ) common_substs = append(common_substs, result_subst[i].AddFormulas(current_subst_from_children.GetForm())) @@ -780,17 +810,20 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co v.ToString()) }), ) - if !v.GetSubst().Equals(new_current_subst.GetSubst()) { + if !Lib.ListEquals(v.GetSubst(), new_current_subst.GetSubst()) { added := false debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Result_subst :%v", - Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(result_subst))) + "Result_subst :%s", + Unif.SubstsToString( + Core.GetSubstListFromSubstAndFormList(result_subst), + ), + ) }), ) for i := range result_subst { - if v.GetSubst().Equals(result_subst[i].GetSubst()) { + if Lib.ListEquals(v.GetSubst(), result_subst[i].GetSubst()) { added = true debug( Lib.MkLazy(func() string { return "Subst already in result_subst" }), @@ -811,9 +844,11 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "New result susbt : %v", - Unif.SubstListToString( - Core.GetSubstListFromSubstAndFormList(result_subst))) + "New result susbt : %s", + Unif.SubstsToString( + Core.GetSubstListFromSubstAndFormList(result_subst), + ), + ) }), ) } @@ -869,7 +904,7 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co if !new_current_subst.IsEmpty() { new_result_subst := []Core.SubstAndForm{} for _, s := range result_subst { - if !s.GetSubst().Equals(new_current_subst.GetSubst()) { + if !Lib.ListEquals(s.GetSubst(), new_current_subst.GetSubst()) { err, new_subst := Core.MergeSubstAndForm(s.Copy(), new_current_subst.Copy()) if err != nil { @@ -884,8 +919,9 @@ func (ds *destructiveSearch) selectChildren(father Communication, children *[]Co debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "New subst at the end : %v", - Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(result_subst))) + "New subst at the end : %s", + Unif.SubstsToString(Core.GetSubstListFromSubstAndFormList(result_subst)), + ) }), ) default: @@ -965,7 +1001,7 @@ func (ds *destructiveSearch) tryRewrite(rewritten []Core.IntSubstAndForm, f Core newRewritten := []Core.IntSubstAndFormAndTerms{} for _, isaf := range rewritten { newFNTs := Core.MakeEmptyFormAndTermsList() - for _, isaf_f := range isaf.GetSaf().GetForm().Slice() { + for _, isaf_f := range isaf.GetSaf().GetForm().GetSlice() { newFNTs = append(newFNTs, Core.MakeFormAndTerm(isaf_f, f.GetTerms())) } newRewritten = append(newRewritten, Core.MakeIntSubstAndFormAndTerms(isaf.GetId_rewrite(), Core.MakeSubstAndFormAndTerms(isaf.GetSaf().GetSubst(), newFNTs))) @@ -978,8 +1014,10 @@ func (ds *destructiveSearch) tryRewrite(rewritten []Core.IntSubstAndForm, f Core newRewritten = Core.CopyIntSubstAndFormAndTermsList(newRewritten[1:]) // If we didn't rewrite as itself ? - if !choosenRewritten.GetSaf().GetSubst().Equals(Unif.Failure()) { - // Create a child with the current rewriting rule and make this process to wait for him, with a list of other subst to try + if Unif.UnifSucceeded(choosenRewritten.GetSaf().GetSubst()) { + // Create a child with the current rewriting rule and make this process to wait for him, + // with a list of other subst to try + // all atomics but not the chosen one state.SetLF(append(remainingAtomics.Copy(), choosenRewrittenForm.Copy())) state.SetBTOnFormulas(true) // I need to know that I can bt on form and my child needs to know it to to don't loop @@ -992,7 +1030,7 @@ func (ds *destructiveSearch) tryRewrite(rewritten []Core.IntSubstAndForm, f Core state.SetCurrentProofRuleName("Rewrite") state.SetCurrentProofIdDMT(choosenRewritten.GetId_rewrite()) - if choosenRewritten.GetSaf().GetSubst().IsEmpty() { + if choosenRewritten.GetSaf().GetSubst().Empty() { choosenRewritten = Core.MakeEmptyIntSubstAndFormAndTerms() } @@ -1017,24 +1055,32 @@ func (ds *destructiveSearch) tryRewrite(rewritten []Core.IntSubstAndForm, f Core } } -//ILL TODO Clean the following function and be careful with the Coq output. /** * clos_res and subst are the result of applyClosureRule. * Manage this result, dispatch the subst and recreate data structures. * Return if the branch is closed without variable from its father **/ -func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Communication, substs []Unif.Substitutions, f Core.FormAndTerms, node_id int, original_node_id int) (bool, []Core.SubstAndForm) { +func (ds *destructiveSearch) ManageClosureRule( + father_id uint64, + st *State, + c Communication, + substs Lib.List[Lib.List[Unif.MixedSubstitution]], + f Core.FormAndTerms, + node_id int, + original_node_id int, +) (bool, []Core.SubstAndForm) { mm := st.GetMM().Copy() subst := st.GetAppliedSubst().GetSubst() mm = mm.Union(Core.GetMetaFromSubst(subst)) - substs_with_mm, substs_with_mm_uncleared, substs_without_mm := Core.DispatchSubst(Unif.CopySubstList(substs), mm) + substs_with_mm, substs_with_mm_uncleared, substs_without_mm := + Core.DispatchSubst(substs.Copy(Lib.ListCpy[Unif.MixedSubstitution]), mm) unifier := st.GetGlobUnifier() appliedSubst := st.GetAppliedSubst().GetSubst() switch { - case len(substs) == 0: + case substs.Empty(): debug( Lib.MkLazy(func() string { return "Branch closed by ¬⊤ or ⊥ or a litteral and its opposite!" }), ) @@ -1061,24 +1107,27 @@ func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Co ds.sendSubToFather(c, true, false, Glob.GetGID(), *st, []Core.SubstAndForm{}, node_id, original_node_id, []int{}) } - case len(substs_without_mm) > 0: + case !substs_without_mm.Empty(): debug( Lib.MkLazy(func() string { return fmt.Sprintf( "Contradiction found (without mm) : %v", - Unif.SubstListToString(substs_without_mm)) + Unif.SubstsToString(substs_without_mm)) }), ) - if Glob.GetAssisted() && !substs_without_mm[0].IsEmpty() { + if Glob.GetAssisted() && !substs_without_mm.At(0).Empty() { fmt.Printf("The branch can be closed by using a substitution which has no impact elsewhere!\nApplying it automatically : ") - fmt.Printf("%v !\n", Unif.SubstListToString(substs_without_mm)) + fmt.Printf("%v !\n", Unif.SubstsToString(substs_without_mm)) } st.SetSubstsFound([]Core.SubstAndForm{st.GetAppliedSubst()}) // Proof - st.SetCurrentProofRule(fmt.Sprintf("⊙ / %v", substs_without_mm[0].ToString())) + st.SetCurrentProofRule(fmt.Sprintf( + "⊙ / %s", + Lib.ListToString(substs_without_mm.At(0), ", ", "(empty subst)"), + )) st.SetCurrentProofRuleName("CLOSURE") st.SetCurrentProofFormula(f.Copy()) st.SetCurrentProofNodeId(node_id) @@ -1086,8 +1135,8 @@ func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Co st.SetProof(append(st.GetProof(), st.GetCurrentProof())) // As no MM is involved, these substitutions can be unified with all the others having an empty subst. - for _, subst := range substs_without_mm { - merge, _ := Unif.MergeSubstitutions(appliedSubst, subst) + for _, subst := range substs_without_mm.GetSlice() { + merge, _ := Unif.MergeMixedSubstitutions(appliedSubst, subst) unifier.AddSubstitutions(appliedSubst, merge) } st.SetGlobUnifier(unifier) @@ -1095,12 +1144,12 @@ func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Co ds.sendSubToFather(c, true, false, Glob.GetGID(), *st, []Core.SubstAndForm{}, node_id, original_node_id, []int{}) } - case len(substs_with_mm) > 0: + case !substs_with_mm.Empty(): debug( Lib.MkLazy(func() string { return "Contradiction found (with mm) !" }), ) - // TODO : REMOVE vu qu fait dans wait father ? + // FIXME: should this be removed as it's done in WaitForFather? st.SetCurrentProofRule("⊙") st.SetCurrentProofRuleName("CLOSURE") st.SetCurrentProofFormula(f.Copy()) @@ -1109,17 +1158,20 @@ func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Co st.SetProof(append(st.GetProof(), st.GetCurrentProof())) meta_to_reintroduce := []int{} - for _, subst_for_father := range substs_with_mm { - // Check if subst_for_father is failure - if subst_for_father.Equals(Unif.Failure()) { - Glob.PrintError("MCR", fmt.Sprintf("Error : SubstForFather is failure between : %v and %v \n", subst_for_father.ToString(), st.GetAppliedSubst().ToString())) + for _, subst_for_father := range substs_with_mm.GetSlice() { + if !Unif.UnifSucceeded(subst_for_father) { + Glob.PrintError("MCR", fmt.Sprintf( + "Error : SubstForFather is failure between : %s and %s \n", + Lib.ListToString(subst_for_father, ", ", "(empty substs)"), + st.GetAppliedSubst().ToString()), + ) } debug( Lib.MkLazy(func() string { return fmt.Sprintf("Formula = : %v", f.ToString()) }), ) // Create substAndForm with the current form and the subst found - subst_and_form_for_father := Core.MakeSubstAndForm(subst_for_father, AST.NewFormList(f.GetForm())) + subst_and_form_for_father := Core.MakeSubstAndForm(subst_for_father, Lib.MkListV(f.GetForm())) debug( Lib.MkLazy(func() string { @@ -1155,17 +1207,19 @@ func (ds *destructiveSearch) ManageClosureRule(father_id uint64, st *State, c Co debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Send subst(s) with mm to father : %v", - Unif.SubstListToString( - Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound()))) + "Send subst(s) with mm to father : %s", + Unif.SubstsToString( + Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound()), + ), + ) }), ) sort.Ints(meta_to_reintroduce) // Add substs_with_mm found with the corresponding subst - for i, subst := range substs_with_mm { - mergeUncleared, _ := Unif.MergeSubstitutions(appliedSubst, substs_with_mm_uncleared[i]) - mergeCleared, _ := Unif.MergeSubstitutions(appliedSubst, subst) + for i, subst := range substs_with_mm.GetSlice() { + mergeUncleared, _ := Unif.MergeMixedSubstitutions(appliedSubst, substs_with_mm_uncleared.At(i)) + mergeCleared, _ := Unif.MergeMixedSubstitutions(appliedSubst, subst) unifier.AddSubstitutions(mergeCleared, mergeUncleared) } st.SetGlobUnifier(unifier) diff --git a/src/Search/exchanges.go b/src/Search/exchanges.go index 4e680f17..84663d2d 100644 --- a/src/Search/exchanges.go +++ b/src/Search/exchanges.go @@ -83,7 +83,13 @@ func ResetExchangesFile() { } } -func makeJsonExchanges(father_uint uint64, st State, ss_subst []Unif.Substitutions, subst_received Unif.Substitutions, calling_function string) exchanges_struct { +func makeJsonExchanges( + father_uint uint64, + st State, + ss_subst Lib.List[Lib.List[Unif.MixedSubstitution]], + subst_received Lib.List[Unif.MixedSubstitution], + calling_function string, +) exchanges_struct { // ID id_process := Glob.GetGID() id := int(id_process) @@ -109,16 +115,16 @@ func makeJsonExchanges(father_uint uint64, st State, ss_subst []Unif.Substitutio // Subt sr := "" - if len(st.GetAppliedSubst().GetSubst()) > 0 { - sr += st.GetAppliedSubst().GetSubst().ToString() + if !st.GetAppliedSubst().GetSubst().Empty() { + sr += Lib.ListToString(st.GetAppliedSubst().GetSubst(), ", ", "(empty subst)") } - if len(subst_received) > 0 { - sr += subst_received.ToString() + if !subst_received.Empty() { + sr += Lib.ListToString(subst_received, ", ", "(empty subst)") } ss := "" - if len(ss_subst) > 0 { - ss += Unif.SubstListToString(ss_subst) + if !ss_subst.Empty() { + ss += Unif.SubstsToString(ss_subst) } // fmt.Printf("Id = %v, version = %v, father = %v, forms = %v, mm = %v, mc = %v, ss = %v, sr = %v\n", id, version, father, forms, mm, mc, ss, sr) @@ -135,7 +141,9 @@ func WriteExchanges(father uint64, st State, sub_sent []Core.SubstAndForm, subst } else { file_exchanges.WriteString("[\n") } - json_content := makeJsonExchanges(father, st, Core.RemoveEmptySubstFromSubstList(Core.GetSubstListFromSubstAndFormList(sub_sent)), subst_received.GetSubst(), calling_function) + json_content := makeJsonExchanges(father, st, + Core.RemoveEmptySubstFromSubstList(Core.GetSubstListFromSubstAndFormList(sub_sent)), + subst_received.GetSubst(), calling_function) json_string, _ := json.MarshalIndent(json_content, "", " ") file_exchanges.Write(json_string) mutex_file_exchanges.Unlock() diff --git a/src/Search/incremental/rules.go b/src/Search/incremental/rules.go index 4fffd124..73ac26a0 100644 --- a/src/Search/incremental/rules.go +++ b/src/Search/incremental/rules.go @@ -203,7 +203,7 @@ func (aa *AlphaAnd) apply() []RuleList { switch form := aa.GetForm().(type) { case AST.And: - for _, subForm := range form.FormList.Slice() { + for _, subForm := range form.GetChildFormulas().GetSlice() { resultRules = append(resultRules, makeCorrectRule(subForm, aa.GetTerms())) } } @@ -242,7 +242,7 @@ func (ano *AlphaNotOr) apply() []RuleList { case AST.Not: switch subForm := form.GetForm().(type) { case AST.Or: - for _, subForm := range subForm.FormList.Slice() { + for _, subForm := range subForm.GetChildFormulas().GetSlice() { resultRules = append(resultRules, makeCorrectRule(AST.MakerNot(subForm), ano.GetTerms())) } } @@ -283,7 +283,7 @@ func (bna *BetaNotAnd) apply() []RuleList { case AST.Not: switch subForm := form.GetForm().(type) { case AST.And: - for _, andForm := range subForm.FormList.Slice() { + for _, andForm := range subForm.GetChildFormulas().GetSlice() { resultRulesBeta = append(resultRulesBeta, RuleList{makeCorrectRule(AST.MakerNot(andForm), bna.GetTerms())}) } } @@ -326,7 +326,7 @@ func (bo *BetaOr) apply() []RuleList { switch form := bo.GetForm().(type) { case AST.Or: - for _, subForm := range form.FormList.Slice() { + for _, subForm := range form.GetChildFormulas().GetSlice() { resultRulesBeta = append(resultRulesBeta, RuleList{makeCorrectRule(subForm, bo.GetTerms())}) } } @@ -412,13 +412,13 @@ func (gne *GammaNotExists) getGeneratedMetas() Lib.List[AST.Meta] { return gne.generatedMetas } -func (gne *GammaNotExists) getVarList() []AST.Var { +func (gne *GammaNotExists) getVarList() Lib.List[AST.TypedVar] { if not, isNot := gne.formula.(AST.Not); isNot { if exists, isExists := not.GetForm().(AST.Ex); isExists { return exists.GetVarList() } } - return []AST.Var{} + return Lib.NewList[AST.TypedVar]() } type GammaForall struct { @@ -453,11 +453,11 @@ func (gf *GammaForall) getGeneratedMetas() Lib.List[AST.Meta] { return gf.generatedMetas } -func (gf *GammaForall) getVarList() []AST.Var { +func (gf *GammaForall) getVarList() Lib.List[AST.TypedVar] { if forall, isForall := gf.formula.(AST.All); isForall { return forall.GetVarList() } - return []AST.Var{} + return Lib.NewList[AST.TypedVar]() } type DeltaNotForall struct { @@ -500,8 +500,8 @@ func (de *DeltaExists) apply() []RuleList { type RuleList []Rule -func (rl *RuleList) GetFormList() *AST.FormList { - result := AST.NewFormList() +func (rl *RuleList) GetFormList() Lib.List[AST.Form] { + result := Lib.NewList[AST.Form]() for _, rule := range *rl { result.Append(rule.GetForm()) diff --git a/src/Search/incremental/rulesManager.go b/src/Search/incremental/rulesManager.go index 330a9b6c..3daec84f 100644 --- a/src/Search/incremental/rulesManager.go +++ b/src/Search/incremental/rulesManager.go @@ -189,7 +189,7 @@ func (rm *RulesManager) trySubstitutionClosureRules() (applied Rule, subs SubLis negTree := new(Unif.Node).MakeDataStruct(negativeRules.GetFormList(), false) - substitutions := []Unif.MatchingSubstitutions{} + substitutions := []Unif.MixedSubstitutions{} for _, posRule := range positiveRules { success, currentSubst := negTree.Unify(posRule.GetForm()) @@ -200,7 +200,7 @@ func (rm *RulesManager) trySubstitutionClosureRules() (applied Rule, subs SubLis } for _, substitution := range substitutions { - subs = append(subs, NewFromOldSub(substitution)) + subs = append(subs, NewFromOldSub(substitution.MatchingSubstitutions())) } return applied, subs @@ -255,22 +255,22 @@ func (rm *RulesManager) ToString() string { str := "~~~~Rule Manager~~~~\n" if len(rm.atomicRules) > 0 { - str += "| Atomic Rules: " + rm.atomicRules.GetFormList().ToString() + "\n" + str += "| Atomic Rules: " + Lib.ListToString(rm.atomicRules.GetFormList(), ", ", "[]") + "\n" } if len(rm.atomicNotRules) > 0 { - str += "| Negative Atomic Rules: " + rm.atomicNotRules.GetFormList().ToString() + "\n" + str += "| Negative Atomic Rules: " + Lib.ListToString(rm.atomicNotRules.GetFormList(), ", ", "[]") + "\n" } if len(rm.alphaRules) > 0 { - str += "| Alpha Rules: " + rm.alphaRules.GetFormList().ToString() + "\n" + str += "| Alpha Rules: " + Lib.ListToString(rm.alphaRules.GetFormList(), ", ", "[]") + "\n" } if len(rm.deltaRules) > 0 { - str += "| Delta Rules: " + rm.deltaRules.GetFormList().ToString() + "\n" + str += "| Delta Rules: " + Lib.ListToString(rm.deltaRules.GetFormList(), ", ", "[]") + "\n" } if len(rm.betaRules) > 0 { - str += "| Beta Rules: " + rm.betaRules.GetFormList().ToString() + "\n" + str += "| Beta Rules: " + Lib.ListToString(rm.betaRules.GetFormList(), ", ", "[]") + "\n" } if len(rm.gammaRules) > 0 { - str += "| Gamma Rules: " + rm.gammaRules.GetFormList().ToString() + "\n" + str += "| Gamma Rules: " + Lib.ListToString(rm.gammaRules.GetFormList(), ", ", "[]") + "\n" } if len(rm.reintroRules.reintroRules) > 0 { str += "| Reintro Rules: " + rm.reintroRules.ToString() + "\n" diff --git a/src/Search/incremental/search.go b/src/Search/incremental/search.go index a052eec6..defc4795 100644 --- a/src/Search/incremental/search.go +++ b/src/Search/incremental/search.go @@ -42,7 +42,7 @@ func (is *incrementalSearch) SetApplyRules(func(uint64, Search.State, Search.Com } // ManageClosureRule implements Search.SearchAlgorithm. -func (is *incrementalSearch) ManageClosureRule(uint64, *Search.State, Search.Communication, []Unif.Substitutions, Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) { +func (is *incrementalSearch) ManageClosureRule(uint64, *Search.State, Search.Communication, Lib.List[Lib.List[Unif.MixedSubstitution]], Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) { Glob.PrintError("NDS", "Incremental search not compatible with the equality plugin for now.") return false, []Core.SubstAndForm{} } diff --git a/src/Search/nonDestructiveSearch.go b/src/Search/nonDestructiveSearch.go index 46c70f2b..55c0b275 100644 --- a/src/Search/nonDestructiveSearch.go +++ b/src/Search/nonDestructiveSearch.go @@ -54,6 +54,17 @@ func NewNonDestructiveSearch() BasicSearchAlgorithm { return nil } +func getMetas(substs Lib.List[Unif.MixedSubstitution]) Lib.List[AST.Meta] { + metas := Lib.NewList[AST.Meta]() + for _, subst := range substs.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + metas.Append(s.Val.Key()) + } + } + return metas +} + func (nds *nonDestructiveSearch) setApplyRules(function func(uint64, State, Communication, Core.FormAndTermsList, int, int, []int)) { Glob.PrintError("NDS", "Non-destructive search not compatible with the assisted plugin for now.") } @@ -69,7 +80,7 @@ func (nds *nonDestructiveSearch) manageRewriteRules(fatherId uint64, state State /* Choose substitution - whitout meta in lastAppliedSubst */ func (nds *nonDestructiveSearch) chooseSubstitutionWithoutMetaLastApplyNonDestructive(sl []Core.SubstAndForm, ml Lib.List[AST.Meta]) (Core.SubstAndForm, []Core.SubstAndForm) { for i, v := range sl { - if !AST.IsIncludeInsideOF(v.GetSubst().GetMeta(), ml) { + if !AST.IsIncludeInsideOF(getMetas(v.GetSubst()), ml) { return v, Core.RemoveSubstFromSubstAndFormList(i, sl) } } @@ -79,7 +90,7 @@ func (nds *nonDestructiveSearch) chooseSubstitutionWithoutMetaLastApplyNonDestru /* Choose substitution - whith meta in lastAppliedSubst */ func (nds *nonDestructiveSearch) chooseSubstitutionWithtMetaLastApplyNonDestructive(sl []Core.SubstAndForm, last_applied_subst Core.SubstAndForm) (Core.SubstAndForm, []Core.SubstAndForm) { for i, v := range sl { - if !v.GetSubst().Equals(last_applied_subst.GetSubst()) { + if !Lib.ListEquals(v.GetSubst(), last_applied_subst.GetSubst()) { return v, Core.RemoveSubstFromSubstAndFormList(i, sl) } } @@ -88,12 +99,12 @@ func (nds *nonDestructiveSearch) chooseSubstitutionWithtMetaLastApplyNonDestruct /* Choose the best substitution among subst_found_at_this_step and subst_found */ func (nds *nonDestructiveSearch) chooseSubstitutionNonDestructive(substs_found_this_step []Core.SubstAndForm, st *State) Core.SubstAndForm { - res, sl := nds.chooseSubstitutionWithoutMetaLastApplyNonDestructive(substs_found_this_step, st.GetLastAppliedSubst().GetSubst().GetMeta()) + res, sl := nds.chooseSubstitutionWithoutMetaLastApplyNonDestructive(substs_found_this_step, getMetas(st.GetLastAppliedSubst().GetSubst())) if !res.IsEmpty() { // subst without meta in last applied meta found in substs_found_at_this_step st.SetSubstsFound(append(sl, st.GetSubstsFound()...)) return res } else { - res, sl = nds.chooseSubstitutionWithoutMetaLastApplyNonDestructive(st.GetSubstsFound(), st.GetLastAppliedSubst().GetSubst().GetMeta()) + res, sl = nds.chooseSubstitutionWithoutMetaLastApplyNonDestructive(st.GetSubstsFound(), getMetas(st.GetLastAppliedSubst().GetSubst())) if !res.IsEmpty() { // subst without meta in last applied meta found in substs_found st.SetSubstsFound(append(sl, substs_found_this_step...)) return res @@ -121,16 +132,19 @@ func (nds *nonDestructiveSearch) chooseSubstitutionNonDestructive(substs_found_t } /* Take a substitution, returns the id of the formula which introduce the metavariable */ -func (nds *nonDestructiveSearch) catchFormulaToInstantiate(subst_found Unif.Substitutions) int { +func (nds *nonDestructiveSearch) catchFormulaToInstantiate(subst_found Lib.List[Unif.MixedSubstitution]) int { meta_to_reintroduce := -1 - for _, subst := range subst_found { - meta, term := subst.Get() - if meta.GetFormula() < meta_to_reintroduce || meta_to_reintroduce == -1 { - meta_to_reintroduce = meta.GetFormula() - } - if term.IsMeta() { - if term.ToMeta().GetFormula() < meta_to_reintroduce || meta_to_reintroduce == -1 { - meta_to_reintroduce = term.ToMeta().GetFormula() + for _, subst := range subst_found.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + meta, term := s.Val.Get() + if meta.GetFormula() < meta_to_reintroduce || meta_to_reintroduce == -1 { + meta_to_reintroduce = meta.GetFormula() + } + if term.IsMeta() { + if term.ToMeta().GetFormula() < meta_to_reintroduce || meta_to_reintroduce == -1 { + meta_to_reintroduce = term.ToMeta().GetFormula() + } } } } @@ -142,7 +156,12 @@ func (nds *nonDestructiveSearch) catchFormulaToInstantiate(subst_found Unif.Subs **/ func (nds *nonDestructiveSearch) instantiate(fatherId uint64, state *State, c Communication, index int, s Core.SubstAndForm) { debug( - Lib.MkLazy(func() string { return fmt.Sprintf("Instantiate with subst : %v ", s.GetSubst().ToString()) }), + Lib.MkLazy(func() string { + return fmt.Sprintf( + "Instantiate with subst : %s", + Lib.ListToString(s.GetSubst(), ", ", "(empty subst)"), + ) + }), ) newMetaGenerator := state.GetMetaGen() reslf := Core.ReintroduceMeta(&newMetaGenerator, index, state.GetN()) @@ -180,7 +199,7 @@ func (nds *nonDestructiveSearch) instantiate(fatherId uint64, state *State, c Co if !found { // La meta nouvellement générée n'apparaît pas dans la substitution // Trouver celle de la formula de base - for _, f := range s.GetForm().Slice() { + for _, f := range s.GetForm().GetSlice() { for _, term_formula := range f.GetMetas().Elements().GetSlice() { if !found && term_formula.IsMeta() && term_formula.GetName() == new_meta.GetName() { association_subst.Set(new_meta, term_formula) @@ -190,12 +209,15 @@ func (nds *nonDestructiveSearch) instantiate(fatherId uint64, state *State, c Co } } - if !found { // Vérifier dans substapplied - for _, subst := range state.GetAppliedSubst().GetSubst() { - original_meta, original_term := subst.Get() - if !found && original_meta.GetName() == new_meta.GetName() && !found { - association_subst.Set(new_meta, original_term) - found = true + if !found { + for _, subst := range state.GetAppliedSubst().GetSubst().GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + original_meta, original_term := s.Val.Get() + if !found && original_meta.GetName() == new_meta.GetName() && !found { + association_subst.Set(new_meta, original_term) + found = true + } } } } @@ -205,64 +227,56 @@ func (nds *nonDestructiveSearch) instantiate(fatherId uint64, state *State, c Co return fmt.Sprintf( "Error : No matching found for %v in new formula : %v\n", new_meta.ToString(), - s.GetForm().ToString()) + Lib.ListToString(s.GetForm(), ", ", "[]")) }), ) } } - new_subst, same_key := Unif.MergeSubstitutions(association_subst, state.GetAppliedSubst().GetSubst()) + mixed_assoc_subst := Lib.NewList[Unif.MixedSubstitution]() + for _, subst := range association_subst { + mixed_assoc_subst.Append(Unif.MkMixedFromSubst(subst)) + } + new_subst, same_key := Unif.MergeMixedSubstitutions(mixed_assoc_subst, state.GetAppliedSubst().GetSubst()) if same_key { Glob.PrintInfo("PS", "Same key in S2 and S1") } - if new_subst.Equals(Unif.Failure()) { + + if !Unif.UnifSucceeded(new_subst) { Glob.PrintError("PS", "MergeSubstitutions return failure") } - new_subst, same_key = Unif.MergeSubstitutions(new_subst, s.GetSubst()) + new_subst, same_key = Unif.MergeMixedSubstitutions(new_subst, s.GetSubst()) if same_key { Glob.PrintInfo("PS", "Same key in S2 and S1") } - if new_subst.Equals(Unif.Failure()) { + + if !Unif.UnifSucceeded(new_subst) { Glob.PrintError("PS", "MergeSubstitutions return failure") } - // Then associate with the substitution (if possible) - // for _, new_meta := range new_metas { - // found := false - // for original_meta, original_term := range s.GetSubst() { - // if !found && original_meta.GetName() == new_meta.GetName() && !found { - // new_subst[new_meta] = original_term - // found = true - // } else { // Test inverse pour le cas meta/meta - // if !found && original_term.IsMeta() && original_term.GetName() == new_meta.GetName() && !found { - // new_subst[new_meta] = original_term - // found = true - // } - // } - // } - // } - debug( Lib.MkLazy(func() string { return fmt.Sprintf( "Applied subst: %s", - state.GetAppliedSubst().GetSubst().ToString()) + Lib.ListToString(state.GetAppliedSubst().GetSubst(), ", ", "(empty subst)"), + ) }), ) debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Real substitution applied : %s", new_subst.ToString()) + "Real substitution applied : %s", Lib.ListToString(new_subst, ", ", "(empty subst)")) }), ) state.SetLF(Core.ApplySubstitutionsOnFormAndTermsList(new_subst, state.GetLF())) - ms, same_key := Unif.MergeSubstitutions(state.GetAppliedSubst().GetSubst(), new_subst) + ms, same_key := Unif.MergeMixedSubstitutions(state.GetAppliedSubst().GetSubst(), new_subst) if same_key { Glob.PrintError("PS", "Same key in S2 and S1") } - if ms.Equals(Unif.Failure()) { + + if !Unif.UnifSucceeded(ms) { Glob.PrintError("PS", "MergeSubstitutions return failure") } state.SetAppliedSubst(Core.MakeSubstAndForm(ms, s.GetForm())) @@ -296,14 +310,14 @@ func (nds *nonDestructiveSearch) manageSubstFoundNonDestructive(father_id uint64 st.SetSubstsFound(st.GetSubstsFound()[1:]) } - choosenSubstMetas := new_choosen_subst.GetSubst().GetMeta() + choosenSubstMetas := getMetas(new_choosen_subst.GetSubst()) debug(Lib.MkLazy(func() string { return fmt.Sprintf( "Choosen subst : %v - HasInCommon : %v", - new_choosen_subst.GetSubst().ToString(), + Lib.ListToString(new_choosen_subst.GetSubst(), ", ", "(empty subst)"), AST.HasMetaInCommonWith( choosenSubstMetas, - st.GetLastAppliedSubst().GetSubst().GetMeta(), + getMetas(st.GetLastAppliedSubst().GetSubst()), ), ) })) diff --git a/src/Search/proof.go b/src/Search/proof.go index 6a3a5e27..e7bcecad 100644 --- a/src/Search/proof.go +++ b/src/Search/proof.go @@ -111,8 +111,8 @@ func (ifl *IntFormAndTermsList) Copy() IntFormAndTermsList { return MakeIntFormAndTermsList(ifl.i, ifl.fl.Copy()) } -func (ifl *IntFormAndTermsList) GetForms() *AST.FormList { - res := AST.NewFormList() +func (ifl *IntFormAndTermsList) GetForms() Lib.List[AST.Form] { + res := Lib.NewList[AST.Form]() for _, ift := range (*ifl).GetFL() { res.Append(ift.GetForm()) } @@ -126,10 +126,10 @@ func (ifl *IntFormAndTermsList) SubstituteBy( return MakeIntFormAndTermsList(ifl.i, ifl.fl.SubstituteBy(metas, terms)) } -func GetFormulasFromIntFormAndTermList(iftl []IntFormAndTermsList) *AST.FormList { - res := AST.NewFormList() +func GetFormulasFromIntFormAndTermList(iftl []IntFormAndTermsList) Lib.List[AST.Form] { + res := Lib.NewList[AST.Form]() for _, v := range iftl { - res.Append(v.GetForms().Slice()...) + res.Append(v.GetForms().GetSlice()...) } return res } @@ -286,7 +286,7 @@ func IntFormAndTermsListToIntIntStringPairList(fl []IntFormAndTermsList) []IntIn func ProofStructListToJsonProofStructList(ps []ProofStruct) []JsonProofStruct { res := []JsonProofStruct{} for _, p := range ps { - new_json_element := JsonProofStruct{p.GetFormula().GetForm().ToMappedString(AST.DefaultMapString, Glob.GetTypeProof()), p.GetIdDMT(), p.Node_id, p.Rule, p.Rule_name, IntFormAndTermsListToIntIntStringPairList(p.Result_formulas), proofStructChildrenToJsonProofStructChildren(p.Children)} + new_json_element := JsonProofStruct{p.GetFormula().GetForm().ToString(), p.GetIdDMT(), p.Node_id, p.Rule, p.Rule_name, IntFormAndTermsListToIntIntStringPairList(p.Result_formulas), proofStructChildrenToJsonProofStructChildren(p.Children)} res = append(res, new_json_element) } return res @@ -390,7 +390,7 @@ func RetrieveUninstantiatedMetaFromProof(proofStruct []ProofStruct) Lib.Set[AST. res = res.Union(proofMetas) resResultFormulas := GetFormulasFromIntFormAndTermList(proofElement.GetResultFormulas()) - for _, v := range resResultFormulas.Slice() { + for _, v := range resResultFormulas.GetSlice() { res = res.Union(v.GetMetas()) } @@ -404,7 +404,7 @@ func RetrieveUninstantiatedMetaFromProof(proofStruct []ProofStruct) Lib.Set[AST. } /* Apply subst on a proof tree */ -func ApplySubstitutionOnProofList(s Unif.Substitutions, proof_list []ProofStruct) []ProofStruct { +func ApplySubstitutionOnProofList(s Lib.List[Unif.MixedSubstitution], proof_list []ProofStruct) []ProofStruct { new_proof_list := []ProofStruct{} for _, p := range proof_list { @@ -412,7 +412,10 @@ func ApplySubstitutionOnProofList(s Unif.Substitutions, proof_list []ProofStruct new_result_formulas := []IntFormAndTermsList{} for _, f := range p.GetResultFormulas() { - new_result_formulas = append(new_result_formulas, MakeIntFormAndTermsList(f.GetI(), Core.ApplySubstitutionsOnFormAndTermsList(s, f.GetFL()))) + new_result_formulas = append( + new_result_formulas, + MakeIntFormAndTermsList(f.GetI(), Core.ApplySubstitutionsOnFormAndTermsList(s, f.GetFL())), + ) } p.SetResultFormulasProof(new_result_formulas) diff --git a/src/Search/rules.go b/src/Search/rules.go index a2f653dc..b9b490b3 100644 --- a/src/Search/rules.go +++ b/src/Search/rules.go @@ -43,7 +43,6 @@ import ( "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" "github.com/GoelandProver/Goeland/Unif" - "os" ) var strToPrintMap map[string]string = map[string]string{ @@ -60,17 +59,9 @@ var strToPrintMap map[string]string = map[string]string{ "EXISTS": "∃", } -/** -* ApplyClosureRules -* Search closure rules (not true or false), and call search conflict if no obvious closure found -* Datas : -* form : the formula for which we are looking for the contradiction -* state : a state, containing all the formula of the current step -* Result : -* a boolean, true if a contradiction was found, false otherwise -* a substitution, the substitution which make the contradiction (possibly empty) -**/ -func ApplyClosureRules(form AST.Form, state *State) (result bool, substitutions []Unif.Substitutions) { +func ApplyClosureRules(form AST.Form, state *State) (bool, Lib.List[Lib.List[Unif.MixedSubstitution]]) { + result := false + substitutions := Lib.NewList[Lib.List[Unif.MixedSubstitution]]() debug(Lib.MkLazy(func() string { return "Start ACR" })) if searchObviousClosureRule(form) { @@ -79,10 +70,14 @@ func ApplyClosureRules(form AST.Form, state *State) (result bool, substitutions f := form.Copy() - substFound, subst := searchInequalities(form) + substFound, substs := searchInequalities(form) if substFound { result = true - substitutions = append(substitutions, subst) + mixed_substs := Lib.NewList[Unif.MixedSubstitution]() + for _, subst := range substs { + mixed_substs.Append(Unif.MkMixedFromSubst(subst)) + } + substitutions.Append(mixed_substs) } substFound, matchSubsts := searchClosureRule(f, *state) @@ -93,10 +88,10 @@ func ApplyClosureRules(form AST.Form, state *State) (result bool, substitutions for _, subst := range matchSubsts { debug(Lib.MkLazy(func() string { return fmt.Sprintf("MSL : %v", subst.ToString()) })) - if subst.GetSubst().Equals(Unif.MakeEmptySubstitution()) { + if subst.IsSubstsEmpty() { result = true } else { - if !searchForbidden(state, subst) { + if !searchForbidden(state, subst.MatchingSubstitutions()) { result = true } } @@ -105,13 +100,13 @@ func ApplyClosureRules(form AST.Form, state *State) (result bool, substitutions debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Subst found between : %v and %v : %v", + "Subst found between : %s and %s : %s", form.ToString(), subst.GetForm().ToString(), - subst.GetSubst().ToString()) + subst.ToString()) }), ) - substitutions = Unif.AppendIfNotContainsSubst(substitutions, subst.GetSubst()) + substitutions.Add(Lib.ListEquals[Unif.MixedSubstitution], subst.GetSubsts()) } } } @@ -122,8 +117,15 @@ func ApplyClosureRules(form AST.Form, state *State) (result bool, substitutions func searchForbidden(state *State, s Unif.MatchingSubstitutions) bool { foundForbidden := false - for _, substForbidden := range state.GetForbiddenSubsts() { - forbiddenShared := Core.AreEqualsModuloaLaphaConversion(s.GetSubst(), substForbidden) + for _, substForbidden := range state.GetForbiddenSubsts().GetSlice() { + substs := Unif.Substitutions{} + for _, subst := range substForbidden.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + substs = append(substs, s.Val) + } + } + forbiddenShared := Core.AreEqualsModuloaLaphaConversion(s.GetSubst(), substs) if forbiddenShared { foundForbidden = true @@ -195,7 +197,7 @@ func searchInequalities(form AST.Form) (bool, Unif.Substitutions) { } /* Search a contradiction between a formula and another in the datastructure */ -func searchClosureRule(f AST.Form, st State) (bool, []Unif.MatchingSubstitutions) { +func searchClosureRule(f AST.Form, st State) (bool, []Unif.MixedSubstitutions) { switch nf := f.(type) { case AST.Pred: return st.GetTreeNeg().Unify(f) @@ -289,8 +291,10 @@ func applyAlphaNotOrRule( ) Core.FormAndTermsList { setStateRules(state, "ALPHA", "NOT", "OR") - for i := range formWithoutNot.FormList.Slice() { - result = result.AppendIfNotContains(Core.MakeFormAndTerm(AST.MakerNot(formWithoutNot.FormList.Get(i)), terms)) + for i := range formWithoutNot.GetChildFormulas().GetSlice() { + result = result.AppendIfNotContains( + Core.MakeFormAndTerm(AST.MakerNot(formWithoutNot.GetChildFormulas().At(i)), terms), + ) } return result @@ -318,8 +322,10 @@ func applyAlphaAndRule( ) Core.FormAndTermsList { setStateRules(state, "ALPHA", "AND") - for i := range formTyped.FormList.Slice() { - result = result.AppendIfNotContains(Core.MakeFormAndTerm(formTyped.FormList.Get(i), terms)) + for i := range formTyped.GetChildFormulas().GetSlice() { + result = result.AppendIfNotContains( + Core.MakeFormAndTerm(formTyped.GetChildFormulas().At(i), terms), + ) } return result @@ -377,8 +383,11 @@ func applyBetaNotAndRule( ) []Core.FormAndTermsList { setStateRules(state, "BETA", "NOT", "AND") - for i := range formWithoutNot.FormList.Slice() { - result = append(result, Core.MakeSingleElementFormAndTermList(Core.MakeFormAndTerm(AST.MakerNot(formWithoutNot.FormList.Get(i)), terms))) + for i := range formWithoutNot.GetChildFormulas().GetSlice() { + result = append( + result, + Core.MakeSingleElementFormAndTermList( + Core.MakeFormAndTerm(AST.MakerNot(formWithoutNot.GetChildFormulas().At(i)), terms))) } return result @@ -412,8 +421,9 @@ func applyBetaOrRule( ) []Core.FormAndTermsList { setStateRules(state, "BETA", "OR") - for i := range formTyped.FormList.Slice() { - result = append(result, Core.MakeSingleElementFormAndTermList(Core.MakeFormAndTerm(formTyped.FormList.Get(i), terms))) + for i := range formTyped.GetChildFormulas().GetSlice() { + result = append(result, Core.MakeSingleElementFormAndTermList( + Core.MakeFormAndTerm(formTyped.GetChildFormulas().At(i), terms))) } return result @@ -495,10 +505,6 @@ func ApplyGammaRules(fnt Core.FormAndTerms, index int, state *State) (Core.FormA case AST.All: setStateRules(state, "GAMMA", "FORALL") - - case AST.AllType: - Glob.PrintError("search", "Typed search not handled yet") - os.Exit(3) } fnt, mm := Core.Instantiate(fnt, index) diff --git a/src/Search/search.go b/src/Search/search.go index cb5e019b..c55ab779 100644 --- a/src/Search/search.go +++ b/src/Search/search.go @@ -49,7 +49,7 @@ import ( type SearchAlgorithm interface { Search(AST.Form, int) bool SetApplyRules(func(uint64, State, Communication, Core.FormAndTermsList, int, int, []int)) - ManageClosureRule(uint64, *State, Communication, []Unif.Substitutions, Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) + ManageClosureRule(uint64, *State, Communication, Lib.List[Lib.List[Unif.MixedSubstitution]], Core.FormAndTerms, int, int) (bool, []Core.SubstAndForm) } var UsedSearch SearchAlgorithm @@ -118,10 +118,13 @@ func printStandardSolution(status string) { fmt.Printf("%s SZS status %v for %v\n", "%", status, Glob.GetProblemName()) } -func retrieveMetaFromSubst(s Unif.Substitutions) []int { +func retrieveMetaFromSubst(substs Lib.List[Unif.MixedSubstitution]) []int { res := []int{} - for _, s_element := range s { - res = Glob.AppendIfNotContainsInt(res, s_element.Key().GetFormula()) + for _, subst := range substs.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Unif.Substitution]: + res = Glob.AppendIfNotContainsInt(res, s.Val.Key().GetFormula()) + } } return res } diff --git a/src/Search/state.go b/src/Search/state.go index 9015e430..3a5bd354 100644 --- a/src/Search/state.go +++ b/src/Search/state.go @@ -64,7 +64,7 @@ type State struct { proof []ProofStruct current_proof ProofStruct bt_on_formulas bool - forbidden []Unif.Substitutions + forbidden Lib.List[Lib.List[Unif.MixedSubstitution]] unifier Core.Unifier eqStruct eqStruct.EqualityStruct } @@ -116,13 +116,13 @@ func (st State) GetSubstsFound() []Core.SubstAndForm { func (s State) GetTreePos() Unif.DataStructure { return s.tree_pos } -func (s *State) AddToTreePos(fl *AST.FormList) { +func (s *State) AddToTreePos(fl Lib.List[AST.Form]) { s.tree_pos = s.tree_pos.InsertFormulaListToDataStructure(fl) } func (s State) GetTreeNeg() Unif.DataStructure { return s.tree_neg } -func (s *State) AddToTreeNeg(fl *AST.FormList) { +func (s *State) AddToTreeNeg(fl Lib.List[AST.Form]) { s.tree_neg = s.tree_neg.InsertFormulaListToDataStructure(fl) } func (s State) GetProof() []ProofStruct { @@ -134,7 +134,7 @@ func (s State) GetCurrentProof() ProofStruct { func (s State) GetBTOnFormulas() bool { return s.bt_on_formulas } -func (s State) GetForbiddenSubsts() []Unif.Substitutions { +func (s State) GetForbiddenSubsts() Lib.List[Lib.List[Unif.MixedSubstitution]] { return s.forbidden } func (s State) GetGlobUnifier() Core.Unifier { @@ -245,8 +245,8 @@ func (st *State) SetCurrentProofNodeId(i int) { func (st *State) SetBTOnFormulas(b bool) { st.bt_on_formulas = b } -func (st *State) SetForbiddenSubsts(s []Unif.Substitutions) { - st.forbidden = Unif.CopySubstList(s) +func (st *State) SetForbiddenSubsts(s Lib.List[Lib.List[Unif.MixedSubstitution]]) { + st.forbidden = s.Copy(Lib.ListCpy[Unif.MixedSubstitution]) } func (s *State) SetGlobUnifier(u Core.Unifier) { s.unifier = u.Copy() @@ -285,7 +285,7 @@ func MakeState(limit int, tp, tn Unif.DataStructure, f AST.Form) State { []ProofStruct{}, current_proof, false, - []Unif.Substitutions{}, + Lib.NewList[Lib.List[Unif.MixedSubstitution]](), Core.MakeUnifier(), eqStruct.NewEqStruct()} } @@ -353,7 +353,7 @@ func (st State) Print() { debug(Lib.MkLazy(func() string { return "Subst_found: " })) debug( Lib.MkLazy(func() string { - return Unif.SubstListToString(Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound())) + return Unif.SubstsToString(Core.GetSubstListFromSubstAndFormList(st.GetSubstsFound())) }), ) } @@ -363,9 +363,16 @@ func (st State) Print() { debug(Lib.MkLazy(func() string { return st.GetLastAppliedSubst().ToString() })) } - if len(st.forbidden) > 0 { + if st.forbidden.Len() > 0 { debug(Lib.MkLazy(func() string { return "Forbidden:" })) - debug(Lib.MkLazy(func() string { return Unif.SubstListToString(st.forbidden) })) + debug( + Lib.MkLazy(func() string { + return st.forbidden.ToString( + func(m Lib.List[Unif.MixedSubstitution]) string { + return Lib.ListToString(m, ", ", "[]") + }, " ; ", "[]") + }), + ) } debug( diff --git a/src/Typing/apply_rules.go b/src/Typing/apply_rules.go deleted file mode 100644 index 16a7313f..00000000 --- a/src/Typing/apply_rules.go +++ /dev/null @@ -1,189 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -import ( - "fmt" - - "github.com/GoelandProver/Goeland/AST" -) - -/** - * This file contains all the rules of the typing system. - **/ - -const ( - formIsSet = iota - termIsSet = iota - typeIsSet = iota - schemeIsSet = iota - noConsequence = iota -) - -/* Launch the rules depending on what's on the right side of the sequent. */ -func applyRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Only one of the three should be set - if !onlyOneConsequenceIsSet(state) { - return Reconstruct{ - result: false, - err: fmt.Errorf("multiple elements on the right-side of the sequent. Cannot type this system"), - } - } - - // The applicable rules depend on what is set: the form, the term, or the type ? - switch whatIsSet(state.consequence) { - case formIsSet: - return applyFormRule(state, root, fatherChan) - case termIsSet: - return applyTermRule(state, root, fatherChan) - case typeIsSet: - return applyTypeRule(state, root, fatherChan) - case schemeIsSet: - return applySymRule(state, root, fatherChan) - case noConsequence: - return applyWFRule(state, root, fatherChan) - } - - return Reconstruct{result: true, err: nil} -} - -/* Applies one of the forms rule based on the type of the form. */ -func applyFormRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - var rec Reconstruct - switch (state.consequence.f).(type) { - case AST.All, AST.AllType, AST.Ex: - rec = applyQuantRule(state, root, fatherChan) - case AST.And, AST.Or: - rec = applyNAryRule(state, root, fatherChan) - case AST.Imp, AST.Equ: - rec = applyBinaryRule(state, root, fatherChan) - case AST.Top, AST.Bot: - rec = applyBotTopRule(state, root, fatherChan) - case AST.Not: - rec = applyNotRule(state, root, fatherChan) - case AST.Pred: - rec = applyAppRule(state, root, fatherChan) - } - return rec -} - -/* Applies one of the terms rule based on the type of the form. */ -func applyTermRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - var rec Reconstruct - switch (state.consequence.t).(type) { - case AST.Fun: - rec = applyAppRule(state, root, fatherChan) - case AST.Var: - rec = applyVarRule(state, root, fatherChan) - // Metas shoudln't appear in the formula yet. - // IDs are not a real Term. - } - return rec -} - -/* Applies one of the types rule based on the type of the form. */ -func applyTypeRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - var rec Reconstruct - switch type_ := (state.consequence.a).(type) { - case AST.TypeHint: - if type_.Equals(metaType) { - rec = applyTypeWFRule(state, root, fatherChan) - } else { - rec = applyGlobalTypeVarRule(state, root, fatherChan) - } - case AST.TypeVar: - rec = applyLocalTypeVarRule(state, root, fatherChan) - case AST.TypeCross: - // Apply composed rule: launch a child for each TypeHint of the composed type. - rec = applyCrossRule(state, root, fatherChan) - // There shouldn't be any TypeArrow: can not type a variable with it in first order. - case AST.ParameterizedType: - // Apply app rule, we only need to check if the name of the type exists. - rec = applyAppTypeRule(state, root, fatherChan) - } - return rec -} - -/* Applies one of the WF rule based on the type of the form. */ -func applyWFRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - if state.localContext.isEmpty() && state.globalContext.isEmpty() { - root.appliedRule = "WF_0" - return Reconstruct{result: true, err: nil} - } - if state.localContext.isEmpty() { - root.appliedRule = "WF_1" - return Reconstruct{result: true, err: nil} - } - - return applyWF2(state, root, fatherChan) -} - -/* Checks that at most one consequence of the sequent is set. */ -func onlyOneConsequenceIsSet(state Sequent) bool { - numberSet := 0 - if state.consequence.f != nil { - numberSet++ - } - if state.consequence.t != nil { - numberSet++ - } - if state.consequence.a != nil { - numberSet++ - } - if state.consequence.s != nil { - numberSet++ - } - - return numberSet < 2 -} - -/** - * Returns what is set in the consequence of the sequent. Either it's the form, - * the term, or the type. - * It doesn't check if multiple elements are set, it should be done before. - **/ -func whatIsSet(cons Consequence) int { - var set int - if cons.f != nil { - set = formIsSet - } else if cons.t != nil { - set = termIsSet - } else if cons.a != nil { - set = typeIsSet - } else if cons.s != nil { - set = schemeIsSet - } else { - set = noConsequence - } - return set -} diff --git a/src/Typing/contexts.go b/src/Typing/contexts.go deleted file mode 100644 index ae9faeac..00000000 --- a/src/Typing/contexts.go +++ /dev/null @@ -1,341 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -import ( - "fmt" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * This file defines the global & local contexts types. - **/ - -/* Stores the local context */ -type LocalContext struct { - vars []AST.Var - typeVars []AST.TypeVar -} - -/* LocalContext methods */ - -/* Adds a var to a copy of the local context and returns it. */ -func (lc LocalContext) addVar(var_ AST.Var) LocalContext { - newLc := lc.copy() - newLc.vars = append(newLc.vars, var_) - return newLc -} - -/* Adds a type var to a copy of the local context and returns it. */ -func (lc LocalContext) addTypeVar(var_ AST.TypeVar) LocalContext { - newLc := lc.copy() - newLc.typeVars = append(newLc.typeVars, var_) - return newLc -} - -/* Copies a LocalContext. */ -func (lc LocalContext) copy() LocalContext { - newVars := make([]AST.Var, len(lc.vars)) - newTypeVars := make([]AST.TypeVar, len(lc.typeVars)) - copy(newVars, lc.vars) - copy(newTypeVars, lc.typeVars) - return LocalContext{vars: newVars, typeVars: newTypeVars} -} - -/* True if all the slices are cleared */ -func (lc LocalContext) isEmpty() bool { - return len(lc.vars)+len(lc.typeVars) == 0 -} - -/** - * Copies the context and pops the first var (and returns it with the new local context). - * It doesn't check if the size of the array is positive, it should be checked before. - **/ -func (lc LocalContext) popVar() (AST.Var, LocalContext) { - newLc := lc.copy() - newLc.vars = newLc.vars[1:] - return lc.vars[0], newLc -} - -/** - * Copies the context and pops the first type var (and returns it with the new local context). - * It doesn't check if the size of the array is positive, it should be checked before. - **/ -func (lc LocalContext) popTypeVar() (AST.TypeVar, LocalContext) { - newLc := lc.copy() - newLc.typeVars = newLc.typeVars[1:] - return lc.typeVars[0], newLc -} - -/* Stores the global context */ -type GlobalContext struct { - primitiveTypes []AST.TypeHint - parameterizedTypes []string - composedType map[string]AST.TypeCross - simpleSchemes map[string][]AST.TypeScheme - polymorphSchemes map[string][]AST.QuantifiedType -} - -/* Copies a GlobalContext into a new variable and returns it. */ -func (gc GlobalContext) copy() GlobalContext { - context := GlobalContext{ - primitiveTypes: make([]AST.TypeHint, len(gc.primitiveTypes)), - parameterizedTypes: make([]string, len(gc.parameterizedTypes)), - simpleSchemes: make(map[string][]AST.TypeScheme), - polymorphSchemes: make(map[string][]AST.QuantifiedType), - } - copy(context.primitiveTypes, gc.primitiveTypes) - copy(context.parameterizedTypes, gc.parameterizedTypes) - - for name, list := range gc.simpleSchemes { - context.simpleSchemes[name] = make([]AST.TypeScheme, len(list)) - copy(context.simpleSchemes[name], list) - } - - for name, list := range gc.polymorphSchemes { - context.polymorphSchemes[name] = make([]AST.QuantifiedType, len(list)) - copy(context.polymorphSchemes[name], list) - } - - return context -} - -/* Gets a simple / polymorphic type scheme from an ID, type variables, and terms */ -func (gc GlobalContext) getTypeScheme( - id AST.Id, - vars []AST.TypeApp, - terms Lib.List[AST.Term], -) (AST.TypeScheme, error) { - args, err := getArgsTypes(gc, terms) - if err != nil { - return nil, err - } - - typeScheme, err := gc.getSimpleTypeScheme(id.GetName(), args) - - if typeScheme == nil { - typeScheme, err = gc.getPolymorphicTypeScheme( - id.GetName(), - len(vars), - terms.Len(), - ) - // Instantiate type scheme with actual types - if typeScheme != nil { - typeScheme = Glob.To[AST.QuantifiedType](typeScheme).Instanciate(vars) - } - } - - if err != nil { - return nil, err - } - - return typeScheme, nil -} - -func flattenCross(ty AST.TypeApp) []AST.TypeApp { - switch nty := ty.(type) { - case AST.TypeCross: - flattened := []AST.TypeApp{} - for _, uty := range nty.GetAllUnderlyingTypes() { - flattened = append(flattened, flattenCross(uty)...) - } - return []AST.TypeApp{AST.MkTypeCross(flattened...)} - } - return []AST.TypeApp{ty} -} - -/* Search for a TypeScheme with the name & the arguments type */ -func (gc GlobalContext) getSimpleTypeScheme(name string, termsType AST.TypeApp) (AST.TypeScheme, error) { - if termsType == nil { - if typeScheme, found := gc.simpleSchemes[name]; found { - return typeScheme[0], nil - } else { - return nil, fmt.Errorf("no constant function with the name %s in the global context", name) - } - } - - termsType = flattenCross(termsType)[0] - if typeSchemeList, found := gc.simpleSchemes[name]; found { - for _, typeScheme := range typeSchemeList { - if AST.GetInputType(typeScheme).Equals(Lib.ComparableList[AST.TypeApp]{termsType}) { - return typeScheme, nil - } - } - } - return nil, fmt.Errorf("no predicate/function with the name %s in the global context and arguments of type %s", name, termsType.ToString()) -} - -/* Gets the polymorphic type scheme corresponding to the input. */ -func (gc GlobalContext) getPolymorphicTypeScheme(name string, varsLen, termsLen int) (AST.TypeScheme, error) { - if typeSchemeList, found := gc.polymorphSchemes[name]; found { - for _, typeScheme := range typeSchemeList { - if termsLen == typeScheme.Size()-1 && varsLen == typeScheme.QuantifiedVarsLen() { - return typeScheme, nil - } - } - } - return nil, fmt.Errorf("no predicate/function with the name %s in the global context", name) -} - -/* Returns true if the TypeHint is found in the context */ -func (gc GlobalContext) isTypeInContext(typeApp AST.TypeScheme) bool { - for _, type_ := range gc.primitiveTypes { - if type_.Equals(typeApp) { - return true - } - } - for _, type_ := range gc.composedType { - if type_.Equals(typeApp) { - return true - } - } - return false -} - -/* Tests if there are no more TypeScheme stored (doesn't check for primitive types) */ -func (gc GlobalContext) isEmpty() bool { - result := true - - for _, app := range gc.simpleSchemes { - result = result && (len(app) == 0) - } - for _, app := range gc.polymorphSchemes { - result = result && (len(app) == 0) - } - - return result -} - -/* Checks if the parameterized types contains the given name */ -func (gc GlobalContext) parameterizedTypesContains(name string) bool { - for _, parameterTypeName := range gc.parameterizedTypes { - if name == parameterTypeName { - return true - } - } - return false -} - -/* Utils */ - -/** - * Creates a global context from all the types / type schemes recorded in the map of types. - * Incrementally verifies if the context is well typed. - * If not, an error is returned. - **/ -func createGlobalContext(context map[string][]AST.App) (GlobalContext, error) { - globalContext := GlobalContext{ - primitiveTypes: []AST.TypeHint{}, - parameterizedTypes: []string{}, - composedType: make(map[string]AST.TypeCross), - simpleSchemes: make(map[string][]AST.TypeScheme), - polymorphSchemes: make(map[string][]AST.QuantifiedType), - } - - // Fill first the primitive types - for name, appList := range context { - if len(appList) == 0 { - globalContext.parameterizedTypes = append(globalContext.parameterizedTypes, name) - } - for _, app := range appList { - if type_, isTypeHint := app.App.(AST.TypeHint); isTypeHint { - if !AST.IsConstant(name) { - globalContext.primitiveTypes = append(globalContext.primitiveTypes, type_) - } - } - } - } - - for name, appList := range context { - // Then, fill everything else - for _, app := range appList { - switch type_ := app.App.(type) { - case AST.TypeHint: - if AST.IsConstant(name) { - globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) - } - case AST.TypeCross: - globalContext.composedType[name] = type_ - case AST.TypeArrow: - globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) - case AST.QuantifiedType: - globalContext.polymorphSchemes[name] = append(globalContext.polymorphSchemes[name], type_) - case AST.ParameterizedType: - globalContext.simpleSchemes[name] = append(globalContext.simpleSchemes[name], type_) - } - if err := incrementalVerificationOfGlobalContext(globalContext.copy(), name, app.App); err != nil { - return GlobalContext{}, err - } - } - } - - if !globalContextIsWellTyped { - globalContextIsWellTyped = true - } - return globalContext, nil -} - -/** - * Triggers rules to verify the global context while it's constructed. - * It will avoid combinatorial explosion on global context well formedness verification. - **/ -func incrementalVerificationOfGlobalContext(globalContext GlobalContext, name string, app AST.TypeScheme) error { - if globalContextIsWellTyped { - return nil - } - - sequent := Sequent{ - globalContext: globalContext, - localContext: LocalContext{}, - } - rec := Reconstruct{err: nil} - proofTree, chan_ := new(ProofTree), make(chan Reconstruct) - - switch type_ := app.(type) { - case AST.TypeCross: - sequent.consequence = Consequence{a: type_} - rec = applyCrossRule(sequent, proofTree, chan_) - case AST.QuantifiedType, AST.TypeArrow: - sequent.consequence = Consequence{s: app} - rec = applySymRule(sequent, proofTree, chan_) - case AST.TypeHint: - if AST.IsConstant(name) { - sequent.consequence = Consequence{a: type_} - rec = applyGlobalTypeVarRule(sequent, proofTree, chan_) - } - } - return rec.err -} diff --git a/src/Typing/env-and-context.go b/src/Typing/env-and-context.go new file mode 100644 index 00000000..9b7caa83 --- /dev/null +++ b/src/Typing/env-and-context.go @@ -0,0 +1,161 @@ +/** +* Copyright 2022 by the authors (see AUTHORS). +* +* Goéland is an automated theorem prover for first order logic. +* +* This software is governed by the CeCILL license under French law and +* abiding by the rules of distribution of free software. You can use, +* modify and/ or redistribute the software under the terms of the CeCILL +* license as circulated by CEA, CNRS and INRIA at the following URL +* "http://www.cecill.info". +* +* As a counterpart to the access to the source code and rights to copy, +* modify and redistribute granted by the license, users are provided only +* with a limited warranty and the software's author, the holder of the +* economic rights, and the successive licensors have only limited +* liability. +* +* In this respect, the user's attention is drawn to the risks associated +* with loading, using, modifying and/or developing or reproducing the +* software by the user in light of its specific status of free software, +* that may mean that it is complicated to manipulate, and that also +* therefore means that it is reserved for developers and experienced +* professionals having in-depth computer knowledge. Users are therefore +* encouraged to load and test the software's suitability as regards their +* requirements in conditions enabling the security of their systems and/or +* data to be ensured and, more generally, to use and operate it in the +* same conditions as regards security. +* +* The fact that you are presently reading this means that you have had +* knowledge of the CeCILL license and that you accept its terms. +**/ + +/** + * This file declares the environments of the typing process. + * In particular, it handles the global context and its accesses. +**/ + +package Typing + +import ( + "sync" + + "fmt" + "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Lib" +) + +// We define an ordered type of pairs of (string, Ty) in order to use sets. +type definedType struct { + name string + ty AST.Ty +} + +func (dty definedType) Less(oth any) bool { + if other, ok := oth.(definedType); ok { + return dty.name < other.name + } + return false +} + +func (dty definedType) Equals(oth any) bool { + if other, ok := oth.(definedType); ok { + return dty.name == other.name && dty.ty.Equals(other.ty) + } + return false +} + +// A context is a set of defined types +type Con struct { + defs Lib.Set[definedType] +} + +func emptyCon() Con { + return Con{Lib.EmptySet[definedType]()} +} + +func (con Con) Copy() Con { + return Con{con.defs.Copy()} +} + +func (con Con) add(name string, ty AST.Ty) Con { + return Con{con.defs.Add(definedType{name, ty})} +} + +func (con Con) contains(name string, ty AST.Ty) bool { + return con.defs.Contains(definedType{name, ty}) +} + +func (con Con) addTypedVars(typed_vars Lib.List[AST.TypedVar]) Con { + for _, tv := range typed_vars.GetSlice() { + con = con.add(tv.GetName(), tv.GetTy()) + } + return con +} + +func (con Con) toString() string { + to_string := func(def definedType) string { + return fmt.Sprintf("%s: %s", def.name, def.ty.ToString()) + } + return con.defs.Elements().ToString(to_string, ", ", "{}") +} + +// We could use [Con] to do environments, but as we need to query by name it's faster to use a map. +type Env struct { + con map[string]AST.Ty + mut sync.Mutex +} + +func (env *Env) toString() string { + env.mut.Lock() + result := "Environment:" + for k, v := range env.con { + result += "\n- " + k + ": " + v.ToString() + } + env.mut.Unlock() + return result + "\n" +} + +func safeGlobalOperation[T any](f func() T) T { + global_env.mut.Lock() + res := f() + global_env.mut.Unlock() + return res +} + +func AddToGlobalEnv(name string, ty AST.Ty) { + safeGlobalOperation( + func() any { + global_env.con[name] = ty + return nil + }, + ) +} + +func unsafeQuery(name string) Lib.Option[AST.Ty] { + if ty, ok := global_env.con[name]; ok { + return Lib.MkSome(ty) + } + return Lib.MkNone[AST.Ty]() +} + +func QueryGlobalEnv(name string) Lib.Option[AST.Ty] { + return safeGlobalOperation(func() Lib.Option[AST.Ty] { return unsafeQuery(name) }) +} + +// Queries the environment and, if found, instantiate the definition with the given types. +// Guaranteed to not return a Pi-type. +func QueryEnvInstance(name string, instance Lib.List[AST.Ty]) Lib.Option[AST.Ty] { + return safeGlobalOperation( + func() Lib.Option[AST.Ty] { + // If [name] is safely found in the environment, instantiates it with the given vars + // Otherwise, return None + return Lib.OptBind( + unsafeQuery(name), + func(ty AST.Ty) Lib.Option[AST.Ty] { + return Lib.MkSome(AST.InstantiateTy(ty, instance)) + }, + ) + }, + ) +} diff --git a/src/Typing/form_rules.go b/src/Typing/form_rules.go deleted file mode 100644 index c588692f..00000000 --- a/src/Typing/form_rules.go +++ /dev/null @@ -1,233 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -import ( - "github.com/GoelandProver/Goeland/AST" -) - -/** - * This file contains all the rules that the typing system can apply on a formula. - **/ - -/* Applies quantification rule and launches 2 goroutines waiting its children. */ -func applyQuantRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add rule to prooftree - switch (state.consequence.f).(type) { - case AST.All, AST.AllType: - root.appliedRule = "∀" - case AST.Ex: - root.appliedRule = "∃" - } - - var newForm AST.Form - var varTreated AST.Var - var typeTreated AST.TypeVar - - varInstantiated := false - - switch f := (state.consequence.f).(type) { - case AST.All, AST.Ex: - varTreated, newForm = removeOneVar(state.consequence.f) - varInstantiated = true - case AST.AllType: - v := f.GetVarList()[0] - if len(f.GetVarList()) > 1 { - typeTreated, newForm = v, AST.MakeAllType(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) - } else { - typeTreated, newForm = v, f.GetForm() - } - } - - // Create 2 children: - // 1 - First one with the type of the quantified variable. It should be a TypeApp. - // 2 - Second one with the quantified variable added in the local context. - // => copy the local context and use the function to get the global context (copy or not). - // The underlying form should be gotten to be properly typed. - children := mkQuantChildren(state, varInstantiated, varTreated, typeTreated, newForm) - - // Launch the children in a goroutine, and wait for it to close. - // If one branch closes with an error, then the system is not well-typed. - return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -} - -/* Applies OR or AND rule and launches n goroutines waiting its children */ -func applyNAryRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - formList := AST.NewFormList() - // Add rule to prooftree - switch f := (state.consequence.f).(type) { - case AST.And: - root.appliedRule = "∧" - formList = f.FormList - case AST.Or: - root.appliedRule = "∨" - formList = f.FormList - } - - // Construct children with all the formulas - children := []Sequent{} - for _, form := range formList.Slice() { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{f: form}, - }) - } - - // Launch the children in a goroutine, and wait for it to close. - // If one branch closes with an error, then the system is not well-typed. - return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -} - -/* Applies => or <=> rule and launches 2 goroutines waiting its children */ -func applyBinaryRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - var f1, f2 AST.Form - // Add rule to prooftree - switch f := (state.consequence.f).(type) { - case AST.Imp: - root.appliedRule = "⇒" - f1, f2 = f.GetF1(), f.GetF2() - case AST.Equ: - root.appliedRule = "⇔" - f1, f2 = f.GetF1(), f.GetF2() - } - - // Construct children with the 2 formulas - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{f: f1}, - }, - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{f: f2}, - }, - } - - // Launch the children in a goroutine, and wait for it to close. - // If one branch closes with an error, then the system is not well-typed. - return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -} - -/* Applies BOT or TOP rule and does not create a new goroutine */ -func applyBotTopRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add rule to prooftree - switch (state.consequence.f).(type) { - case AST.Top: - root.appliedRule = "⊤" - case AST.Bot: - root.appliedRule = "⊥" - } - - // Construct children with the contexts - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{}, - }, - } - - // If the branch closes with an error, then the system is not well-typed. - return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -} - -func applyNotRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add rule to prooftree - root.appliedRule = "¬" - form := (state.consequence.f).(AST.Not).GetForm() - - // Construct children with the contexts - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{f: form}, - }, - } - - // If the branch closes with an error, then the system is not well-typed. - return reconstructForm(launchChildren(children, root, fatherChan), state.consequence.f) -} - -/** - * Removes the first variable of an exitential or universal form, and returns a - * universal / existential form iff it still possesses other vars. - * Otherwise, it returns the form gotten with GetForm(). - **/ -func removeOneVar(form AST.Form) (AST.Var, AST.Form) { - // It's pretty much the same thing, but I don't have a clue on how to factorize this.. - switch f := form.(type) { - case AST.Ex: - v := f.GetVarList()[0] - if len(f.GetVarList()) > 1 { - return v, AST.MakeEx(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) - } - return v, f.GetForm() - case AST.All: - v := f.GetVarList()[0] - if len(f.GetVarList()) > 1 { - return v, AST.MakeAll(f.GetIndex(), f.GetVarList()[1:], f.GetForm()) - } - return v, f.GetForm() - } - return AST.Var{}, nil -} - -/* Makes the child treating the variable depending on which is set. */ -func mkQuantChildren(state Sequent, varInstantiated bool, varTreated AST.Var, typeTreated AST.TypeVar, newForm AST.Form) []Sequent { - var type_ AST.TypeApp - var newLocalContext LocalContext - if varInstantiated { - type_ = varTreated.GetTypeApp() - newLocalContext = state.localContext.addVar(varTreated) - } else { - type_ = metaType - newLocalContext = state.localContext.addTypeVar(typeTreated) - } - - return []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{a: type_}, - }, - { - globalContext: state.globalContext, - localContext: newLocalContext, - consequence: Consequence{f: newForm}, - }, - } -} diff --git a/src/AST/tptp_native.go b/src/Typing/init.go similarity index 53% rename from src/AST/tptp_native.go rename to src/Typing/init.go index bb3b1d04..ccbccbc0 100644 --- a/src/AST/tptp_native.go +++ b/src/Typing/init.go @@ -31,38 +31,49 @@ **/ /** - * This file declares TPTP native types and types scheme : - * - int, rat, real for primitives - * - a bunch of type schemes - **/ + * This file initializes the global environment (e.g., with TPTP primitives) +**/ -package AST +package Typing import ( + "sync" + + "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" + "github.com/GoelandProver/Goeland/Lib" ) -var tInt TypeHint -var tRat TypeHint -var tReal TypeHint -var defaultType TypeHint -var defaultProp TypeHint +var global_env Env +var ari_var string +var debug Glob.Debugger +var debug_low_level Glob.Debugger + +func Init() { + global_env = Env{make(map[string]AST.Ty), sync.Mutex{}} + ari_var = "number" -var intCrossInt TypeApp -var ratCrossRat TypeApp -var realCrossReal TypeApp + initTPTPNativeTypes() +} -func InitTPTPArithmetic() { - // Types - tInt = MkTypeHint("$int") - tRat = MkTypeHint("$rat") - tReal = MkTypeHint("$real") +func InitDebugger() { + debug = Glob.CreateDebugger("typing") + debug_low_level = Glob.CreateDebugger("typing-low") +} - intCrossInt = MkTypeCross(tInt, tInt) - ratCrossRat = MkTypeCross(tRat, tRat) - realCrossReal = MkTypeCross(tReal, tReal) +func initTPTPNativeTypes() { + for _, ty := range AST.DefinedTPTPTypes().GetSlice() { + AddToGlobalEnv(ty.Symbol(), AST.TType()) + } + + AddToGlobalEnv( + AST.Id_eq.GetName(), + AST.MkTyPi( + Lib.MkListV("α"), + AST.MkTyFunc(AST.MkTyProd(Lib.MkListV(AST.MkTyVar("α"), AST.MkTyVar("α"))), AST.TProp()), + ), + ) - // Schemes // 1 - Binary predicates recordBinaryProp("$less") recordBinaryProp("$lesseq") @@ -81,8 +92,13 @@ func InitTPTPArithmetic() { recordBinaryInArgs("$remainder_f") // 3 - $quotient - SaveTypeScheme("$quotient", ratCrossRat, tRat) - SaveTypeScheme("$quotient", realCrossReal, tReal) + AddToGlobalEnv("$quotient", + AST.MkTyPi( + Lib.MkListV(ari_var, "rat_or_real"), + AST.MkTyFunc( + AST.MkTyProd(Lib.MkListV(AST.MkTyVar(ari_var), AST.MkTyVar(ari_var))), + AST.MkTyVar("rat_or_real")), + )) // 4 - Unary input arguments recordUnaryInArgs("$uminus") @@ -96,59 +112,60 @@ func InitTPTPArithmetic() { recordUnaryProp("$is_rat") // 6 - Conversion - recordConversion("$to_int", tInt) - recordConversion("$to_rat", tRat) - recordConversion("$to_real", tReal) + recordConversion("$to_int", AST.TInt()) + recordConversion("$to_rat", AST.TRat()) + recordConversion("$to_real", AST.TReal()) + + debug(Lib.MkLazy(func() string { return "TPTP native loaded in global environment" })) + debug_low_level(Lib.MkLazy(global_env.toString)) } func recordBinaryProp(name string) { - SaveTypeScheme(name, intCrossInt, defaultProp) - SaveTypeScheme(name, ratCrossRat, defaultProp) - SaveTypeScheme(name, realCrossReal, defaultProp) + AddToGlobalEnv( + name, + AST.MkTyPi( + Lib.MkListV(ari_var), + AST.MkTyFunc(AST.MkTyProd(Lib.MkListV(AST.MkTyVar(ari_var), AST.MkTyVar(ari_var))), AST.TProp()), + ), + ) } func recordBinaryInArgs(name string) { - SaveTypeScheme(name, intCrossInt, tInt) - SaveTypeScheme(name, ratCrossRat, tRat) - SaveTypeScheme(name, realCrossReal, tReal) + AddToGlobalEnv( + name, + AST.MkTyPi( + Lib.MkListV(ari_var), + AST.MkTyFunc(AST.MkTyProd(Lib.MkListV(AST.MkTyVar(ari_var), AST.MkTyVar(ari_var))), AST.MkTyVar(ari_var)), + ), + ) } func recordUnaryInArgs(name string) { - SaveTypeScheme(name, tInt, tInt) - SaveTypeScheme(name, tRat, tRat) - SaveTypeScheme(name, tReal, tReal) + AddToGlobalEnv( + name, + AST.MkTyPi( + Lib.MkListV(ari_var), + AST.MkTyFunc(AST.MkTyVar(ari_var), AST.MkTyVar(ari_var)), + ), + ) } func recordUnaryProp(name string) { - SaveTypeScheme(name, tInt, defaultProp) - SaveTypeScheme(name, tRat, defaultProp) - SaveTypeScheme(name, tReal, defaultProp) + AddToGlobalEnv( + name, + AST.MkTyPi( + Lib.MkListV(ari_var), + AST.MkTyFunc(AST.MkTyVar(ari_var), AST.TProp()), + ), + ) } -func recordConversion(name string, out TypeApp) { - SaveTypeScheme(name, tInt, out) - SaveTypeScheme(name, tRat, out) - SaveTypeScheme(name, tReal, out) -} - -func IsInt(tType TypeScheme) bool { return tType.Equals(tInt) } -func IsRat(tType TypeScheme) bool { return tType.Equals(tRat) } -func IsReal(tType TypeScheme) bool { return tType.Equals(tReal) } -func DefaultType() TypeApp { return defaultType } -func DefaultProp() TypeApp { return defaultProp } -func DefaultFunType(len int) TypeScheme { return defaultAppType(len, defaultType) } -func DefaultPropType(len int) TypeScheme { return defaultAppType(len, defaultProp) } - -func defaultAppType(len int, out TypeApp) TypeScheme { - if len == 0 { - return Glob.To[TypeScheme](out) - } else if len == 1 { - return MkTypeArrow(defaultType, out) - } else { - ts := []TypeApp{} - for i := 0; i < len; i++ { - ts = append(ts, defaultType) - } - return MkTypeArrow(MkTypeCross(ts...), out) - } +func recordConversion(name string, out AST.Ty) { + AddToGlobalEnv( + name, + AST.MkTyPi( + Lib.MkListV(ari_var), + AST.MkTyFunc(AST.MkTyVar(ari_var), out), + ), + ) } diff --git a/src/Typing/launch_rules.go b/src/Typing/launch_rules.go deleted file mode 100644 index 3eb3299b..00000000 --- a/src/Typing/launch_rules.go +++ /dev/null @@ -1,177 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -import ( - "fmt" - "reflect" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * This file manages everything related to parallelism / concurrency. - **/ - -type Reconstruct struct { - result bool - forms *AST.FormList - terms Lib.List[AST.Term] - err error -} - -/* Launches the first instance of applyRule. Do this to launch the typing system. */ -func launchRuleApplication(state Sequent, root *ProofTree) (AST.Form, error) { - superFatherChan := make(chan Reconstruct) - go tryApplyRule(state, root, superFatherChan) - res := <-superFatherChan - return treatReturns(res) -} - -/* Launches applyRule and manages the error return. */ -func tryApplyRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) { - select { - case <-fatherChan: // Message from the father received: it can only be a kill order. - default: - // No kill order, it's still properly typed, let's apply the next rules. - reconstruct := applyRule(state, root, fatherChan) - select { - case <-fatherChan: // Kill order received, it's finished anyway. - case fatherChan <- reconstruct: // Otherwise, send result to father. - } - } -} - -/* Launch each sequent in a goroutine if sequent length > 1. */ -func launchChildren(sequents []Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - if len(sequents) == 1 { - // Do not launch another goroutine if the applied rule has only 1 child. - return applyRule(sequents[0], root.addChildWith(sequents[0]), fatherChan) - } else { - // Create a channel for each child, and launch it in a goroutine. - chanTab := make([](chan Reconstruct), len(sequents)) - for i := range sequents { - childChan := make(chan Reconstruct) - chanTab[i] = childChan - go tryApplyRule(sequents[i], root.addChildWith(sequents[i]), childChan) - } - // If a child dies with an error, stops the typesearch procedure. - return selectSequents(chanTab, fatherChan) - } -} - -/** - * Waits for all the children to close. - * If an error is received, stops the type-search of every children and sends an error - * to the parent. - **/ -func selectSequents(chansTab [](chan Reconstruct), chanQuit chan Reconstruct) Reconstruct { - // Instantiation - cases := makeCases(chansTab, chanQuit) - hasAnswered := make([]bool, len(chansTab)) // Everything to false - remaining, indexQuit := len(chansTab), len(chansTab) - var errorFound error = nil - - forms := make([]AST.Form, len(chansTab)) - terms := Lib.MkList[AST.Term](len(chansTab)) - - // Wait for all children to finish. - for remaining > 0 && errorFound == nil { - index, value, _ := reflect.Select(cases) - remaining-- - if index == indexQuit { - errorFound = fmt.Errorf("father detected an error") - } else { - res := value.Interface().(Reconstruct) - hasAnswered[index] = true - if !res.result { - errorFound = res.err - } else { - // Once the child sends back to the father, it should only have one item. - if res.forms != nil && res.forms.Len() == 1 { - forms[index] = res.forms.Get(0) - } - if res.terms.Len() == 1 { - terms.Upd(index, res.terms.At(0)) - } - } - } - } - - selectCleanup(errorFound, hasAnswered, chansTab) - return Reconstruct{result: errorFound == nil, forms: AST.NewFormList(forms...), terms: terms, err: errorFound} -} - -/* Utils functions for selectSequents */ - -/* Makes the array of cases from the channels */ -func makeCases(chansTab [](chan Reconstruct), chanQuit chan Reconstruct) []reflect.SelectCase { - cases := make([]reflect.SelectCase, len(chansTab)+1) - // Children - for i, chan_ := range chansTab { - cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(chan_)} - } - // Father - cases[len(chansTab)] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(chanQuit)} - return cases -} - -/* If an error was found, kills all the children. */ -func selectCleanup(errorFound error, hasAnswered []bool, chansTab [](chan Reconstruct)) { - if errorFound != nil { - for i, answered := range hasAnswered { - if !answered { - select { - case <-chansTab[i]: // Filter out, he already responded - case chansTab[i] <- Reconstruct{result: false, err: errorFound}: // Kill child - } - } - } - } -} - -/* Treats the different return types of the system. */ -func treatReturns(res Reconstruct) (AST.Form, error) { - if !res.result { - return nil, res.err - } else { - if res.forms.Len() == 0 { - return nil, res.err - } - if res.forms.Len() > 1 { - return nil, fmt.Errorf("more than one formula is returned by the typing system") - } - return res.forms.Get(0), res.err - } -} diff --git a/src/Typing/prooftree_dump.go b/src/Typing/prooftree_dump.go deleted file mode 100644 index b2e82f5d..00000000 --- a/src/Typing/prooftree_dump.go +++ /dev/null @@ -1,151 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -import ( - "encoding/json" - "errors" - "fmt" - "os" - "strings" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" -) - -/** - * This file contains the methods to dump a prooftree in a json. - **/ - -/* Dumps the prooftree in a json. */ -func (root *ProofTree) DumpJson() error { - // Dump folder should be a flag in the future - dump := "../visualization/types/" - // Create a new file - i := 0 - for fileExists(getFileName(dump, i)) { - i++ - } - - f, err := os.OpenFile(getFileName(dump, i), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return err - } - json, err := root.dump() - - if err != nil { - return err - } - - _, err = f.WriteString(json) - Glob.PrintInfo("DUMP", fmt.Sprintf("Dumped type proof in %s\n", f.Name())) - return err -} - -/* Creates file if not exists, dump informations in it, and calls recursively on each child */ -func (root *ProofTree) dump() (string, error) { - varsString := []string{} - var consequence string = "" - var ts string - if root.typeScheme != nil { - ts = root.typeScheme.ToString() - } - - for _, var_ := range root.sequent.localContext.vars { - varsString = append(varsString, var_.ToString()) - } - for _, var_ := range root.sequent.localContext.typeVars { - varsString = append(varsString, fmt.Sprintf("%s: Type", var_.ToString())) - } - - switch whatIsSet(root.sequent.consequence) { - case formIsSet: - consequence = root.sequent.consequence.f.ToString() - if root.typeScheme == nil { - ts = root.sequent.consequence.f.GetType().ToString() - } - case termIsSet: - consequence = root.sequent.consequence.t.ToString() - if root.typeScheme == nil { - if root.sequent.consequence.t.(AST.TypedTerm).GetTypeHint() == nil { - ts = root.sequent.consequence.t.(AST.TypedTerm).GetTypeApp().ToString() - } else { - ts = root.sequent.consequence.t.(AST.TypedTerm).GetTypeHint().ToString() - } - } - case typeIsSet: - consequence = root.sequent.consequence.a.ToString() - if root.typeScheme == nil { - ts = "Type" - } - } - - childrenProofs := []string{} - - for _, child := range root.children { - bytes, err := child.dump() - if err != nil { - return "", err - } - childrenProofs = append(childrenProofs, bytes) - } - - bytes, err := json.Marshal(&struct { - LocalContext string `json:"localContext"` - Consequence string `json:"consequence"` - TypeScheme string `json:"typeScheme"` - Rule string `json:"rule"` - Children []string `json:"children"` - }{ - LocalContext: strings.Join(varsString, ", "), - Consequence: consequence, - TypeScheme: ts, - Rule: root.appliedRule, - Children: childrenProofs, - }) - - return strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(string(bytes), "\\", ""), "\"{", "{"), "}\"", "}"), err -} - -/* Utils */ - -/* Checks if file exists at given path */ -func fileExists(path string) bool { - _, err := os.Stat(path) - return !errors.Is(err, os.ErrNotExist) -} - -/* Create a formated file name */ -func getFileName(folder string, i int) string { - return fmt.Sprintf("%sproof_%d.json", folder, i) -} diff --git a/src/Typing/rules.go b/src/Typing/rules.go index ea0a22a3..1b2332ef 100644 --- a/src/Typing/rules.go +++ b/src/Typing/rules.go @@ -30,207 +30,295 @@ * knowledge of the CeCILL license and that you accept its terms. **/ +/** + * This file is the entry point to perform typing of a formula. + * It implements all the rules. +**/ + package Typing import ( - "reflect" - + "fmt" "github.com/GoelandProver/Goeland/AST" "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) -/** - * This file contains the functions to create a typing proof tree. - * It defines the TypingProofTree structure and all the rules to check if a - * system is well-typed. - **/ - -/* Stores the consequence of the sequent */ -type Consequence struct { - f AST.Form - t AST.Term - a AST.TypeApp - s AST.TypeScheme -} +var label = "typing" -/* A Sequent is formed of a global context, local context, and a formula or a term to type */ -type Sequent struct { - globalContext GlobalContext - localContext LocalContext - consequence Consequence -} +func TypeCheck(form AST.Form) bool { + debug(Lib.MkLazy(func() string { return fmt.Sprintf("Launching type checking on %s", form.ToString()) })) -/* Makes a typing prooftree to output. */ -type ProofTree struct { - sequent Sequent - appliedRule string - typeScheme AST.TypeScheme - children []*ProofTree + return typecheckForm(emptyCon(), form) } -/* ProofTree meta-type */ -var metaType AST.TypeHint +func typecheckForm(con Con, form AST.Form) bool { + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Trying to type-check: %s |- %s : o", con.toString(), form.ToString()) + })) -/* ProofTree methods */ + switch f := form.(type) { + case AST.Bot, AST.Top: + return true + case AST.Pred: + return checkFunctional( + con, + f.GetID().GetName(), + f.GetTyArgs(), + f.GetArgs(), + Lib.MkLazy(func() string { return form.ToString() }), + ) + + case AST.Not, AST.And, AST.Or, AST.Imp, AST.Equ: + return typecheckRec( + con, + f.GetChildFormulas(), + Lib.NewList[Lib.Pair[AST.Term, AST.Ty]](), + Lib.NewList[AST.Ty](), + ) + + case AST.All: + return typecheckRec( + con.addTypedVars(f.GetVarList()), + Lib.MkListV(f.GetForm()), + Lib.NewList[Lib.Pair[AST.Term, AST.Ty]](), + Lib.NewList[AST.Ty](), + ) -/* Creates and adds a child to the prooftree and returns it. */ -func (pt *ProofTree) addChildWith(sequent Sequent) *ProofTree { - child := ProofTree{ - sequent: sequent, - children: []*ProofTree{}, + case AST.Ex: + return typecheckRec( + con.addTypedVars(f.GetVarList()), + Lib.MkListV(f.GetForm()), + Lib.NewList[Lib.Pair[AST.Term, AST.Ty]](), + Lib.NewList[AST.Ty](), + ) } - pt.children = append(pt.children, &child) - return &child + + Glob.Anomaly( + label, + fmt.Sprintf("%s is not a known internal formula", form.ToString()), + ) + return false } -var globalContextIsWellTyped bool = false +func typecheckTerm(con Con, term AST.Term, ty AST.Ty) bool { + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Trying to type-check: %s |- %s : %s", con.toString(), term.ToString(), ty.ToString()) + })) -/** - * Tries to type form. - * If not well-typed, will return an error. - **/ -func WellFormedVerification(form AST.Form, dump bool) error { - // Instanciate meta type - metaType = AST.MkTypeHint("$tType") + switch t := term.(type) { + case AST.Var: + if !con.contains(t.GetName(), ty) { + Glob.Fatal( + label, + fmt.Sprintf( + "Variable %s is either not in the context or should not have type %s\nContext: %s", + t.GetName(), + ty.ToString(), + con.toString(), + )) + return false + } - // Second pass to type variables & to give the typevars to functions and predicates - form = SecondPass(form) + return typecheckRec( + con, + Lib.NewList[AST.Form](), + Lib.NewList[Lib.Pair[AST.Term, AST.Ty]](), + Lib.MkListV(ty), + ) - globalContext, err := createGlobalContext(AST.GetGlobalContext()) - if err != nil { - return err + case AST.Fun: + return checkFunctional( + con, + t.GetID().GetName(), + t.GetTyArgs(), + t.GetArgs(), + Lib.MkLazy(func() string { return t.ToString() }), + ) } - // Sequent creation - state := Sequent{ - globalContext: globalContext, - localContext: LocalContext{vars: []AST.Var{}, typeVars: []AST.TypeVar{}}, - consequence: Consequence{f: form}, - } + Glob.Anomaly( + label, + fmt.Sprintf("Only bound variables and functions should be typechecked, but found %s", term.ToString()), + ) + return false +} - // Prooftree creation - root := ProofTree{ - sequent: state, - children: []*ProofTree{}, - } +func typecheckType(con Con, ty AST.Ty) bool { + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Trying to type-check: %s |- %s : %s", + con.toString(), ty.ToString(), AST.TType().ToString()) + })) - // Launch the typing system - _, err = launchRuleApplication(state, &root) + switch nty := ty.(type) { + case AST.TyBound: + if !con.contains(nty.GetName(), AST.TType()) { + Glob.PrintInfo("Context", con.toString()) + Glob.Fatal( + label, + fmt.Sprintf( + "Variable %s is either not in the context or is not a type variable\nContext: %s", + nty.ToString(), + con.toString(), + )) + return false + } - // Dump prooftree in json if it's asked & there is no error - if dump && err == nil { - err = root.DumpJson() - } + return true - return err -} + case AST.TyConstr: + oty := QueryGlobalEnv(nty.Symbol()) -/* Reconstructs a Form depending on what the children has returned */ -func reconstructForm(reconstruction Reconstruct, baseForm AST.Form) Reconstruct { - if !reconstruction.result { - return reconstruction - } + switch rty := oty.(type) { + case Lib.Some[AST.Ty]: + args := AST.GetArgsTy(rty.Val) + if args.Len() != nty.Args().Len() { + Glob.Fatal( + label, + fmt.Sprintf( + "Type constructor %s expects %d arguments, got %d", + nty.Symbol(), + args.Len(), + nty.Args().Len(), + ), + ) + return false + } - var f AST.Form - switch form := baseForm.(type) { - case AST.All: - f = AST.MakeAll(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.Get(1), form)) - case AST.AllType: - f = AST.MakeAllType(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.Get(1), form)) - case AST.Ex: - f = AST.MakeEx(form.GetIndex(), form.GetVarList(), unquantify(reconstruction.forms.Get(1), form)) - case AST.And: - f = AST.MakeAnd(form.GetIndex(), reconstruction.forms) - case AST.Or: - f = AST.MakeOr(form.GetIndex(), reconstruction.forms) - case AST.Imp: - f = AST.MakeImp(form.GetIndex(), reconstruction.forms.Get(0), reconstruction.forms.Get(1)) - case AST.Equ: - f = AST.MakeEqu(form.GetIndex(), reconstruction.forms.Get(0), reconstruction.forms.Get(1)) - case AST.Not: - f = AST.MakeNot(form.GetIndex(), reconstruction.forms.Get(0)) - case AST.Pred: - // The len(form.GetTypeVars()) first children launched are children for typevars. - // So the len(form.GetTypeVars()) first children will return - if reconstruction.terms.Len() > len(form.GetTypeVars()) { - terms := Lib.MkListV(reconstruction.terms.Get( - len(form.GetTypeVars()), - reconstruction.terms.Len(), - )...) - f = AST.MakePred( - form.GetIndex(), - form.GetID(), - terms, - form.GetTypeVars(), - form.GetType(), + if nty.Args().Empty() { + return true + } + + return typecheckRec( + con, + Lib.NewList[AST.Form](), + Lib.NewList[Lib.Pair[AST.Term, AST.Ty]](), + nty.Args(), ) - } else { - f = AST.MakePred( - form.GetIndex(), - form.GetID(), - Lib.NewList[AST.Term](), - form.GetTypeVars(), - form.GetType(), + + case Lib.None[AST.Ty]: + Glob.Anomaly( + label, + fmt.Sprintf("Unknown type %s", nty.ToString()), ) } - case AST.Top, AST.Bot: - f = baseForm } - return Reconstruct{result: true, forms: AST.NewFormList(f), err: nil} + Glob.Anomaly( + label, + fmt.Sprintf("On typechecking of types: expected atomic type, got %s", ty.ToString()), + ) + return false } -/* Reconstructs a Term depending on what the children has returned */ -func reconstructTerm(reconstruction Reconstruct, baseTerm AST.Term) Reconstruct { - if !reconstruction.result { - return reconstruction +func checkFunctional( + con Con, + name string, + tys Lib.List[AST.Ty], + args Lib.List[AST.Term], + debug_str Lib.Lazy[string], +) bool { + oty := QueryEnvInstance(name, tys) + switch ty := oty.(type) { + case Lib.Some[AST.Ty]: + debug_low_level(Lib.MkLazy(func() string { + return fmt.Sprintf("%s has a functional scheme instantiated to %s", debug_str.Run(), ty.Val.ToString()) + })) + + instantiated_ty := AST.GetArgsTy(ty.Val) + debug_low_level(Lib.MkLazy(func() string { + return fmt.Sprintf("Arguments will be typechecked against: [%s]", + Lib.ListToString(instantiated_ty, ", ", "")) + })) + + terms_checker := buildTermCheckList( + debug_str, + ty.Val, + args, + instantiated_ty, + ) + tys.Append(AST.GetOutTy(ty.Val)) + + return typecheckRec(con, Lib.NewList[AST.Form](), terms_checker, tys) + + case Lib.None[AST.Ty]: + Glob.Fatal( + label, + fmt.Sprintf("Type of %s not found in the global environment", debug_str.Run()), + ) } + return false +} - // fun: reconstruct with children terms - if Glob.Is[AST.Fun](baseTerm) { - termFun := Glob.To[AST.Fun](baseTerm) - var fun AST.Fun - // The len(form.GetTypeVars()) first children launched are children for typevars. - // So the len(form.GetTypeVars()) first children will return - if reconstruction.terms.Len() > len(termFun.GetTypeVars()) { - terms := Lib.MkListV(reconstruction.terms.Get( - len(termFun.GetTypeVars()), - reconstruction.terms.Len(), - )...) - fun = AST.MakerFun( - termFun.GetID(), - terms, - termFun.GetTypeVars(), - termFun.GetTypeHint(), - ) - } else { - fun = AST.MakerFun( - termFun.GetID(), - Lib.NewList[AST.Term](), - termFun.GetTypeVars(), - termFun.GetTypeHint(), - ) - } - return Reconstruct{result: true, terms: Lib.MkListV[AST.Term](fun), err: nil} +func typecheckRec( + con Con, + forms Lib.List[AST.Form], + typed_terms Lib.List[Lib.Pair[AST.Term, AST.Ty]], + tys Lib.List[AST.Ty], +) bool { + + debug(Lib.MkLazy(func() string { + return fmt.Sprintf("Next typecheck: forms (%v), terms (%v), types (%v)", + !forms.Empty(), !typed_terms.Empty(), !tys.Empty()) + })) + + calls := []func(chan bool){} + + for _, form := range forms.GetSlice() { + loop_form := form + calls = append(calls, func(outchan chan bool) { + outchan <- typecheckForm(con, loop_form) + }) + } + + for _, typed_term := range typed_terms.GetSlice() { + loop_term := typed_term + calls = append(calls, func(outchan chan bool) { + outchan <- typecheckTerm(con, loop_term.Fst, loop_term.Snd) + }) + } + + for _, ty := range tys.GetSlice() { + loop_ty := ty + calls = append(calls, func(outchan chan bool) { + outchan <- typecheckType(con, loop_ty) + }) + } + + res, err := Lib.GenericParallel( + calls, + func(x, y bool) bool { return x && y }, + true, // Neutral of the operation + ) + + if err != nil { + Glob.Anomaly( + label, + fmt.Sprintf("Encountered a Lib error: %s", err.Error()), + ) } - return Reconstruct{result: true, terms: Lib.MkListV(baseTerm), err: nil} + return res } -/* Utils for reconstructions function */ - -/* Removes all the quantifiers of form of the same type of quant. */ -func unquantify(form AST.Form, quant AST.Form) AST.Form { - for reflect.TypeOf(form) == reflect.TypeOf(quant) { - switch quant.(type) { - case AST.All: - form = Glob.To[AST.All](form).GetForm() - case AST.AllType: - form = Glob.To[AST.AllType](form).GetForm() - case AST.Ex: - form = Glob.To[AST.Ex](form).GetForm() - } +func buildTermCheckList( + debug_str Lib.Lazy[string], + ty AST.Ty, + terms Lib.List[AST.Term], + tys Lib.List[AST.Ty], +) Lib.List[Lib.Pair[AST.Term, AST.Ty]] { + if terms.Len() != tys.Len() { + Glob.Fatal( + label, + fmt.Sprintf("Expected %d arguments in %s (which has type %s), but got %d", + tys.Len(), debug_str.Run(), ty.ToString(), terms.Len()), + ) + return Lib.NewList[Lib.Pair[AST.Term, AST.Ty]]() + } + + ls := Lib.MkList[Lib.Pair[AST.Term, AST.Ty]](terms.Len()) + for i := range terms.GetSlice() { + ls.Upd(i, Lib.MkPair(terms.At(i), tys.At(i))) } - return form + return ls } diff --git a/src/Typing/term_rules.go b/src/Typing/term_rules.go deleted file mode 100644 index 62ae0d6c..00000000 --- a/src/Typing/term_rules.go +++ /dev/null @@ -1,215 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -import ( - "fmt" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * This file contains the rules for typing terms, and also the App rule. - * The App rule is used for predicates and functions. - **/ - -/* Applies the App rule for predicates or functions */ -func applyAppRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - var index int - var id AST.Id - var terms Lib.List[AST.Term] - var vars []AST.TypeApp - - if whatIsSet(state.consequence) == formIsSet { - index = (state.consequence.f).(AST.Pred).GetIndex() - id = (state.consequence.f).(AST.Pred).GetID() - terms = (state.consequence.f).(AST.Pred).GetArgs() - vars = (state.consequence.f).(AST.Pred).GetTypeVars() - } else { - id = (state.consequence.t).(AST.Fun).GetID() - terms = (state.consequence.t).(AST.Fun).GetArgs() - vars = (state.consequence.t).(AST.Fun).GetTypeVars() - } - - root.appliedRule = "App" - - // Search for the ID in the global context - typeScheme, err := state.globalContext.getTypeScheme(id, vars, terms) - if err != nil { - return Reconstruct{ - result: false, - err: err, - } - } - - // Affect new type scheme to the prooftree - root.typeScheme = typeScheme - primitives := typeScheme.GetPrimitives() - - // Type predicate or function - if whatIsSet(state.consequence) == formIsSet { - fTyped := AST.MakePred(index, id, terms, vars, typeScheme) - return reconstructForm(launchChildren( - createAppChildren(state, vars, terms, primitives), - root, - fatherChan, - ), fTyped) - } else { - fTyped := AST.MakerFun(id, terms, vars, typeScheme) - return reconstructTerm(launchChildren(createAppChildren(state, vars, terms, primitives), root, fatherChan), fTyped) - } -} - -/* Applies the Var rule for a term variable. */ -func applyVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add applied rule to the prooftree - root.appliedRule = "Var" - - // Find current variable in the local context - if _, ok := getTermFromLocalContext(state.localContext, state.consequence.t); !ok { - return Reconstruct{ - result: false, - err: fmt.Errorf("term %s not found in the local context", state.consequence.t.ToString()), - } - } - - // No consequence: next rule is the WF rule. - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{}, - }, - } - - return reconstructTerm(launchChildren(children, root, fatherChan), state.consequence.t) -} - -/* Utils functions */ - -/** - * Takes all the types of the terms and makes a cross product of everything - **/ -func getArgsTypes( - context GlobalContext, - terms Lib.List[AST.Term], -) (AST.TypeApp, error) { - if terms.Len() == 0 { - return nil, nil - } - - var types []AST.TypeApp - - for _, term := range terms.GetSlice() { - switch tmpTerm := term.(type) { - case AST.Fun: - typeScheme, err := context.getTypeScheme( - tmpTerm.GetID(), - tmpTerm.GetTypeVars(), - tmpTerm.GetArgs(), - ) - if err != nil { - return nil, err - } - if typeScheme == nil { - return nil, fmt.Errorf("function %s not found in global context", tmpTerm.GetName()) - } - types = append(types, AST.GetOutType(typeScheme)) - case AST.Var: - // Variables can't be of type TypeScheme, so this line shouldn't fail. - types = append(types, tmpTerm.GetTypeApp()) - // There shouldn't be Metas yet. - case AST.Meta: - debug(Lib.MkLazy(func() string { return "Found a Meta while typing everything." })) - // ID is filtered out - } - } - - if len(types) == 1 { - return types[0], nil - } - typeCross := AST.MkTypeCross(types[0], types[1]) - for i := 2; i < len(types); i += 1 { - typeCross = AST.MkTypeCross(typeCross, types[i]) - } - return typeCross, nil -} - -/* Creates children for app rule */ -func createAppChildren( - state Sequent, - vars []AST.TypeApp, - terms Lib.List[AST.Term], - primitives []AST.TypeApp, -) []Sequent { - children := []Sequent{} - - // 1 for each type in the vars - for _, var_ := range vars { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{a: var_}, - }) - } - - // 1 for each term - for i, term := range terms.GetSlice() { - switch t := term.(type) { - case AST.Fun: - term = AST.MakerFun(t.GetID(), t.GetArgs(), t.GetTypeVars(), primitives[i].(AST.TypeScheme)) - case AST.Meta: - term = AST.MakeMeta(t.GetIndex(), t.GetOccurence(), t.GetName(), t.GetFormula(), primitives[i]) - case AST.Var: - term = AST.MakeVar(t.GetIndex(), t.GetName(), primitives[i]) - } - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{t: term}, - }) - } - - return children -} - -/* Finds the given term in the local context, returns false if it couldn't */ -func getTermFromLocalContext(localContext LocalContext, term AST.Term) (AST.Var, bool) { - for _, var_ := range localContext.vars { - if var_.Equals(term) { - return var_, true - } - } - return AST.Var{}, false -} diff --git a/src/Typing/type.go b/src/Typing/type.go deleted file mode 100644 index efb7e599..00000000 --- a/src/Typing/type.go +++ /dev/null @@ -1,196 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -import ( - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -var debug Glob.Debugger - -func InitDebugger() { - debug = Glob.CreateDebugger("typing") -} - -/** - * This file implements a second pass on the given formula to: - * - Type the variables - * - Give a type to the polymorph predicates / functions - **/ - -func SecondPass(form AST.Form) AST.Form { - after := secondPassAux(form, []AST.Var{}, []AST.TypeApp{}) - return after -} - -func secondPassAux(form AST.Form, vars []AST.Var, types []AST.TypeApp) AST.Form { - switch f := form.(type) { - case AST.Pred: - terms := nArySecondPassTerms(f.GetArgs(), vars, types) - - // Special case: defined predicate. We need to infer types. - if f.GetID().Equals(AST.Id_eq) { - return AST.MakePred( - f.GetIndex(), - f.GetID(), - terms, - []AST.TypeApp{ - AST.GetOutType( - Glob.To[AST.TypedTerm, AST.Term](terms.At(0)).GetTypeHint(), - )}) - } - - // Real case: classical predicate, it should be given - return AST.MakePred(f.GetIndex(), f.GetID(), terms, f.GetTypeVars()) - case AST.And: - return AST.MakeAnd(f.GetIndex(), nArySecondPass(f.FormList, vars, types)) - case AST.Or: - return AST.MakeOr(f.GetIndex(), nArySecondPass(f.FormList, vars, types)) - case AST.Imp: - return AST.MakeImp(f.GetIndex(), secondPassAux(f.GetF1(), vars, types), secondPassAux(f.GetF2(), vars, types)) - case AST.Equ: - return AST.MakeEqu(f.GetIndex(), secondPassAux(f.GetF1(), vars, types), secondPassAux(f.GetF2(), vars, types)) - case AST.Not: - return AST.MakeNot(f.GetIndex(), secondPassAux(f.GetForm(), vars, types)) - case AST.All: - return AST.MakeAll(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), append(vars, f.GetVarList()...), types)) - case AST.Ex: - return AST.MakeEx(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), append(vars, f.GetVarList()...), types)) - case AST.AllType: - return AST.MakeAllType(f.GetIndex(), f.GetVarList(), secondPassAux(f.GetForm(), vars, append(types, Glob.ConvertList[AST.TypeVar, AST.TypeApp](f.GetVarList())...))) - } - return form -} - -func secondPassTerm(term AST.Term, vars []AST.Var, types []AST.TypeApp) AST.Term { - switch t := term.(type) { - case AST.Fun: - terms := nArySecondPassTerms(t.GetArgs(), vars, types) - - // - It's a function - outType := func(term AST.Term) AST.TypeApp { - return AST.GetOutType(Glob.To[AST.TypedTerm](term).GetTypeHint()) - } - - termsType := []AST.TypeApp{} - for _, tm := range terms.GetSlice() { - termsType = append(termsType, outType(tm)) - } - - return AST.MakerFun(t.GetID(), terms, t.GetTypeVars(), - getTypeOfFunction(t.GetName(), t.GetTypeVars(), termsType)) - - case AST.Var: - return t - } - return term -} - -func nArySecondPass(forms *AST.FormList, vars []AST.Var, types []AST.TypeApp) *AST.FormList { - res := AST.NewFormList() - - for _, form := range forms.Slice() { - res.Append(secondPassAux(form, vars, types)) - } - - return res -} - -func nArySecondPassTerms( - terms Lib.List[AST.Term], - vars []AST.Var, - types []AST.TypeApp, -) Lib.List[AST.Term] { - resTerms := Lib.NewList[AST.Term]() - - for _, term := range terms.GetSlice() { - t := secondPassTerm(term, vars, types) - - if t != nil { - resTerms.Append(t) - } - } - - return resTerms -} - -func getTypeOfFunction(name string, vars []AST.TypeApp, termsType []AST.TypeApp) AST.TypeScheme { - // Build TypeCross from termsType - var tt []AST.TypeApp - if len(termsType) >= 2 { - tc := AST.MkTypeCross(termsType[0], termsType[1]) - for i := 2; i < len(termsType); i += 1 { - tc = AST.MkTypeCross(tc, termsType[i]) - } - tt = []AST.TypeApp{tc} - } else { - tt = termsType - } - - simpleTypeScheme := AST.GetType(name, tt...) - if simpleTypeScheme != nil { - if Glob.Is[AST.QuantifiedType](simpleTypeScheme) { - return Glob.To[AST.QuantifiedType](simpleTypeScheme).Instanciate(vars) - } - return simpleTypeScheme - } - - typeScheme := AST.GetPolymorphicType(name, len(vars), len(termsType)) - - if typeScheme != nil { - // Instantiate type scheme with actual types - typeScheme = Glob.To[AST.QuantifiedType](typeScheme).Instanciate(vars) - } else { - // As only distinct objects are here, it should work with only this. - // I leave the other condition if others weirderies are found later. - if len(termsType) == 0 { - AST.SaveConstant(name, Glob.To[AST.TypeApp](AST.DefaultFunType(0))) - } - /* - else { - type_ := DefaultFunType(len(termsType)) - if len(termsType) == 1 { - SaveTypeScheme(name, GetInputType(type_)[0], GetOutType(type_)) - } else { - SaveTypeScheme(name, AST.MkTypeCross(GetInputType(type_)...), GetOutType(type_)) - } - } - */ - typeScheme = AST.DefaultFunType(0) - - } - - return typeScheme -} diff --git a/src/Typing/type_rules.go b/src/Typing/type_rules.go deleted file mode 100644 index 82f03ced..00000000 --- a/src/Typing/type_rules.go +++ /dev/null @@ -1,220 +0,0 @@ -/** -* Copyright 2022 by the authors (see AUTHORS). -* -* Goéland is an automated theorem prover for first order logic. -* -* This software is governed by the CeCILL license under French law and -* abiding by the rules of distribution of free software. You can use, -* modify and/ or redistribute the software under the terms of the CeCILL -* license as circulated by CEA, CNRS and INRIA at the following URL -* "http://www.cecill.info". -* -* As a counterpart to the access to the source code and rights to copy, -* modify and redistribute granted by the license, users are provided only -* with a limited warranty and the software's author, the holder of the -* economic rights, and the successive licensors have only limited -* liability. -* -* In this respect, the user's attention is drawn to the risks associated -* with loading, using, modifying and/or developing or reproducing the -* software by the user in light of its specific status of free software, -* that may mean that it is complicated to manipulate, and that also -* therefore means that it is reserved for developers and experienced -* professionals having in-depth computer knowledge. Users are therefore -* encouraged to load and test the software's suitability as regards their -* requirements in conditions enabling the security of their systems and/or -* data to be ensured and, more generally, to use and operate it in the -* same conditions as regards security. -* -* The fact that you are presently reading this means that you have had -* knowledge of the CeCILL license and that you accept its terms. -**/ - -package Typing - -import ( - "fmt" - - "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" - "github.com/GoelandProver/Goeland/Lib" -) - -/** - * This file contains the rules for typing terms, and also the App rule. - * The App rule is used for predicates and functions. - **/ - -/* Applies the Var rule for a type variable: erase consequence */ -func applyLocalTypeVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add applied rule to the prooftree - root.appliedRule = "Var" - - // Find current variable in the local context - if _, ok := getTypeFromLocalContext(state.localContext, state.consequence.a.(AST.TypeVar)); !ok { - return Reconstruct{ - result: false, - err: fmt.Errorf("TypeVar %s not found in the local context", state.consequence.a.ToString()), - } - } - - // No consequence: next rule is the WF rule. - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{}, - }, - } - - return launchChildren(children, root, fatherChan) -} - -/* Applies the Var rule for a type hint: erase consequence */ -func applyGlobalTypeVarRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add applied rule to the prooftree - root.appliedRule = "Var" - - // Find current variable in the local context - if found := state.globalContext.isTypeInContext(Glob.To[AST.TypeScheme](state.consequence.a)); !found { - return Reconstruct{ - result: false, - err: fmt.Errorf("TypeVar %s not found in the global context", state.consequence.a.ToString()), - } - } - - // No consequence: next rule is the WF rule. - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{}, - }, - } - - return launchChildren(children, root, fatherChan) -} - -/* Applies Type rule: erase consequence */ -func applyTypeWFRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add applied rule to the prooftree - root.appliedRule = "Type" - - // WF child - children := []Sequent{ - { - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{}, - }, - } - - return launchChildren(children, root, fatherChan) -} - -/* Applies Cross rule */ -func applyCrossRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - // Add applied rule to the prooftree - root.appliedRule = "Cross" - - if tc, ok := state.consequence.a.(AST.TypeCross); ok { - // Construct a child for every type recovered - return launchChildren(constructWithTypes(state, tc.GetAllUnderlyingTypes()), root, fatherChan) - } else { - return Reconstruct{ - result: false, - err: fmt.Errorf("CrossRule type on something that is not a TypeCross: %s", state.consequence.a.ToString()), - } - } -} - -/* Sym rule: a child for each type in the input, and one for the output if it's a function */ -func applySymRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - root.appliedRule = "Sym" - - primitives := state.consequence.s.GetPrimitives() - out := AST.GetOutType(state.consequence.s) - - newLocalContext := state.localContext.copy() - if qt, found := state.consequence.s.(AST.QuantifiedType); found { - newLocalContext.typeVars = append(newLocalContext.typeVars, qt.QuantifiedVars()...) - } - - children := []Sequent{} - if Glob.Is[AST.TypeScheme](out) { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: newLocalContext, - consequence: Consequence{a: out}, - }) - } - - for _, type_ := range primitives[:len(primitives)-1] { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: newLocalContext, - consequence: Consequence{a: type_}, - }) - } - - return launchChildren(children, root, fatherChan) -} - -/* AppType rule: a child for each type in the input, and checks if the parameterized type exists. */ -func applyAppTypeRule(state Sequent, root *ProofTree, fatherChan chan Reconstruct) Reconstruct { - root.appliedRule = "App" - - type_ := state.consequence.a.(AST.ParameterizedType) - types := type_.GetParameters() - - // Search for the ID in the global context - if !state.globalContext.parameterizedTypesContains(type_.GetName()) { - return Reconstruct{ - result: false, - err: fmt.Errorf("parameterized Type %s not in context", type_.ToString()), - } - } - - children := []Sequent{} - for _, type_ := range types { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{a: type_}, - }) - } - - result := launchChildren(children, root, fatherChan) - - // Only one term needs to be returned because the ParameterizedType is counted as one. - return Reconstruct{ - result: result.result, - err: result.err, - terms: Lib.NewList[AST.Term](), - } -} - -/* Utils functions */ - -/* Finds the given term in the local context, returns false if it couldn't */ -func getTypeFromLocalContext(localContext LocalContext, typeApp AST.TypeVar) (AST.TypeApp, bool) { - for _, type_ := range localContext.typeVars { - if typeApp.Equals(type_) { - return type_, true - } - } - return AST.TypeVar{}, false -} - -/* Constructs all the children of a composed type */ -func constructWithTypes(state Sequent, types []AST.TypeApp) []Sequent { - children := []Sequent{} - for _, type_ := range types { - children = append(children, Sequent{ - globalContext: state.globalContext, - localContext: state.localContext.copy(), - consequence: Consequence{a: type_}, - }) - } - return children -} diff --git a/src/Unif/code-trees.go b/src/Unif/code-trees.go index 0f8687ac..6beb3371 100644 --- a/src/Unif/code-trees.go +++ b/src/Unif/code-trees.go @@ -58,11 +58,11 @@ func (c CodeBlock) Copy() CodeBlock { type Node struct { value CodeBlock children []*Node - formulae *AST.FormList + formulas Lib.List[AST.Form] } func NewNode() *Node { - return &Node{CodeBlock{}, []*Node{}, AST.NewFormList()} + return &Node{CodeBlock{}, []*Node{}, Lib.NewList[AST.Form]()} } func (n Node) getValue() CodeBlock { @@ -71,8 +71,8 @@ func (n Node) getValue() CodeBlock { func (n Node) getChildren() []*Node { return CopyNodeList(n.children) } -func (n Node) getFormulae() *AST.FormList { - return n.formulae.Copy() +func (n Node) getFormulas() Lib.List[AST.Form] { + return Lib.ListCpy(n.formulas) } /* Check if a node is empty */ @@ -81,13 +81,13 @@ func (n Node) IsEmpty() bool { } /* Make data struct */ -func (n Node) MakeDataStruct(fl *AST.FormList, is_pos bool) DataStructure { +func (n Node) MakeDataStruct(fl Lib.List[AST.Form], is_pos bool) DataStructure { return makeCodeTreeFromAtomic(fl, is_pos) } /* Copy a datastruct */ func (n Node) Copy() DataStructure { - return Node{n.getValue(), n.getChildren(), n.getFormulae()} + return Node{n.getValue(), n.getChildren(), n.getFormulas()} } /********************/ @@ -96,14 +96,14 @@ func (n Node) Copy() DataStructure { /* The Node is a leaf when it contains at least one formulae. */ func (n Node) isLeaf() bool { - return n.getFormulae().Len() > 0 + return n.getFormulas().Len() > 0 } /* Make two code trees (tree_pos and tree_neg) from st.atomic */ -func makeCodeTreeFromAtomic(lf *AST.FormList, is_pos bool) *Node { - form := AST.NewFormList() +func makeCodeTreeFromAtomic(lf Lib.List[AST.Form], is_pos bool) *Node { + form := Lib.NewList[AST.Form]() - for _, f := range lf.Slice() { + for _, f := range lf.GetSlice() { switch nf := f.(type) { case AST.Pred: if is_pos { @@ -126,10 +126,10 @@ func makeCodeTreeFromAtomic(lf *AST.FormList, is_pos bool) *Node { } /* Makes a Code Tree from a Sequence of instructions */ -func makeCodeTree(forms *AST.FormList) *Node { +func makeCodeTree(forms Lib.List[AST.Form]) *Node { root := makeNode(nil) - for _, f := range forms.Slice() { + for _, f := range forms.GetSlice() { f_tmp := f.Copy() form_tmp := ParseFormula(f_tmp) root.insert(form_tmp) @@ -152,13 +152,13 @@ func makeNode(block CodeBlock) *Node { n := new(Node) n.value = block.Copy() n.children = []*Node{} - n.formulae = AST.NewFormList() + n.formulas = Lib.NewList[AST.Form]() return n } /* Insert a lsit of formula into the right tree */ -func (n Node) InsertFormulaListToDataStructure(lf *AST.FormList) DataStructure { - for _, f := range lf.Slice() { +func (n Node) InsertFormulaListToDataStructure(lf Lib.List[AST.Form]) DataStructure { + for _, f := range lf.GetSlice() { switch nf := f.Copy().(type) { case AST.Pred: n.insert(ParseFormula(nf)) @@ -198,7 +198,7 @@ func (n Node) printAux(tab int) { } if n.isLeaf() { - for _, form := range n.formulae.Slice() { + for _, form := range n.formulas.GetSlice() { debug(Lib.MkLazy(func() string { return strings.Repeat("\t", tab+1) + form.ToString() })) } } @@ -214,7 +214,7 @@ func (n Node) printAux(tab int) { func (n *Node) insert(sequence Sequence) { if len(n.value) == 0 { n.value = sequence.GetInstructions() - n.formulae = AST.NewFormList(sequence.GetFormula()) + n.formulas = Lib.MkListV(sequence.GetFormula()) } else { n.followInstructions(sequence.GetInstructions(), sequence.GetFormula()) } @@ -236,8 +236,8 @@ func (n *Node) followInstructions(instructions []Instruction, form AST.Form) { // * It's the end of the CodeBlock, but not of the sequence. In this case, check if the following instruction matches with any child. if instr.IsEquivalent(current.value[oui]) { oui += 1 - if i == len(instructions)-1 && oui == len(current.value) && !current.formulae.Contains(form) { - current.formulae.Append(form) + if i == len(instructions)-1 && oui == len(current.value) && !Lib.ListMem(form, current.formulas) { + current.formulas.Append(form) } else if i < len(instructions)-1 && oui == len(current.value) { // If the instruction matches, then continue the algorithm with the child as the current node. @@ -252,7 +252,7 @@ func (n *Node) followInstructions(instructions []Instruction, form AST.Form) { } if !found { newNode := makeNode(instructions[i+1:]) - newNode.formulae = AST.NewFormList(form) + newNode.formulas = Lib.MkListV(form) current.children = append(current.children, newNode) break } @@ -263,13 +263,13 @@ func (n *Node) followInstructions(instructions []Instruction, form AST.Form) { // * The second one contains the remaining instructions of the sequence plus the formulae. child1 := makeNode(current.value[oui:]) child2 := makeNode(instructions[i:]) - child2.formulae = AST.NewFormList(form) + child2.formulas = Lib.MkListV(form) child1.children = current.children - child1.formulae = current.formulae + child1.formulas = current.formulas current.value = current.value[:oui] - current.formulae = AST.NewFormList() + current.formulas = Lib.NewList[AST.Form]() current.children = []*Node{child1, child2} break @@ -284,7 +284,7 @@ func (n *Node) followInstructions(instructions []Instruction, form AST.Form) { child1.children = current.children current.value = current.value[:oui] current.children = []*Node{child1} - current.formulae = AST.NewFormList(form.Copy()) + current.formulas = Lib.MkListV(form.Copy()) } } diff --git a/src/Unif/data_structure.go b/src/Unif/data_structure.go index 77aae7f3..c3d9f2a7 100644 --- a/src/Unif/data_structure.go +++ b/src/Unif/data_structure.go @@ -39,13 +39,14 @@ package Unif import ( "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Lib" ) type DataStructure interface { Print() IsEmpty() bool - MakeDataStruct(*AST.FormList, bool) DataStructure - InsertFormulaListToDataStructure(*AST.FormList) DataStructure - Unify(AST.Form) (bool, []MatchingSubstitutions) + MakeDataStruct(Lib.List[AST.Form], bool) DataStructure + InsertFormulaListToDataStructure(Lib.List[AST.Form]) DataStructure + Unify(AST.Form) (bool, []MixedSubstitutions) Copy() DataStructure } diff --git a/src/Unif/matching.go b/src/Unif/matching.go index ce544e2c..5989f2ec 100644 --- a/src/Unif/matching.go +++ b/src/Unif/matching.go @@ -54,10 +54,17 @@ func InitDebugger() { /*** Unify ***/ /* Helper function to avoid using MakeMachine() outside of this file. */ -func (n Node) Unify(formula AST.Form) (bool, []MatchingSubstitutions) { +func (n Node) Unify(formula AST.Form) (bool, []MixedSubstitutions) { machine := makeMachine() res := machine.unify(n, formula) - return !reflect.DeepEqual(machine.failure, res), res // return found, res + // As we have transformed type metas to terms, we get everything in a term substitution. + // But externally, we want to have a substitution of both (term) metas to terms and (type) metas to types. + // We use MixedSubstitution to properly manage things internally. + mixed_substs := []MixedSubstitutions{} + for _, subst := range res { + mixed_substs = append(mixed_substs, subst.toMixed()) + } + return !reflect.DeepEqual(machine.failure, res), mixed_substs } /* Tries to find the substitutions needed to unify the formulae with the one described by the sequence of instructions. */ @@ -66,23 +73,19 @@ func (m *Machine) unify(node Node, formula AST.Form) []MatchingSubstitutions { // The formula has to be a predicate. switch formula_type := formula.(type) { case AST.Pred: - terms := TypeAndTermsToTerms(formula_type.GetTypeVars(), formula_type.GetArgs()) - // Transform the predicate to a function to make the tool work properly m.terms = Lib.MkListV[AST.Term](AST.MakerFun( formula_type.GetID(), - terms, - []AST.TypeApp{}, - formula_type.GetType(), + Lib.NewList[AST.Ty](), + getFunctionalArguments(formula_type.GetTyArgs(), formula_type.GetArgs()), )) result = m.unifyAux(node) if !reflect.DeepEqual(m.failure, result) { filteredResult := []MatchingSubstitutions{} - // For each substitutions, remove the [0...MetaCount(formula_type.GetTypeVars())] ones to put it in another slice (the type slice) for _, matchingSubst := range result { - actualSubsts := matchingSubst.GetSubst()[AST.CountMeta(formula_type.GetTypeVars()):] - filteredResult = append(filteredResult, MakeMatchingSubstitutions(matchingSubst.GetForm(), actualSubsts)) + filteredResult = append(filteredResult, + MakeMatchingSubstitutions(matchingSubst.GetForm(), matchingSubst.GetSubst())) } result = filteredResult } @@ -173,7 +176,7 @@ func (m *Machine) unifyAux(node Node) []MatchingSubstitutions { matching := []MatchingSubstitutions{} if node.isLeaf() { - for _, f := range node.formulae.Slice() { + for _, f := range node.formulas.GetSlice() { if reflect.TypeOf(f) == reflect.TypeOf(AST.Pred{}) || reflect.TypeOf(f) == reflect.TypeOf(TermForm{}) { // Rebuild final substitution between meta and subst final_subst := computeSubstitutions(CopySubstPairList(m.subst), m.meta.Copy(), f.Copy()) @@ -257,7 +260,7 @@ func (m *Machine) end(instrTerm AST.Term) Status { func (m *Machine) right() Status { if m.isUnlocked() { m.q += 1 - if m.q > m.terms.Len() { + if m.q >= m.terms.Len() { return Status(ERROR) } m.topLevelCount += 1 diff --git a/src/Unif/matching_substitutions.go b/src/Unif/matching_substitutions.go index 7a727207..b268d21a 100644 --- a/src/Unif/matching_substitutions.go +++ b/src/Unif/matching_substitutions.go @@ -40,9 +40,197 @@ import ( "fmt" "github.com/GoelandProver/Goeland/AST" + "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" + "github.com/GoelandProver/Goeland/Typing" ) +type TySubstitution struct { + k AST.TyMeta + v AST.Ty +} + +func MkTySubstitution(k AST.TyMeta, v AST.Ty) TySubstitution { + return TySubstitution{k, v} +} + +func (s TySubstitution) ToString() string { + return fmt.Sprintf("%s |-> %s", s.k.ToString(), s.v.ToString()) +} + +func (s TySubstitution) Equals(oth any) bool { + if os, ok := oth.(TySubstitution); ok { + return os.k.Equals(s.k) && os.v.Equals(s.v) + } + return false +} + +func (s TySubstitution) Copy() TySubstitution { + return MkTySubstitution(s.k.Copy().(AST.TyMeta), s.v.Copy()) +} + +func (s TySubstitution) Get() (AST.TyMeta, AST.Ty) { + return s.k, s.v +} + +type MixedSubstitution struct { + s Lib.Either[TySubstitution, Substitution] +} + +func translateFromSubst(subst Substitution) MixedSubstitution { + if AST.IsTType(subst.k.GetTy()) { + return MixedSubstitution{Lib.MkLeft[TySubstitution, Substitution]( + MkTySubstitution( + AST.TyMetaFromMeta(subst.k), + AST.TermToTy(subst.v), + ), + )} + } else { + return MixedSubstitution{Lib.MkRight[TySubstitution, Substitution]( + MakeSubstitution( + subst.k, + translateTermRec(subst.v), + ))} + } +} + +func translateTermRec(term AST.Term) AST.Term { + switch trm := term.(type) { + case AST.Fun: + // Already converted: do nothing (either everything is converted or nothing) + if !trm.GetTyArgs().Empty() { + return term + } + + ty_args := Lib.NewList[AST.Ty]() + opt_ty := Typing.QueryGlobalEnv(trm.GetName()) + switch ty := opt_ty.(type) { + case Lib.Some[AST.Ty]: + switch t := ty.Val.(type) { + case AST.TyPi: + for i := 0; i < t.VarsLen(); i++ { + ty_args.Append(AST.TermToTy(trm.GetArgs().At(i))) + } + } + } + args := trm.GetArgs() + args = trm.GetArgs().Slice(ty_args.Len(), trm.GetArgs().Len()) + + return AST.MakerFun( + trm.GetID(), + ty_args, + Lib.ListMap(args, translateTermRec), + ) + } + return term +} + +func MkMixedFromSubst(subst Substitution) MixedSubstitution { + return MixedSubstitution{Lib.MkRight[TySubstitution, Substitution](subst)} +} + +func MkMixedFromTy(subst TySubstitution) MixedSubstitution { + return MixedSubstitution{Lib.MkLeft[TySubstitution, Substitution](subst)} +} + +func FromSubstitutions(substs Substitutions) Lib.List[MixedSubstitution] { + mixed_substs := Lib.MkList[MixedSubstitution](len(substs)) + for i, subst := range substs { + mixed_substs.Upd(i, MixedSubstitution{Lib.MkRight[TySubstitution, Substitution](subst)}) + } + return mixed_substs +} + +func ToSubstitutions(mixed_substs Lib.List[MixedSubstitution]) Substitutions { + substs := Substitutions{} + for _, subst := range mixed_substs.GetSlice() { + switch s := subst.Substitution().(type) { + case Lib.Some[Substitution]: + substs = append(substs, s.Val) + } + } + return substs +} + +func (m MixedSubstitution) ToString() string { + return Lib.EitherToString[TySubstitution, Substitution](m.s, "TySubst", "TrmSubst") +} + +func (m MixedSubstitution) Equals(oth any) bool { + if om, ok := oth.(MixedSubstitution); ok { + return Lib.EitherEquals[TySubstitution, Substitution](m.s, om.s) + } + return false +} + +func (m MixedSubstitution) Copy() MixedSubstitution { + return MixedSubstitution{Lib.EitherCpy[TySubstitution, Substitution](m.s)} +} + +func (m MixedSubstitution) Substitution() Lib.Option[Substitution] { + switch s := m.s.(type) { + case Lib.Right[TySubstitution, Substitution]: + return Lib.MkSome(s.Val) + } + return Lib.MkNone[Substitution]() +} + +func (m MixedSubstitution) TySubstitution() Lib.Option[TySubstitution] { + switch s := m.s.(type) { + case Lib.Left[TySubstitution, Substitution]: + return Lib.MkSome(s.Val) + } + return Lib.MkNone[TySubstitution]() +} + +func (m MixedSubstitution) GetMixed() Lib.Either[TySubstitution, Substitution] { + return m.s +} + +type MixedSubstitutions struct { + form AST.Form + substs []MixedSubstitution +} + +func (m MixedSubstitutions) GetForm() AST.Form { + return m.form.Copy() +} + +func (m MixedSubstitutions) GetSubsts() Lib.List[MixedSubstitution] { + return Lib.MkListV(m.substs...) +} + +func (m MixedSubstitutions) GetTrmSubsts() Substitutions { + out_substs := Substitutions{} + for _, subst := range m.substs { + switch s := subst.s.(type) { + case Lib.Right[TySubstitution, Substitution]: + out_substs = append(out_substs, s.Val) + } + } + return out_substs +} + +func (m MixedSubstitutions) GetTySubsts() Lib.List[TySubstitution] { + out_substs := Lib.NewList[TySubstitution]() + for _, subst := range m.substs { + switch s := subst.s.(type) { + case Lib.Left[TySubstitution, Substitution]: + out_substs.Append(s.Val) + } + } + return out_substs +} + +func (m MixedSubstitutions) ToString() string { + substs_list := Lib.MkListV(m.substs...) + return m.GetForm().ToString() + " {" + Lib.ListToString(substs_list, ", ", "") + "}" +} + +func (m MixedSubstitutions) IsSubstsEmpty() bool { + return len(m.substs) == 0 +} + type MatchingSubstitutions struct { form AST.Form subst Substitutions @@ -64,6 +252,68 @@ func (m MatchingSubstitutions) Print() { m.GetSubst().Print() } +func (m MatchingSubstitutions) toMixed() MixedSubstitutions { + substs := []MixedSubstitution{} + for _, subst := range m.subst { + substs = append(substs, translateFromSubst(subst)) + } + return MixedSubstitutions{m.form, substs} +} + func MakeMatchingSubstitutions(form AST.Form, subst Substitutions) MatchingSubstitutions { return MatchingSubstitutions{form.Copy(), subst.Copy()} } + +func (m MixedSubstitutions) MatchingSubstitutions() MatchingSubstitutions { + return MakeMatchingSubstitutions(m.form, m.GetTrmSubsts()) +} + +func translateToSubst(subst MixedSubstitution) Substitution { + switch s := subst.s.(type) { + case Lib.Left[TySubstitution, Substitution]: + return MakeSubstitution( + s.Val.k.ToTermMeta(), + AST.TyToTerm(s.Val.v), + ) + case Lib.Right[TySubstitution, Substitution]: + return s.Val + } + + Glob.Anomaly("unification internals", "Found neither a type substitution nor a substitution") + return MakeSubstitution(AST.MakeEmptyMeta(), nil) +} + +func MergeMixedSubstitutions(substs1, substs2 Lib.List[MixedSubstitution]) (Lib.List[MixedSubstitution], bool) { + translated_substs1 := Lib.ListMap(substs1, translateToSubst).GetSlice() + translated_substs2 := Lib.ListMap(substs2, translateToSubst).GetSlice() + + merged_tmp, _ := MergeSubstitutions(translated_substs1, translated_substs2) + + success := !merged_tmp.Equals(Failure()) + + merged := Lib.MkList[MixedSubstitution](len(merged_tmp)) + for i, subst := range merged_tmp { + merged.Upd(i, translateFromSubst(subst)) + } + return merged, success +} + +func SubstsToString(substs Lib.List[Lib.List[MixedSubstitution]]) string { + return substs.ToString( + func(m Lib.List[MixedSubstitution]) string { + return Lib.ListToString(m, ", ", "[]") + }, " ; ", "[]") +} + +func UnifSucceeded(unifs Lib.List[MixedSubstitution]) bool { + if unifs.Empty() { + return true + } + + succeeded := true + switch subst := unifs.At(0).Substitution().(type) { + case Lib.Some[Substitution]: + succeeded = !subst.Val.Equals(Failure()[0]) + } + return succeeded +} diff --git a/src/Unif/parsing.go b/src/Unif/parsing.go index 63393721..c8a80fc6 100644 --- a/src/Unif/parsing.go +++ b/src/Unif/parsing.go @@ -34,42 +34,30 @@ package Unif import ( "github.com/GoelandProver/Goeland/AST" - "github.com/GoelandProver/Goeland/Glob" "github.com/GoelandProver/Goeland/Lib" ) type TermForm struct { - *AST.MappedString index int t AST.Term } -func (t TermForm) ToMappedStringSurround(mapping AST.MapString, displayTypes bool) string { - return "%s" -} - -func (t TermForm) ToMappedStringChild(mapping AST.MapString, displayTypes bool) (separator, emptyValue string) { - return "", t.t.ToMappedString(mapping, displayTypes) -} - -func (t TermForm) GetChildrenForMappedString() []AST.MappableString { - return t.GetChildFormulas().ToMappableStringSlice() -} - -func (t TermForm) GetTerm() AST.Term { return t.t.Copy() } -func (t TermForm) Copy() AST.Form { return makeTermForm(t.GetIndex(), t.GetTerm()) } -func (t TermForm) GetType() AST.TypeScheme { return AST.DefaultFunType(0) } -func (t TermForm) RenameVariables() AST.Form { return t } -func (t TermForm) ReplaceTypeByMeta([]AST.TypeVar, int) AST.Form { return t } +func (t TermForm) ToString() string { return t.ToString() } +func (t TermForm) GetTerm() AST.Term { return t.t.Copy() } +func (t TermForm) Copy() AST.Form { return makeTermForm(t.GetIndex(), t.GetTerm()) } +func (t TermForm) RenameVariables() AST.Form { return t } func (t TermForm) ReplaceTermByTerm(AST.Term, AST.Term) (AST.Form, bool) { return t, false } +func (t TermForm) SubstTy(AST.TyGenVar, AST.Ty) AST.Form { + return t +} func (t TermForm) GetIndex() int { return t.index } func (t TermForm) SubstituteVarByMeta(AST.Var, AST.Meta) AST.Form { return t } func (t TermForm) GetInternalMetas() Lib.List[AST.Meta] { return Lib.NewList[AST.Meta]() } func (t TermForm) SetInternalMetas(Lib.List[AST.Meta]) AST.Form { return t } -func (t TermForm) GetSubFormulasRecur() *AST.FormList { return AST.NewFormList() } -func (t TermForm) GetChildFormulas() *AST.FormList { return AST.NewFormList() } +func (t TermForm) GetSubFormulasRecur() Lib.List[AST.Form] { return Lib.NewList[AST.Form]() } +func (t TermForm) GetChildFormulas() Lib.List[AST.Form] { return Lib.NewList[AST.Form]() } func (t TermForm) Equals(t2 any) bool { switch nt := t2.(type) { @@ -109,14 +97,16 @@ func (t TermForm) ReplaceMetaByTerm(meta AST.Meta, term AST.Term) AST.Form { } func MakerTermForm(t AST.Term) TermForm { + switch trm := t.(type) { + case AST.Fun: + args := getFunctionalArguments(trm.GetTyArgs(), trm.GetArgs()) + t = AST.MakerFun(trm.GetID(), Lib.NewList[AST.Ty](), args) + } return makeTermForm(AST.MakerIndexFormula(), t.Copy()) } func makeTermForm(i int, t AST.Term) TermForm { - fms := &AST.MappedString{} - tf := TermForm{fms, i, t.Copy()} - fms.MappableString = &tf - return tf + return TermForm{i, t.Copy()} } /* Parses a formulae to a sequence of instructions. */ @@ -125,20 +115,14 @@ func ParseFormula(formula AST.Form) Sequence { // The formula has to be a predicate switch formula_type := formula.(type) { case AST.Pred: - pred := AST.MakePred(formula_type.GetIndex(), formula_type.GetID(), TypeAndTermsToTerms(formula_type.GetTypeVars(), formula_type.GetArgs()), []AST.TypeApp{}, formula_type.GetType()) - instructions := Sequence{formula: pred} + instructions := Sequence{formula: formula_type} instructions.add(Begin{}) - parsePred(pred, &instructions) + parsePred(formula_type, &instructions) instructions.add(End{}) return instructions case TermForm: - if Glob.Is[AST.Fun](formula_type.GetTerm()) { - fun := Glob.To[AST.Fun](formula_type.GetTerm()) - formula = makeTermForm(formula.GetIndex(), AST.MakerFun(fun.GetID(), TypeAndTermsToTerms(fun.GetTypeVars(), fun.GetArgs()), []AST.TypeApp{}, fun.GetTypeHint())) - } - instructions := Sequence{formula: formula} varCount := 0 postCount := 0 @@ -159,26 +143,40 @@ func ParseFormula(formula AST.Form) Sequence { } } -func TypeAndTermsToTerms( - types []AST.TypeApp, - terms Lib.List[AST.Term], -) Lib.List[AST.Term] { - tms := Lib.NewList[AST.Term]() - tms.Append(AST.TypeAppArrToTerm(types).GetSlice()...) - tms.Append(terms.GetSlice()...) +/* Parses a predicate to machine instructions */ +func getFunctionalArguments(ty_args Lib.List[AST.Ty], trm_args Lib.List[AST.Term]) Lib.List[AST.Term] { + args := Lib.ListMap(ty_args, AST.TyToTerm) + + for _, arg := range trm_args.GetSlice() { + switch term := arg.(type) { + case AST.Meta: + args.Append(arg) + case AST.Fun: + args.Append(AST.MakerFun( + term.GetID(), + Lib.NewList[AST.Ty](), + getFunctionalArguments(term.GetTyArgs(), term.GetArgs()), + )) + } + } - return tms + return args } -/* Parses a predicate to machine instructions */ func parsePred(p AST.Pred, instructions *Sequence) { instructions.add(makeCheck(p.GetID())) - if p.GetArgs().Len() > 0 { + if !p.GetTyArgs().Empty() || !p.GetArgs().Empty() { instructions.add(Begin{}) instructions.add(Down{}) varCount := 0 postCount := 0 - parseTerms(p.GetArgs(), instructions, Lib.NewList[AST.Meta](), &varCount, &postCount) + parseTerms( + getFunctionalArguments(p.GetTyArgs(), p.GetArgs()), + instructions, + Lib.NewList[AST.Meta](), + &varCount, + &postCount, + ) instructions.add(End{}) } } @@ -227,7 +225,8 @@ func parseTerms( *postCount++ } instructions.add(Down{}) - subst = parseTerms(t.GetArgs(), instructions, subst, varCount, postCount) + subTerms := getFunctionalArguments(t.GetTyArgs(), t.GetArgs()) + subst = parseTerms(subTerms, instructions, subst, varCount, postCount) if rightDefined(terms, i) { *postCount-- instructions.add(Pop{*postCount}) diff --git a/src/Unif/substitutions_tree.go b/src/Unif/substitutions_tree.go index ab123186..5a9be9e7 100644 --- a/src/Unif/substitutions_tree.go +++ b/src/Unif/substitutions_tree.go @@ -63,7 +63,10 @@ func computeSubstitutions(subs []SubstPair, metasToSubs Substitutions, form AST. // Retrieve all the meta of from the tree formula switch typedForm := form.(type) { case AST.Pred: - metasFromTreeForm.Append(typedForm.GetMetaList().GetSlice()...) + trms := getFunctionalArguments(typedForm.GetTyArgs(), typedForm.GetArgs()) + for _, trm := range trms.GetSlice() { + metasFromTreeForm.Append(trm.GetMetaList().GetSlice()...) + } case TermForm: metasFromTreeForm.Append(typedForm.GetTerm().GetMetaList().GetSlice()...) default: diff --git a/src/Unif/substitutions_type.go b/src/Unif/substitutions_type.go index 32acc4bc..7c43b118 100644 --- a/src/Unif/substitutions_type.go +++ b/src/Unif/substitutions_type.go @@ -213,7 +213,7 @@ func MakeEmptySubstitutionList() []Substitutions { /* Returns a « failed » substitution. */ func Failure() Substitutions { - fail := AST.MakeMeta(-1, -1, "FAILURE", -1, AST.MkTypeHint("i")) + fail := AST.MakeEmptyMeta() return Substitutions{Substitution{fail, fail}} } @@ -313,9 +313,8 @@ func eliminateInside(key AST.Meta, value AST.Term, s Substitutions, has_changed_ case AST.Fun: new_value := AST.MakerFun( value_2_type.GetP(), + value_2_type.GetTyArgs(), eliminateList(key, value, value_2_type.GetArgs(), &has_changed), - value_2_type.GetTypeVars(), - value_2_type.GetTypeHint(), ) if OccurCheckValid(key_2, new_value) { s_tmp.Set(key_2, new_value) @@ -360,9 +359,8 @@ func eliminateList( case AST.Fun: // If its a function, reccursive call for the arguments tempList.Append(AST.MakerFun( lt.GetP(), + lt.GetTyArgs(), eliminateList(key, value, lt.GetArgs(), &hasChanged), - lt.GetTypeVars(), - lt.GetTypeHint(), )) default: tempList.Append(elementList) diff --git a/src/main.go b/src/main.go index 07107474..7240cbad 100644 --- a/src/main.go +++ b/src/main.go @@ -55,6 +55,8 @@ import ( "github.com/GoelandProver/Goeland/Mods/assisted" "github.com/GoelandProver/Goeland/Mods/dmt" equality "github.com/GoelandProver/Goeland/Mods/equality/bse" + "github.com/GoelandProver/Goeland/Mods/gs3" + "github.com/GoelandProver/Goeland/Mods/lambdapi" "github.com/GoelandProver/Goeland/Parser" "github.com/GoelandProver/Goeland/Search" "github.com/GoelandProver/Goeland/Search/incremental" @@ -135,12 +137,12 @@ func presearchLoader() (AST.Form, int) { ) statements, bound, containsEquality := Parser.ParseTPTPFile(problem) - actualStatements := Engine.ToInternalSyntax(statements) + actual_statements, is_typed_problem := Engine.ToInternalSyntax(statements) debug( Lib.MkLazy(func() string { return fmt.Sprintf( - "Statement : %s", Core.StatementListToString(actualStatements)) + "Statement : %s", Core.StatementListToString(actual_statements)) }), ) @@ -148,7 +150,7 @@ func presearchLoader() (AST.Form, int) { bound = Glob.GetLimit() } - form, bound, contEq := StatementListToFormula(actualStatements, bound, path.Dir(problem)) + form, bound, contEq, is_typed_include := StatementListToFormula(actual_statements, bound, path.Dir(problem)) containsEquality = containsEquality || contEq if !containsEquality { @@ -160,7 +162,9 @@ func presearchLoader() (AST.Form, int) { Glob.Fatal(main_label, "Problem not found") } - form = checkForTypedProof(form) + if is_typed_problem || is_typed_include { + checkForTypedProof(form) + } return form, bound } @@ -187,9 +191,11 @@ func initEverything() { Glob.InitLogs() // Always init debuggers before options initDebuggers() + // Always init AST before options (for printers) + AST.Init() initOpts() runtime.GOMAXPROCS(Glob.GetCoreLimit()) - AST.Init() + Typing.Init() } func initDebuggers() { @@ -203,10 +209,19 @@ func initDebuggers() { Search.InitDebugger() Typing.InitDebugger() Unif.InitDebugger() + Engine.InitDebugger() + gs3.InitDebugger() + lambdapi.InitDebugger() } -func StatementListToFormula(statements []Core.Statement, old_bound int, problemDir string) (form AST.Form, bound int, containsEquality bool) { - and_list := AST.NewFormList() +// FIXME: eventually, we would want to add an "interpretation" layer between elab and internal representation that does this +func StatementListToFormula( + statements []Core.Statement, + old_bound int, + problemDir string, +) (form AST.Form, bound int, containsEquality bool, is_typed_problem bool) { + and_list := Lib.NewList[AST.Form]() + is_typed_problem = false var not_form AST.Form bound = old_bound @@ -220,18 +235,19 @@ func StatementListToFormula(statements []Core.Statement, old_bound int, problemD if err != nil { Glob.PrintError(main_label, err.Error()) - return nil, -1, false + return nil, -1, false, false } new_lstm, bound_tmp, contEq := Parser.ParseTPTPFile(realname) - actual_new_lstm := Engine.ToInternalSyntax(new_lstm) + actual_new_lstm, is_typed := Engine.ToInternalSyntax(new_lstm) containsEquality = containsEquality || contEq - new_form_list, new_bound, contEq := StatementListToFormula( + new_form_list, new_bound, contEq, is_typed := StatementListToFormula( actual_new_lstm, bound_tmp, path.Join(problemDir, path.Dir(file_name)), ) containsEquality = containsEquality || contEq + is_typed_problem = is_typed_problem || is_typed if new_form_list != nil { bound = new_bound @@ -265,20 +281,20 @@ func StatementListToFormula(statements []Core.Statement, old_bound int, problemD } switch { - case and_list.IsEmpty() && not_form == nil: - return nil, bound, containsEquality - case and_list.IsEmpty(): - return AST.MakerNot(not_form), bound, containsEquality + case and_list.Empty() && not_form == nil: + return nil, bound, containsEquality, is_typed_problem + case and_list.Empty(): + return AST.MakerNot(not_form), bound, containsEquality, is_typed_problem case not_form == nil: - return AST.MakerAnd(and_list), bound, containsEquality + return AST.MakerAnd(and_list), bound, containsEquality, is_typed_problem default: - flattened := and_list.Flatten() + flattened := AST.LsFlatten(and_list) flattened.Append(AST.MakerNot(not_form)) - return AST.MakerAnd(flattened), bound, containsEquality + return AST.MakerAnd(flattened), bound, containsEquality, is_typed_problem } } -func doAxiomStatement(andList *AST.FormList, f AST.Form) *AST.FormList { +func doAxiomStatement(andList Lib.List[AST.Form], f AST.Form) Lib.List[AST.Form] { newForm := f.RenameVariables() // FIXME: dmt should be a plugin and therefore not checked here. @@ -305,33 +321,13 @@ func doConjectureStatement(f AST.Form) AST.Form { } func doTypeStatement(atomTyping Core.TFFAtomTyping) { - typeScheme := atomTyping.Ts + typeScheme := atomTyping.Ty if typeScheme == nil { Glob.PrintWarn("main", fmt.Sprintf("The constant %s has no type!", atomTyping.Literal.ToString())) - return } - if typeScheme.Size() == 1 { - isNewType := typeScheme.ToString() == "$tType" - if isNewType { - AST.MkTypeHint(atomTyping.Literal.GetName()) - } else { - isConstant := !Glob.Is[AST.QuantifiedType](typeScheme) - if isConstant { - AST.SaveConstant(atomTyping.Literal.GetName(), typeScheme.GetPrimitives()[0]) - } else { - AST.SavePolymorphScheme(atomTyping.Literal.GetName(), typeScheme) - } - } - } else { - switch typeScheme.(type) { - case AST.TypeArrow: - AST.SaveTypeScheme(atomTyping.Literal.GetName(), AST.GetInputType(typeScheme)[0], AST.GetOutType(typeScheme)) - case AST.QuantifiedType: - AST.SavePolymorphScheme(atomTyping.Literal.GetName(), typeScheme) - } - } + Typing.AddToGlobalEnv(atomTyping.Literal.GetName(), atomTyping.Ty) } func getFile(filename string, dir string) (string, error) { @@ -362,18 +358,9 @@ func getFile(filename string, dir string) (string, error) { return "", fmt.Errorf("file %s not found", filename) } -func checkForTypedProof(form AST.Form) AST.Form { - isTypedProof := !AST.EmptyGlobalContext() && !Glob.NoTypeCheck() - - if isTypedProof { - err := Typing.WellFormedVerification(form.Copy(), Glob.GetTypeProof()) - - if err != nil { - Glob.Fatal("typechecker", fmt.Sprintf("Typing error: %v", err)) - } else { - Glob.PrintInfo("typechecker", fmt.Sprintf("The problem %s is well typed.", Glob.GetProblemName())) - } +func checkForTypedProof(form AST.Form) { + if !Glob.NoTypeCheck() && !Typing.TypeCheck(form) { + Glob.Fatal(main_label, fmt.Sprintf("Formula %s is not well typed", form.ToString())) } - - return form + Glob.PrintInfo(main_label, "Problem is well typed") } diff --git a/src/options.go b/src/options.go index 0fa84bf0..48cdf630 100644 --- a/src/options.go +++ b/src/options.go @@ -206,7 +206,7 @@ func buildOptions() { "pretty", false, "Should only be used with the -proof parameter. Enables UTF-8 characters in prints for a pretty proof", - func(bool) { Glob.DisplayPretty() }, + func(bool) { AST.SetPrinter(AST.PrettyPrinter) }, func(bool) {}) (&option[bool]{}).init( "dmt", @@ -390,16 +390,16 @@ func buildOptions() { }, func(bool) {}) (&option[bool]{}).init( - "no_id", + "print-id", false, - "Disables the id in the ToString", - func(bool) { AST.ToStringId = AST.NoIdToString }, + "Enables id printing", + func(bool) { AST.ComposePrinter(AST.PrintIDAction) }, func(bool) {}) (&option[bool]{}).init( "quoted_pred", false, "Print predicates between quotes if they start by a capital letter (TPTP compliance)", - func(bool) { AST.ToStringId = AST.QuotedToString }, + func(bool) { AST.ComposePrinter(AST.QuoteID) }, func(bool) {}) (&option[bool]{}).init( "quiet",